可视化全链路日志追踪
- 1. 背景
- 1.1 业务系统日益复杂
- 1.2 业务追踪面临挑战
- 2. 可视化全链路日志追踪
- 2.1 设计思路
- 2.2 通用方案
- 3. 大众点评内容平台实践
- 3.1 业务特点与挑战
- 3.2 实践与成果
- 4. 总结与展望
1. 背景
1.1 业务系统日益复杂
随着互联网产品的快速发展,不断变化的商业环境和用户诉求带来了纷繁复杂的业务需求。业务系统需要支撑的业务场景越来越广、涵盖的业务逻辑越来越多,系统的复杂度也跟着快速提升。与此同时,由于微服务架构的演进,业务逻辑的实现往往需要依赖多个服务间的共同协作。总而言之,业务系统的日益复杂已经成为一种常态。1.2 业务追踪面临挑战
业务系统往往面临着多样的日常客诉和突发问题,“业务追踪”就成为了关键的应对手段。业务追踪可以看做一次业务执行的现场还原过程,通过执行中的各种记录还原出原始现场,可用于业务逻辑执行情况的分析和问题的定位,是整个系统建设中重要的一环。 目前在分布式场景下,业务追踪的主流实现方式包括两类,一类是基于日志的ELK方案,一类是基于单次请求调用的会话跟踪方案。然而随着业务逻辑的日益复杂,上述方案越来越不适用于当下的业务系统。1.2.1 传统的ELK方案
-
日志搜集繁琐 :虽然ES提供了日志检索的能力,但是日志数据往往是缺乏结构性的文本段,很难快速完整地搜集到全部相关的日志。
-
日志筛选困难 :不同业务场景、业务逻辑之间存在重叠,重叠逻辑打印的业务日志可能相互干扰,难以从中筛选出正确的关联日志。
-
日志分析耗时 :搜集到的日志只是一条条离散的数据,只能阅读代码,再结合逻辑,由人工对日志进行串联分析,尽可能地还原出现场。
1.2.2 分布式会话跟踪方案
在分布式系统,尤其是微服务系统中,业务场景的某次请求往往需要经过多个服务、多个中间件、多台机器的复杂链路处理才能完成。为了解决复杂链路排查困难的问题,“分布式会话跟踪方案”诞生。该方案的理论知识由Google在2010年《Dapper》论文 [3] 中发表,随后Twitter开发出了一个开源版本Zipkin [4] 。1.2.3 总结
传统的ELK方案是一种滞后的业务追踪,需要事后从大量离散的日志中搜集和筛选出需要的日志,并人工进行日志的串联分析,其过程必然耗时耗力。而分布式会话跟踪方案则是在调用执行的同时,实时地完成了链路的动态串联,但由于是会话级别且仅关注于调用关系等问题,导致其无法很好地应用于业务追踪。 因此,无论是传统的ELK方案还是分布式会话跟踪方案,都难以满足日益复杂的业务追踪需求。本文希望能够实现聚焦于业务逻辑追踪的高效解决方案,将业务执行的日志以业务链路为载体进行高效组织和串联,并支持业务执行现场的还原和可视化查看,从而提升定位问题的效率,即 可视化全链路日志追踪 。 下文将介绍 可视化全链路日志追踪 的设计思路和通用方案,同时介绍新方案在大众点评内容平台的落地情况,旨在帮助有类似需求的业务系统开发需求的同学提供一些思路。2. 可视化全链路日志追踪
2.1 设计思路
可视化全链路日志追踪 考虑在前置阶段,即业务执行的同时实现业务日志的高效组织和动态串联,如下图4所示,此时离散的日志数据将会根据业务逻辑进行组织,绘制出执行现场,从而可以实现高效的业务追踪。-
逻辑节点 :业务系统的众多逻辑可以按照业务功能进行拆分,形成一个个相互独立的业务逻辑单元,即 逻辑节点 ,可以是本地方法( 如下图5的“判断逻辑”节点 )也可以是RPC等远程调用方法( 如下图5的“逻辑A”节点 )。
-
逻辑链路 :业务系统对外支撑着众多的业务场景,每个业务场景对应一个完整的业务流程,可以抽象为由逻辑节点组合而成的 逻辑链路 ,如下图5中的逻辑链路就准确完整地描述了“审核业务场景”。
- 通过在执行线程和网络通信中持续地透传参数,实现在业务逻辑执行的同时,不中断地传递链路和节点的标识,实现离散日志的染色。
- 基于标识,染色的离散日志会被动态串联至正在执行的节点,逐渐汇聚出完整的逻辑链路,最终实现业务执行现场的高效组织和可视化展示。
2.2 通用方案
明确日志的高效组织和动态串联这两个基本问题后,本文选取图4业务系统中的“逻辑链路1”进行通用方案的详细说明,方案可以拆解为以下步骤:2.2.1 链路定义
“链路定义”的含义为:使用特定语言,静态描述完整的 逻辑链路 ,链路通常由多个 逻辑节点 ,按照一定的 业务规则 组合而成, 业务规则 即各个逻辑节点之间存在的执行关系,包括 串行 、 并行 、 条件分支 。 [
{
"nodeName": "A",
"nodeType": "rpc"
},
{
"nodeName": "Fork",
"nodeType": "fork",
"forkNodes": [
[
{
"nodeName": "B",
"nodeType": "rpc"
}
],
[
{
"nodeName": "C",
"nodeType": "local"
}
]
]
},
{
"nodeName": "Join",
"nodeType": "join",
"joinOnList": [
"B",
"C"
]
},
{
"nodeName": "D",
"nodeType": "decision",
"decisionCases": {
"true": [
{
"nodeName": "E",
"nodeType": "rpc"
}
]
},
"defaultCase": [
{
"nodeName": "F",
"nodeType": "rpc"
}
]
}
]
2.2.2 链路染色
“链路染色”的含义为:在链路执行过程中,通过透传串联标识,明确具体是哪条链路在执行,执行到了哪个节点。 链路染色包括两个步骤: 步骤一 :确定串联标识,当逻辑链路开启时,确定唯一标识,能够明确后续待执行的链路和节点。-
链路唯一标识 = 业务标识 + 场景标识 + 执行标识 ( 三个标识共同决定“某个业务场景下的某次执行” ) - 业务标识:赋予链路业务含义,例如“用户id”、“活动id”等等。
- 场景标识:赋予链路场景含义,例如当前场景是“逻辑链路1”。
- 执行标识:赋予链路执行含义,例如只涉及单次调用时,可以直接选择“traceId”;涉及多次调用时则,根据业务逻辑选取多次调用相同的“公共id”。
-
节点唯一标识 = 链路唯一标识 + 节点名称 ( 两个标识共同决定“某个业务场景下的某次执行中的某个逻辑节点” ) - 节点名称:DSL中预设的节点唯一名称,如“A”。
- 当“A”节点触发执行,则开始在后续链路和节点中传递串联标识,随着业务流程的执行,逐步完成整个链路的染色。
- 当标识传递至“E”节点时,则表示“D”条件分支的判断结果是“true”,同时动态地将“E”节点串联至已执行的链路中。
2.2.3 链路上报
“链路上报”的含义为:在链路执行过程中,将日志以链路的组织形式进行上报,实现业务现场的准确保存。2.2.4 链路存储
“链路存储”的含义为:将链路执行中上报的日志落地存储,并用于后续的“现场还原”。上报日志可以拆分为链路日志、节点日志和业务日志三类:-
链路日志 :链路单次执行中,从开始节点和结束节点的日志中提取的链路基本信息,包含链路类型、链路元信息、链路开始/结束时间等。
-
节点日志 :链路单次执行中,已执行节点的基本信息,包含节点名称、节点状态、节点开始/结束时间等。
-
业务日志 :链路单次执行中,已执行节点中的业务日志信息,包含日志级别、日志时间、日志数据等。
3. 大众点评内容平台实践
3.1 业务特点与挑战
互联网时代,内容为王。内容型平台的核心打法就是搭建内容流水线,保障内容可持续、健康且有价值地流转到内容消费者,并最终形成内容“生产→治理→消费→生产”的良性循环。 大众点评和美团App拥有丰富多样的内容,站内外业务方、合作方有着众多的消费场景。对于内容流水线中的三方,分别有如下需求:-
内容的生产方 :希望生产的内容能在更多的渠道分发,收获更多的流量,被消费者所喜爱。
-
内容的治理方 :希望作为“防火墙”过滤出合法合规的内容,同时整合机器和人工能力,丰富内容属性。
-
内容的消费方 :希望获得满足其个性化需求的内容,能够吸引其种草,或辅助其做出消费决策。
-
统一接入 :统一内容数据模型,对接不同的内容生产方,将异构的内容转化为内容平台通用的数据模型。
-
统一处理 :统一处理能力建设,积累并完善通用的机器处理和人工运营能力,保证内容合法合规,属性丰富。
-
统一输出 :统一输出门槛建设,对接不同的内容消费方,为下游提供规范且满足其个性化需求的内容数据。
-
业务场景多 :业务流程涉及多个不同的业务场景,且逻辑各异,例如实时接入、人工运营、分发重算等图中列出的部分场景。
-
逻辑节点多 :业务场景涉及众多的逻辑节点,且不同内容类型节点各异,例如同样是实时接入场景,笔记内容和直播内容在执行的逻辑节点上存在较大差异。
-
触发执行多 :业务场景会被多次触发执行,且由于来源不同,逻辑也会存在差异,例如笔记内容被作者编辑、被系统审核等等后,都会触发实时接入场景的重新执行。
3.2 实践与成果
3.2.1 实践
点评内容平台是一个复杂的业务系统,对外支撑着众多的业务场景,通过对于业务场景的梳理和抽象,可以定义出实时接入、人工运营、任务导入、分发重算等多个业务逻辑链路。由于点评内容平台涉及众多的内部服务和下游依赖服务,每天支撑着大量的内容处理业务,伴随着业务的执行将生成大量的日志数据,与此同时链路上报还需要对众多的服务进行改造。因此在通用的全链路日志追踪方案的基础上,点评内容平台进行了如下的具体实践。 (1) 支持大数据量日志的上报和存储 点评内容平台实现了图12所示的日志上报架构,支持众多服务统一的日志收集、处理和存储,能够很好地支撑大数据量下的日志追踪建设。
- 模仿slf4j-api :工具包的实现在slf4j框架之上,并模仿slf4j-api对外提供相同的API,因此使用方无学习成本。
- 屏蔽内部细节,内部封装一系列的链路日志上报逻辑,屏蔽染色等细节,降低使用方的开发成本。
-
上报判断 : - 判断链路标识:无标识时,进行兜底的日志上报,防止日志丢失。
- 判断上报方式:有标识时,支持日志和RPC中转两种上报方式。
-
日志组装 :实现参数占位、异常堆栈输出等功能,并将相关数据组装为Trace对象,便于进行统一的收集和处理。 -
异常上报 :通过ErrorAPI主动上报异常,兼容原日志上报中ErrorAppender。 -
日志上报 :适配Log4j2日志框架实现最终的日志上报。
// 替换前:原日志上报
LOGGER.error("update struct failed, param:{}", GsonUtils.toJson(structRequest), e);
// 替换后:全链路日志上报
TraceLogger.error("update struct failed, param:{}", GsonUtils.toJson(structRequest), e);
节点日志上报
:支持API、AOP两种上报方式,灵活且成本低。
案例
:节点日志上报
public Response realTimeInputLink(long contentId) {
// 链路开始:传递串联标识(业务标识 + 场景标识 + 执行标识)
TraceUtils.passLinkMark("contentId_type_uuid");
// ...
// 本地调用(API上报节点日志)
TraceUtils.reportNode("contentStore", contentId, StatusEnums.RUNNING)
contentStore(contentId);
TraceUtils.reportNode("contentStore", structResp, StatusEnums.COMPLETED)
// ...
// 远程调用
Response processResp = picProcess(contentId);
// ...
}
// AOP上报节点日志
@TraceNode(nodeName="picProcess")
public Response picProcess(long contentId) {
// 图片处理业务逻辑
// 业务日志数据上报
TraceLogger.warn("picProcess failed, contentId:{}", contentId);
}
3.2.2 成果
基于上述实践,点评内容平台实现了可视化全链路日志追踪,能够一键追踪任意一条内容所有业务场景的执行,并通过可视化的链路进行执行现场的还原,追踪效果如下图所示: 【链路查询功能】 :根据内容id实时查询该内容所有的逻辑链路执行,覆盖所有的业务场景。-
接入成本低 :DSL配置配合简单的日志上报改造,即可快速接入。
-
追踪范围广 :任意一条内容的所有逻辑链路,均可被追踪。
-
使用效率高 :管理后台支持链路和日志的可视化查询展示,简单快捷。
4. 总结与展望
5. 参考文献
-
[1] Metrics, tracing, and logging -
[2] ELK Stack: Elasticsearch, Logstash, Kibana | Elastic -
[3] Dapper, a Large-Scale Distributed Systems Tracing Infrastructure -
[4] OpenZipkin · A distributed tracing system -
[5] 分布式会话跟踪系统架构设计与实践 -
[6] 凤凰架构-可观测性 -
[7] 万字破解云原生可观测性