「转载」微服务分布式架构中,如何实现日志链路跟踪?

代码鄙视员 2020-10-23 22:59:16 ⋅ 316 阅读

背景

开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用ELK来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,我们来看下面的图

微服务分布式架构中,如何实现日志链路跟踪?

 

 

上图一个用户请求一个url,整个链路如图,每个处理层都会产生日志,那我们如何把这些日志串在一些,形成一个请求全路径日志。

在现有的系统中,由于大量的其他用户/其他线程的日志也一起输出穿行其中导致很难筛选出指定请求的全部相关日志。那我们如何来处理呢?

解决思路

我们可以把每个请求弄一个唯一标识,然后我们可以在日志打印的时候代上每个请求都使用一个唯一标识,而且那个唯一标识需要传递给下游服务下游服务打印日志的时候也带上这个唯一标识,这样就很好的追踪全部的链路显示在日志中。

那技术实现方案是什么呢?我们应该尽可能的对代码无入侵,使用Logback的MDC机制日志模板中加入traceId标识,取值方式为%X{traceId}

什么是MDC

MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能MDC 可以看成是一个与当前线程绑定的Map,可以往其中添加键值对

MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据。

方案实现

由于MDC内部使用的是ThreadLocal所以只有本线程才有效,子线程和下游的服务MDC里的值会丢失;所以方案主要的难点是解决值的传递问题,主要包括以几下部分:

  • API网关中的MDC数据如何传递给下游服务
  • 服务如何接收数据,并且调用其他远程服务时如何继续传递
  • 异步的情况下(线程池)如何传给子线程

修改日志模板

logback配置文件日志格式添加该标识

微服务分布式架构中,如何实现日志链路跟踪?

 

网关添加过滤器

此过滤器就是来解决网关如何把MDC的数据传递给下游服务

生成traceId并通过header传递给下游服务

微服务分布式架构中,如何实现日志链路跟踪?

 

上面代码有个MDC是属于org.slf4j.MDC中的,下面就是常量的值

/**
* 日志链路追踪id信息头
*/
String TRACE_ID_HEADER = "x-traceId-header";
/**
* 日志链路追踪id日志标志
*/
String LOG_TRACE_ID = "traceId";

下游服务增加spring拦截器

接收并保存traceId的值

微服务分布式架构中,如何实现日志链路跟踪?

 

下游服务增加feign拦截器

继续把当前服务的traceId值传递给下游服务

微服务分布式架构中,如何实现日志链路跟踪?

 

解决父子线程传递问题

主要针对业务会使用线程池(异步、并行处理),并且spring自己也有@Async注解来使用线程池,要解决这个问题需要以下两个步骤:

重写logback的LogbackMDCAdapter

由于logback的MDC实现内部使用的是ThreadLocal不能传递子线程,所以需要重写替换为阿里的TransmittableThreadLocal

TransmittableThreadLocal 是Alibaba开源的、用于解决 “在使用线程池等会缓存线程的组件情况下传递ThreadLocal” 问题的 InheritableThreadLocal 扩展。若希望 TransmittableThreadLocal 在线程池与主线程间传递,需配合TtlRunnable和TtlCallable使用。

微服务分布式架构中,如何实现日志链路跟踪?

 

其他代码与ch.qos.logback.classic.util.LogbackMDCAdapter一样,只需改为调用copyOnInheritThreadLocal变量

TtlMDCAdapterInitializer类用于程序启动时加载自己的mdcAdapter实现

微服务分布式架构中,如何实现日志链路跟踪?

 

扩展线程池实现

增加TtlRunnable和TtlCallable扩展

微服务分布式架构中,如何实现日志链路跟踪?

 

微服务分布式架构中,如何实现日志链路跟踪?

 

场景测试

测试代码如下

log.info("测试")


@Async
public void test(){
  log.info("测试1")
}


userService.findByUserName("gu")

api网关打印的日志

微服务分布式架构中,如何实现日志链路跟踪?

 

ELK聚合日志通过traceId查询整条链路日志

当系统出现异常时,可直接通过该异常日志的traceId​的值,在日志中心中询该请求的所有日志信息,类似下图

