1.现状和问题
在微服务架构下,单独部署运行的并且无状态微服务都是彼此通过调用来进行交互。这种架构下,应用架构由集中式向分布式演进后,整个调用关系变得复杂,如图1所示。
一个完整业务的调用过程要在多个微服务进行处理和传递,各个微服务之间相当独立,可能由不同的团队来开发、不同的语言来实现,这样可能会出现如下问题:如果微服务出现调用错误和异常,如何准确定位微服务出错的位置?如何快速定位错误问题?如何跟踪微服务处理顺序和结果?如何准确知道整体系统性能及运行情况?
对于这个问题,业内已经有了一些实践和成熟的解决方案。
图1 复杂的调用链图
2.理论基础及核心思路
Google Dapper是Google公司为广泛使用分布式集群,应对自身大规模的复杂集群环境而研发的一套分布式跟踪系统。其相关论文《Dapper,a Large-Scale Distributed Systems TracingInfrastructure》也成为当前分布式跟踪系统的理论基础。分布式跟踪的调用如图2所示。
图2 分布式跟踪的调用图
分布式跟踪原理就是对服务器上每一次发送和接收的动作进行收集和记录跟踪标识符(Message Identifiers)和时间戳(Timestamped Events)等相关信息。
基于这个模型,Google在此论文中提出了几个重要的概念:
①基于标注(Annotation-based),又叫植入点或埋点。在应用程序或中间件中明确定义一个全局的标注(Annotation),这是一个特殊的ID,通过这个ID连接每一条记录和发起者的请求,Dapper能够以对应用开发者近乎零侵入的成本对分布式控制路径进行跟踪。当一个线程在处理跟踪控制路径的过程中,Dapper把这次跟踪的上下文在ThreadLocal中进行存储。追踪上下文是一个小而且容易复制的容器,其中承载了Scan的属性,比如跟踪ID和Span ID。计算过程是延迟调用或是异步进行。Dapper确保所有这样的调用可以存储这次跟踪的上下文,而当回调函数被触发时,这次跟踪的上下文会与适当的线程关联。在这种方式下,Dapper可以使用Trace ID和Span ID来辅助构建异步调用的路径。
②跟踪树和Span。在Dapper跟踪树结构中,树节点是整个架构的基本单元,而每一个节点又是对Span的引用。节点之间的连线表示的Span和它的父Span的直接关系。通过简单的ParentId和SpanID就可以有序地把所有的关系串联起来,达到记录业务流的作用。
系统整个调用链(核心思路),现用一个例子来说明对整个调用过程的追踪,5个span在Dapper跟踪树中的关联关系如图3所示,主要有下面几个步骤。
所有请求到来即生成一个全局唯一编码的TraceID,通过TraceID可以串联起整个调用链,一个TraceID只代表一次请求。
在调用过程中,需要SpanID用于记录调用父子关系。每个服务会记录下Parent ID和Span ID。这样通过TraceID和TraceID可以组织一次完整调用链的父子关系。
一个没有Parent Id的Span成为Root Span,可以看成调用链入口。
所有这些ID可用全局唯一的64位整数表示。
整个调用过程中每个请求都要透传TraceID和SpanID。
每个服务将该次请求附带的TraceID和附带的SpanID作为Parent ID记录下,并且将自己生成的SpanID也记录下。
要查看某次完整的调用,只要根据TraceID查出所有调用记录,然后通过Parent ID和Span Id组织起整个调用父子关系即可。
图3 5个Span在Dapper跟踪树中的关联关系图
3.分布式调用链架构及功能
分布式调用链就是把所有调用过程都记录下来。分布式调用链过程中关注各个调用的各项性能指标,如吞吐量(TPS)、响应时间以及错误记录等。全链路性能监控从整体维度到局部维度展示各项指标,将跨应用的所有调用链性能信息集中展现,可方便度量整体和局部性能,并且方便找到故障产生的源头,生产上可极大缩短故障排除时间。常用调用链解决方案的分布式调用链架构如图4所示。
图4 分布式调用链架构图
分布式调用链系统的构成模块及其内容说明如表1所示。
表1 分布式调用链的构成模块及其功能描述
分布式调用链系统的过程如下:通过Agengt组件生成调用链日志;通过Logstash框架采集日志到Kafka框架;Kafka框架负责提供数据给下游消费;Storm框架计算汇聚指标结果并落到Elasticsearch框架;Storm框架抽取Trace数据并落到Elasticsearch框架,这是为了提供比较复杂的查询。如通过时间维度查询调用链,可以很快查询出所有符合的TraceID,根据这些TraceID再去HBase查数据就快了;Logstash框架将Kafka框架的原始数据拉取到HBase数据库中。HBase数据库的Rowkey为TraceID,根据TraceID进行查询速度非常快。
调用链监控核心工作:定义和生成调用链数据——对整个调用过程的所有服务进行埋点并输出日志;采集调用链数据——采集各个服务中的日志数据;存储及查询调用链数据——对采集到的数据进行存储,同时提供快速查询;指标运算、存储及查询——对采集到的调用链数据进行各种指标运算;告警功能——提供各种阈值警告功能。
4.常用解决方案
微服务常见分布式调用链方案如表2所示。
表2 常用的分布式调用链解决方案及其描述。
本文摘抄自书籍《微服务体系建设和实践》,略有改动。如需要更全面和体系化地了解更多细节内容,请阅读书籍《微服务体系建设和实践》。