可见可观测是服务治理反馈机制的第一步,只有获取到足够多有价值的数据,才能对服务的运行状态进行分析和控制。
服务元数据平台负责维护服务相关的元数据信息,主要包括服务层面、接口层面、拓扑层面这几个维度的元数据信息,通过服务元数据平台,可以对系统提供全方位的可见性。
服务层面,服务元数据平台汇聚了当前所有的服务列表,默认按照服务功能进行分类,业务需要某种功能的服务时就可以直接到服务商城浏览和查询,做到服务信息的透明化,减少重复建设。为了增强服务查询的灵活性,可以支持多种服务查询方式,比如按照服务所属部门查询、按照服务属性查询等,服务基本信息平台化等。服务基本信息如下。
1) 服务描述 :简要描述服务提供的基本能力,服务的适用场景等,供潜在服务使用者参考,必要时可以加上服务的详细描述信息wiki,以及服务对应的邮件组和沟通群。
2) 服务所有权 :服务当前所属部门、服务当前的owner等。
3) 服务对外接口 :服务接口定义,使用说明和注意事项等。
4) 服务SLA :服务对外的SLA承诺。
5) 服务的上下游拓扑 :服务商城中维护了每个服务的上下游依赖,基于上下游依赖,不仅可以查询上下游服务的使用方式和使用情况,同时也可以进行服务重大变更时的上下游服务通知。
6) 服务变更 :服务商城中维护服务每个重要变更的变更日志,重要变更时会通过相应机制知会上下游依赖,上下游会评估是否需要适配升级等,这样服务使用者可以从变更历史中了解到服务的整个发展脉络。
7) 服务接入和资源配额管理 :服务如何接入,资源配额如何申请等。
8) 服务线上部署和线下测试环境信息 :描述了服务线上和线下的部署信息,使用者直接基于平台给定的环境使用。
服务元数据平台的作用是将服务基本信息平台化,同时可以将服务接入、服务客服等日常工作从线下转移到线上,减少线下的人力成本开销。因此服务元数据平台的评价标准是微服务接入和运营时线下沟通的比重。
变更是引发系统故障的主要因素,通过对各个维度的变更进行系统的梳理和记录,不仅方便出现故障时的追溯和定位,后续还可以基于完善的变更事件库,对这些变更的原因、质量以及影响进行全面的审计和分析,从中找到规律性的东西,建立相应的改进反馈闭环。
服务变更是变更的最重要来源,常见的服务变更方式有应用变更、配置变更、数据变更以及预案变更等。
对于微服务架构来说,除了关注当前服务的变更之外,还需要关注上下游依赖服务的变更,以及部署层面关联服务的变更,比如和当前服务混部在同一台物理机上的其他服务变更。
除了服务变更,还需要对服务周边的各个环境变更进行记录,比如网络变更、机器变更、机房变更、交换机变更,这些变更都可能对服务的正常运行产生影响。
微服务架构下,各个微服务采用分布式部署,并且通过网络进行分布式通信,随着微服务个数和集群规模的扩大,系统中会产生各种形式的故障,并且很多故障是无法事先预测的,因此需要有完善的平台和工具体系,能够对微服务的运行状态进行全方位多维度的监控,使得我们可以随时掌握微服务当前的运行状态,并且针对运行状态不正常的场景进行及时处理。
可观测性就是用于上述微服务状态监控的工具集合,具体分为Logging(日志系统)、Metrics(度量系统)和Tracing(分布式跟踪系统)3个层次,三者的关系图如图2-2所示。
日志用于对系统中离散的事件进行记录,比如服务的调试信息和错误信息,日志是系统监控的基石,也是服务状态监控和问题诊断的第一个抓手,通过日志可以大体判断系统的运行状态是否正常。
日志是最常见、最通用的监控手段,但服务的日志监控和告警一般都需要人工添加,不仅效率低,也很容易遗漏。同时不同服务的日志格式和日志信息可能都会有差异,不太方便进行标准化,不仅日志收集、处理和展示比较麻烦,有太多个性化的需求,而且每个服务的日志都不统一,基于日志的全系统问题定位也非常麻烦。
为了提高日志和监控的标准化,引入了Metric的概念,Metric就是将日志中可以聚合的部分通过标准化的协议进行处理,Metric定义一套完善的日志收集、传输和处理标准,通过Metric可以实现日志和监控的标准化,同时基于Metric的日志聚合特性,聚合后的日志会小很多,减少日志系统的成本开销。
Tracing用于记录请求级别的信息,它会跟踪请求整个链路的执行过程和各阶段耗时信息,基于Tracing,可以定位请求性能问题和跨服务交互相关的问题。
Logging、Metric和Tracing这3个系统关注的侧重点有所不同。Logging系统对服务的运行状态和事件进行记录,比如调试日志、错误日志等,日志记录一般会比较全(有时出于性能考虑可能需要在不同场景下打开相应的日志开关),这些日志会作为问题追查和定位的依据。Metric系统侧重事件聚合,相比日志来说,Metric关注的对象相对小一些,比如服务QPS、成功率、耗时等,聚焦核心指标,基于Metric可以方便实现服务核心指标的监控告警自动化。Tracing关注请求级别的处理。使用过程中一般先关注日志监控是否有问题,如果有问题通过Metric查看具体的服务和指标异常,最后通过Tracing进行全链路排查。
Metric系统和Tracing系统在实际中是交叉使用的,可类比公安破案的过程。
1)公安会在犯罪高发地段部署监控,以便及时发现各类蛛丝马迹,比如一段时间内,每个过客的神色、停留时长,类似Metric系统,以在大面上发现隐患或嫌疑。
2)通过Metric系统锁定高嫌疑犯后,会进一步分析嫌疑犯的衣食住行轨迹,得到证据链,从而给嫌犯定罪。衣食住行轨迹系统,就类似Tracing系统。这里通过Tracing获得证据链,确认之前的异常指标确实导致了问题。
3)最终从客观角度分析罪犯的作案根因时,可能又会将一段时间内该罪犯的行为指标进行时序分析,最终分析出该罪犯是因强制拆迁投诉无门而报复社会。这里通过复盘Metric,在微观面(个人层次)找到犯罪根因。
综上所述,一般通过无处不在的Metric监控,发现大面上的异常或隐患,如机器cpu idle过低、服务崩溃退出等;再通过Tracing系统,查看异常机器或实例上的轨迹,确认异常由哪个环节引入,造成了多大损失(例如个别机器CPU idle低处理慢,因为有上游重试,未必会造成损失);如果问题由业务逻辑导致,此时基本能找到根因;否则再通过Metric系统,确定运行环境类根因,如查看异常机器或实例上的QPS、CPU idle率、进程CPU使用率的秒级曲线,最终判定cpu ilde低是由QPS增加导致,还是其他进程CPU使用率增加导致。
一般来说,对于大故障,直接关联分析各种指标就能定位出问题;对于零星故障,业务逻辑故障,上下游耦合类故障(如调度),要通过跟踪才能分析清楚。
图2-2 可观测机制关系图
1.标准化监控Metric
监控标准化是在业务中埋点主动上报标准业务指标来满足业务监控需求的解决方案。期望在业务完成标准上报之后,自动给业务提供调用关系拓扑、自动错误率监控、自动服务可用性计算、服务性能评估等高级功能。业务服务一般习惯于使用日志监控的方式,监控系统对日志的监控也容易实现,但日志监控有如下几个缺点。
日志监控采集只能适用于简单规则,比如流量采集、接口平均耗时等,在耗时上采用平均耗时,在分析业务性能时缺少精细粒度的分位耗时信息,比较难科学反应模块性能。
日志监控分析在业务流量大的情况下,在线消耗性能比较多。
日志监控采用配置分析的模式,让监控系统和日志格式有依赖,如果修改代码的时候不小心调整了日志格式,忘记调整对应监控正则,会导致日志监控出错。
相比之下,标准化监控,主动上报监控指标,可以自动绘出调用链,为服务可用性提供衡量指标,支持复杂的统计功能,可以定制业务相关的复杂策略。
为了实现监控标准化,针对监控项的收集和上报,需要制定一个规范,如果各个业务或者一个业务的各个接口都按照上述的规范,那么可以在监控自动化上做到更高程度,避免人工配置。
举个例子:如果一个业务的各个接口都有错误率,且各个接口的错误率不能超过30%,那么只需要配置错误率≥30%就报警,则新增一个接口自动添加报警,可以实现报警自动化。监控项规范可以规定,所有上报的监控项均需要关注QPS、耗时和错误率这几个服务基础监控指标。
标准化项采集实现起来也比较简单,可以借鉴开源系统statsd的设计思想,在业务代码中引入监控标准化SDK。SDK负责实现监控项埋点和统计功能,以及服务间RPC调用质量等业务指标,SDK通过UDP协议上报业务监控指标项到本机的Agent,本机Agent以一定的周期(如10s)为周期聚合业务指标,并将聚合结果发送到监控平台。
2.分布式跟踪Tracing
大型互联网公司的微服务架构下,一个业务可能会有上百个微服务组成,一次请求由几十次服务调用共同完成。这种架构下就会出现很多跨服务的问题,比如请求处理为什么突然变慢,问题具体出在那个环节;业务故障的排查,是哪个流程中出错等,通过分布式跟踪系统,可以建立一个以请求为中心的全局视图,查看请求处理过程中各个阶段的具体状态和处理情况。
2010年,Google发表了一篇名为《Dapper,a Large-Scale Distributed Systems Tracing Infrastructure》的论文,介绍了Google生产环境中大规模使用的分布式跟踪系统Dapper的设计原理和使用经验,Dapper掀开了分布式跟踪系统的序幕。之后Twitter根据这篇论文开发了自己的分布式跟踪系统Zipkin,并将其开源。现在不少国内外的大型互联网公司也都有自己的分布式跟踪系统,比如Uber的Jaeger、阿里的鹰眼、京东的Hydra、微博的Watchman等,这些分布式跟踪系统的原理基本都差不多,一般分为数据采集、数据传输、数据处理和数据展示4个方面,下面以Dapper为例,讲述分布式跟踪系统的大体实现。
首先看下分布式跟踪相关的几个重要概念,TraceID用于对请求进行唯一标识,一般是请求进入链路处理入口时生成(比如在接入层生成),此后一直在请求处理的整个链路中一直携带和传递,不再修改。TraceID是分布式跟踪系统中最重要的概念,通过TraceID串联请求的各个阶段,同时也通过TraceID查询请求的整个处理链。
Span ID用于标识请求在一个模块内的处理过程,理论上讲,Span ID只需要做到同一个TraceID下唯一即可,不需要全局唯一。为了通过服务调用关系实现请求调用链信息的组织,调用下游服务时,需要将自身的Span ID和TraceID传递给下游服务,下游服务会将上游服务传递过来的Span ID作为自己的父Span ID,并通过一定的方式生成自身的Span ID,然后使用TraceID、父Span ID和Span ID生成标准化的Trace日志,分布式跟踪系统收集各个服务的Trace日志,然后通过TraceID完成一个请求对应Trace日志的收集,通过父Span ID和Span ID完成请求跟踪树的建立。
Annotation用于给跟踪信息添加相应的注释,这个注释信息是带时间戳的,Annotation可以添加任意请求相关的信息,通过Annotation,方便进行一些业务相关的问题定位。
对于分布式跟踪系统来说,TraceID和Span ID的正确生成是一个非常重要的前提,不同分布式跟踪系统的ID生成规则不一样,对于TraceID来说,必要条件是全局唯一,同时为了方便根据TraceID进行问题定位和追查,TraceID生成时可以加入一些请求相关的基本信息。
对于Span ID的生成,必要的约束条件是保证同一个请求下的不同节点对应的Span ID唯一即可。不同的分布式跟踪系统,生成Span ID的方式也不尽相同,比如阿里的鹰眼系统巧妙用Span ID来体现调用层次关系(例如0,0.1,0.2,0.1.1等),对于请求的根节点来说,使用一个特殊的标识来标识当前节点是根节点,没有上游信息。
对于分布式跟踪来说,设计和使用过程中,有一些需要遵守的要点。
低侵入接入不仅是分布式跟踪,也是所有服务治理相关特性的共同需求。服务治理特性接入最好能做到对业务透明,这样接入的过程中不会有特别大的阻力,如果业务需要花费比较大的改造成本才能完成接入,业务接入的意愿就不会那么强烈。
为了实现透明低侵入接入,一般可以将分布式跟踪特性下沉到服务框架或者Service Mesh层面,尤其是Service Mesh可以真正做到让分布式跟踪特性的修改对业务服务完全透明,业务服务零改动。
为了减少对业务服务正常运行的影响,分布式跟踪需要做到尽可能轻量,尤其是一些性能特别敏感的业务,需要随时调整Trace日志采集频率,甚至需要Trace日志采集开关。
分布式跟踪作为基础服务治理组件,如果没有足够的稳定性保障,会给业务服务带来非常严重的后果,因此分布式跟踪系统设计和实现过程中的各个环节都要考虑稳定性因素,尽可能简化设置。对于Trace日志输出来说,不要有太复杂的处理逻辑,同时日志收集代理尽可能轻量部署,减少不必要的依赖。
当前国内外主流互联网公司基本上都有自己的分布式跟踪系统,但这些系统实现各异,并且相互不兼容,无法实现跨业务、跨公司的全链路跟踪,制约了全链路跟踪的进一步发展,为了解决不同分布式跟踪系统API不兼容的问题,诞生了OpenTracing规范,OpenTracing是一个轻量级的标准化层,希望通过OpenTracing实现分布式跟踪的兼容互通和标准化。当前OpenTracing已进入CNCF,成为云原生基础设施的一部分,OpenTracing通过提供平台无关、语言无关的API,使得开发人员能够方便地替换追踪系统,目标是为全球的分布式追踪提供统一的概念和分布式跟踪标准。
OpenTracing数据模型中,重点定义了两个相关的概念Span Tag和Log Field,其中Span Tag定义一系列作用于整个Span过程的Tag;每个Span的log操作,都具有一个特定的时间戳(这个时间戳必须在Span的开始时间和结束时间之间),以及一个或多个field,Log Field定义了一系列标准化的Log Field字段,通过Span Tag和Log Field实现了分布式跟踪输出的标准化。
OpenTracing规范还在不断完善过程中,当前Jaeger和Zipkin均实现了对OpenTracing的支持。