微服务分布式架构中,如何实现日志链路跟踪?

 

总结

到此分布式的日志跟踪就已经完成了,这样就很好的可以排查整个微服务的日志链路,谢谢!!!

---End---


全部评论: 0

    我有话说:

    WeCube 2.7.1 发布,一站式 IT 架构管理和运维管理工具

    WeCube简介 众银行在分布式架构实践的过程,发现将银行核心系统构建于分布式架构之上,会遇到一些与传统单体应用不同的痛点(例如,服务器增多,部署难度大;调用长,全跟踪困难; 系统复杂

    WeCube 2.7.0 版本发布,一站式架构和运维管理工具

    WeCube简介 众银行在分布式架构实践的过程,发现将银行核心系统构建于分布式架构之上,会遇到一些与传统单体应用不同的痛点(例如,服务器增多,部署难度大;调用长,全跟踪困难; 系统复杂

    架构实战篇:认识一下服务架构

    服务是一个新兴的软件架构,就是把一个大型的单个应用程序和服务拆分为数十个的支持服务

    码云推荐:一个优秀的分布式spring boot/Spring Cloud API限流框架,特别适合服务架构

    一个优秀的分布式spring boot/Spring Cloud API限流框架,特别适合服务架构.

    架构实战篇:一个可供中小团队参考的服务架构技术栈

    作者近年一直在一线互联网公司(携程,拍拍贷等)开展服务架构实践,根据我个人的一线实践经验和我平时对Spring Cloud的调研,我认为Spring Cloud技术栈的有些组件离生产级开发尚有

    你的老板逼你上服务了吗?

    “ 这些年软件的设计规模越来越庞大,业务需求也越来越复杂,针对系统的性能、高吞吐率、高稳定性、高扩展等特性提出了更高的要求。   图片来自 Pexels可以说业务需求是软件架构能力的

    服务架构学习笔记(一):重新认识服务

    服务(Microservice)是服务化思路的一种最佳实践方向,遵循SOA的思路,各个企业在服务化治理的道路上走的时间长了,踩的坑多了,整个软件交付路上各个环节的基础设施逐渐成熟了,服务

    精品推荐:服务架构下静态数据通用缓存机制

    分布式系统,特别是最近很火的服务架构下,有没有或者能不能总结出一个业务静态数据的通用缓存处理机制或方案,这篇文章将结合一些实际的研发经验,尝试理清其中存在的关键问题以及探寻通用的解决之道。

    【开源资讯】JWCloud 专业版 v1.0.0 发布,基于 SpringCloud 研发的服务框架

    简介 JavaWeb_Cloud 服务平台是一款基于 SpringCloud 框架研发的分布式微服务框架,主要使用技术栈包括: SpringCloud、Vue、ElementUI

    字节跳动 | 服务架构如何优雅地重试?

    背景 在服务架构,一个大系统被拆分成多个小服务,小服务之间大量 RPC 调用,经常可能因为网络抖动等原因导致 RPC 调用失败,这时候使用重试机制可以提高请求的最终成功率,减少故障影响,让系统

    服务架构下的若干常用设计模式

    在我们选择了用服务架构来设计、交付数字化应用后,因服务架构本身所带来的一些共性问题。

    SpringBoot+zk+dubbo架构实践(一):本地部署zookeeper

    SpringBoot+zk+dubbo架构实践系列实现目标:自己动手搭建服务架构

    【分享】一次单体架构改造成服务架构的拆分实践

    从5个方面设计这次服务的拆分方案,以及经验总结!

    服务化改造实践 | 如何在 Dubbo 支持 REST

    随着服务的流行以及多语言互操作诉求的日益增多,在 Dubbo 暴露 REST 服务变成了一个不容忽视的诉求。

    服务架构:搭建网站扫码登录的功能设计

    信扫码登录大家都是应用比较多的登录方式了,现在大的购物网站像京东、淘宝等都支持使用APP扫码登录网站了。今天就用APP扫码登录网站的实例来举例说明服务架构的搭建过程。

    Plumelog 3.3-RELEASE 已经发布,分布式日志组件

    ,设置ID,方便查询关联日志 基于ela...