前言
进入云原生时代后,依托于容器技术与分布式技术的发展,为适应高并发,高压力,快速迭代场景,微服务架构成为了更多企业的必然选择。微服务架构为互联网时代的软件开发带来了巨大优势,如增加了服务的可扩展性,增强了易维护性,减少了语言相关性等等。
但同时,从单体架构到微服务架构的转变,应用监控层面提出了前所未有的挑战。服务的拆分使应用及服务间相互调用关系成几何级增长。从用户端发起的一个请求,可能会在微服务及各中间件之间相互调用,最终形成一篇复杂的调用关系网。
一个用户请求发出后,完整的调用链示意图如下:
此时,传统的基于单机业务的监控系统对新的关系网络监控显得力不从心。因此,在微服务架构体系下,亟需建立一种全新的监控机制,能够及时监控及反馈应用及系统的运行状况,在系统运行异常时能够辅助研发人员定位问题,同时为系统性能调优提供充足的数据支持。
1、全链路监控的目标是什么?
微服务架构使应用及中间件之间的调用链路变得更加复杂。同时,云原生及混合云的兴起对全链路监控的实现提出了更高要求。
为提升混合云模式下的微服务架构应用的健壮性及稳定性,通常来说,我们对全链路监控提出的3个核心诉求如下:
1. 系统间依赖梳理:能够完整绘制系统及服务间的调用关系,以帮助开发及运维评判上下游依赖关系,确定故障影响范围等;
2. 关键性能指标展示:能够展示每一个环节对应的关键性能指标,可为研发人员给出性能优化方向,且可帮助运维人员对系统资源的合理分配给出建议;
3. 端到端问题诊断:当系统出现故障或异常时,能够第一时间发出报警,协助运维人员发现并快速定位和解决问题。
全链路监控就在为解决这些问题的背景下产生。
全链路监控是一套用来针对跨语言、跨应用、跨服务器、跨数据中心的分布式系统服务,通过添加探针等方式,采样并收集应用及系统等性能指标,以调用链为主要方式展示监控数据,用于帮助开发及运维人员分析性能问题,定位异常问题的分布式监控系统。
一些平台也将全链路监控称为全链路追踪。可以说全链路监控是一套覆盖全部相关联的IT系统,是一套能够完整记录用户行为,存储日志,展示各系统之间调用路径与状态的最佳实践方案。
在全链路监控体系下,调用链是一个核心概念。其意指从请求源头,经过微服务调用,到底层各中间件之间的所有中间调用环节。
全链路监控的关键价值在于“关联”,即由终端用户、后台微服务应用、云端中间件组件等共同构建编织的关系网。理论上,这张关系网能够覆盖的范围越大,收集的关键指标越多,那么全链路监控能够发挥的价值也就越大。
2、实现全链路监控的难点是什么?
混合云模式下的各个微服务应用可能由不同的研发团队开发,且需要部署在多台服务器中以实现水平扩展功能,甚至可能同时部署在云端及自建机房的数据中心中,各类型的中间件部署及调用方式也是千差万别。
在此背景下,实现全链路监控所要面临的挑战很多,总结起来有如下几点:
1. 支持大规模混合云场景:当数以千计的微服务应用部署在公有云及混合云的情况下,如何快速及时的采集应用运行状态信息,同时采集日志至日志中心。如何采集并将第三方中间件间纳入监控系统,均是全链路监控研发人员需要面对的最严峻问题。
2. 降低对业务的影响:如果全链路监控抓取数据的SDK或探针在运行时,占用过多系统资源,或对应用性能产生过大影响,则会降低系统整体的抗压能力,甚至可能会对业务造成后果严重的不可预知的故障。
3. 监控体系丰富完备:一般而言,Java语言编写的应用较为容易获取其运行态监控数据,但其他类型应用由于生态相对不够完备,难以从底层架构层面进行全面支持。针对其他语言编写的应用,及对通过多种渠道部署的中间件进行完备的指标采集,是研发人员需要考虑的问题。
4. 维护工作简单可行:除部署在客户端的SDK或探针以外,一套完整的全链路监控在服务端由接收模块、计算模块、存储模块、展示模块等部分组成。运维人员需要对每一个探针及模块进行维护。因此,全链路监控系统在研发时必须考虑自身的易维护性,否则在大规模体系下,运维工作将成为一场灾难。
5. 保障自身高可用性:全链路监控系统必须能够保障自身具有一定的高可用性,否则可能当某个模块或组件出现异常时,对整体业务系统失去正常监控功能。极端情况下,甚至会引起蝴蝶效应,而引起整个系统的雪崩出现。
我们说全链路监控的价值与其可覆盖的监控范围成正比,而它的挑战也同样与监控范围成正比。因此,全链路监控研发人员在实现功能时,必须同时考虑并克服这五条难点。
3、全链路监控的规范是什么?
十几年前,在《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》这篇业内著名论文中,谷歌详细阐述了如何在一个大规模的系统上,建立一套具有低损耗、应用级透明、可大范围部署属性的分布式系统链路追踪服务。
在Dapper论文中,谷歌披露了分布式系统链路跟踪的实现技术细节,包括数据表示、埋点、传输、采集、存储和显示,并提出了跟踪树、Trace、Span、和Annotation等重要概念,为全链路监控的实现提供了理论依据。
受Dapper的启发,业界研发了许多用于分布式链接跟踪的开源组件。由于需要记录链路中每一个环节的信息,这些信息不仅局限在某一个环节内,更需要跨越不同的应用和分布式中间件传播,因此必须制定一套统一的标准规范。全链路中的各个环节必须遵守此规范及标准,才能实现完整信息的描述、跟踪及传输功能。这套标准被称为OpenTracing。
可以这样说,OpenTracing是独立于编程语言和业务逻辑之外,抽象出的一套接口,可以统一管理链路跟踪领域中的各个元素,从而实现完整的全链路监控。
Span
Span是全链路监控中的基本单元,微服务及中间件之间每次调用创建一个Span。这个调用既可以是RPC调用,也可以是数据库访问等。Span由一个64位ID标识。UUID较为方便,是生成Span ID的首选。一个Span中记录了包括名称、调用时间、键值对形式的标签数据、父调用ID等信息。
值得强调的是,Dapper通过记录每个Span的父ID,来跟踪一次完整的链路请求。即每级Span只记录调用发起方的ID,同时一次完整的调用具有相同的trace id。如果一个Span没有父ID,则其称为Root Span。读取记录时,根据Trace ID获取全部的Span,根据父ID将各个Span连接起来,即可绘制一次请求的完整调用链路。
Trace
Trace用于标记一次请求从发起开始,经过各个微服务应用和中间件,直到服务返回结束为止。Trace是有向树结构的Span集合。
图中,每种颜色的标签表示一个Span,一条访问链路通过唯一的Trace ID标识。整个架构以树结构表示,树中的每个节点是一个Span。树中节点之间的连线表示Span和它的父Span之间的调用关系。
Annotation
Annotation为注解,用来记录与某一事件相关的信息,比如发生时间等。一个Span中可以由多个Annotation来描述。
Dapper采集数据过程
如图所示,Dapper daemon采集业务日志,并将日志信息存入log file中,Dapper Collectors 定时请求拉取日志,存放到Central Bigtable中。
由于日志量过大,Dapper在采集日志时使用采样率模式。如设置采样率为1/1024,则意为每产生1024份日志采集一次。