原创 梁波Eric Eric技术圈 2024年08月15日 09:18 四川
如果不想引入第三方组件,比如:Sping Cloud Sleuth ,可以采用轻量级的解决方案来完成分布式系统下的日志链路追踪。
同时本文主要聚焦在日志的链路追踪,服务之间的调用链路追踪,可采用工具实现,比如:Jaeger、Zipkin、SkyWalking、Pinpoint、Elastic APM 等。
问题
Spring 默认的日志框架 Logback 中提供的 LogbackMDCAdapter 内部使用的是ThreadLocal,只有本线程才有效,子线程和下游的服务 MDC 里的值会丢失。
主要的难点是解决值传递问题,主要包括以下几个部分:
-
API Gateway 网关中如何传递 MDC 中的 TraceId
-
微服务之间互相远程调用时如何传递 MDC 中的 TraceId
-
异步情况下(线程池)如何传递 MDC 中的 TraceId 到子线程
-
........
环境准备
技术选型:
-
Java 21
-
Spring Boot 3.2.4
-
Spring Cloud 2023.0.1
-
Spring Cloud Gateway 4.1.2
-
Spring Cloud OpenFeign 4.1.1
-
Alibaba Transmittable Thread Local 2.14.5
01 API Gateway 网关
创建一个 GlobalTraceFilter
进行 Web 请求 和 路由请求的 TraceId 过滤处理,参考:
配置 Logback 文件 logback-spring.xml:
-
<springProperty scope="context" name="appName" source="spring.application.name"/>
-
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%X{traceId:-}]){yellow} %clr([${appName}]){blue} %clr([%thread]){orange} %clr(%-40.40logger{39}){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
02 下游微服务拦截 Http Header
解析 Http 请求 Header 中的 TraceId,可以看到由第一步 Api Gateway 设置的。创建一个
03 下游微服务互相调用
创建 OpenFeign Interceptor ,下游服务之间的相互调用统一使用 FeignClient 进行调用。
04 异步多线程传递问题
改造 LogbackMDCAdapter
将 LogbackMDCAdapter 重新拷贝使用阿里巴巴的 TransmittableThreadLocal 替换 ThreadLocal,来解决多线程无法传递 MDC 值问题。
SpringBoot 3.0 以上版本后,无法替换 Logback 的 MDC Adapter,需要将我们新建的 MDC Adapter配置到spi文件中,参考下图 META-INFO下services 目录中的SLF4JServiceProvider。
成功后日志输出如下:
但是每次启动都会有类似的错误提醒,后续看下是否可以优化。
替换 Spring 默认线程池
同理也是使用 alibaba 的 TtlRunnable进行替换。
小结
随着系统管理的服务数量的不断增加,了解系统在生产环境的状态愈发困难,同时也导致排查问题故障变得更加困难,建议在考虑采用微服务架构之前,将日志聚合和分布式追踪作为先决条件。
附录
Gateway 改造 MDC 后验证:
下游服务调用:
1)通过 Gateway 请求下游服务
2)下游服务日志查看 TraceId
可观测性( Elastic Stack ):
关于如何部署可视化工具,参考公众号之前 Elastic 可观测性系列文章。
Spring Cloud Sleuth: