全链路追踪落地一年:从翻日志到秒级定位,我们都做了什么

一年前,我们排查线上问题的方式是这样的:用户反馈"下单失败",我们打开日志平台,用订单号搜日志,搜出来的是一堆散落在各个服务的日志片段,得人工拼起来才能知道请求到底经过了哪些服务、卡在了哪一环。

一次完整排查平均要40分钟到1个小时。遇到大促期间问题密集,基本就是灾难。

现在我们有了全链路追踪,同样的"下单失败",点开Trace ID,整条调用链一目了然:请求从网关进来,经过订单服务、库存服务、支付服务,在哪一步耗时最长、哪一步抛了异常,全部看得清清楚楚。排查时间从1小时缩到了几分钟。

这篇把我们全链路追踪的落地过程写出来,包括选型、接入、踩坑。给准备搞的团队一个参考。


全链路追踪解决什么问题

微服务架构下,一个请求要经过多个服务,问题就来了:出了问题,你不知道问题在哪一环。

  • 请求超时了,是订单服务慢,还是库存服务慢,还是数据库慢?
  • 请求失败了,异常是在哪个服务抛的?
  • 同一个请求在订单服务打了日志,在支付服务也打了日志,怎么把它们关联起来?

全链路追踪的核心思路:给每个请求分配一个全局唯一的Trace ID,让它贯穿所有服务。每个服务在处理这个请求时,都带上这个Trace ID记录日志。 这样就能把分散在各服务的日志串成一条完整的调用链。

配合可视化工具,你看到的是一张瀑布图:每个服务是一段,耗时、异常一目了然。


选型:我们为什么选SkyWalking

当时市面上的方案主要有三个:SkyWalking、Zipkin、Jaeger。对比了一圈:

方案 接入方式 优点 缺点
SkyWalking Java Agent,无代码侵入 自动探针,部署简单,UI功能全 有一定学习成本
Zipkin SDK埋点 轻量 需要手动埋点,接入成本高
Jaeger SDK埋点 性能好 同样需要手动埋点

我们最终选了SkyWalking,核心原因就一个:Java Agent无侵入。 不需要改业务代码,加上一个Agent参数就能自动采集Spring Boot、Feign、数据库、Redis、消息队列的调用链数据。对存量系统来说,这个优势是碾压级的。

bash 复制代码
# 启动参数加上SkyWalking Agent,其他什么都不用改
java -javaagent:/opt/skywalking/agent/skywalking-agent.jar \
     -Dskywalking.agent.service_name=order-service \
     -jar order-service.jar

落地步骤

第一步:部署SkyWalking后端

SkyWalking包括三部分:OAP Server(收集和存储数据)、UI(可视化界面)、Agent(嵌入应用采集数据)。

我们用Docker Compose起了OAP和UI,一套搞定:

yaml 复制代码
services:
  oap:
    image: apache/skywalking-oap-server:9.7.0
    ports:
      - "11800:11800"   # gRPC采集端口
      - "12800:12800"   # HTTP查询端口
  ui:
    image: apache/skywalking-ui:9.7.0
    ports:
      - "8080:8080"
    environment:
      SW_OAP_ADDRESS: oap:12800

Agent的数据通过gRPC(11800端口)上报到OAP,UI通过HTTP(12800端口)查数据。

第二步:所有服务接入Agent

每个服务的启动参数加上Agent,service_name改成对应服务名。这一步是纯配置,不改任何代码:

bash 复制代码
java -javaagent:/opt/skywalking/agent/skywalking-agent.jar \
     -Dskywalking.agent.service_name=order-service \
     -jar order-service.jar

网关、订单、库存、支付、积分,所有服务都加上,链路就通了。

第三步:日志关联Trace ID

这是让排查效率翻倍的关键一步。SkyWalking会自动生成Trace ID,但这个ID在业务日志里默认看不到。

通过日志框架的MDC(Mapped Diagnostic Context)把Trace ID注入到日志里:

xml 复制代码
<!-- logback配置:在日志格式里加一个traceId占位符 -->
<pattern>%d{HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n</pattern>

再配合SkyWalking Agent,它会自动把Trace ID塞进MDC:

yaml 复制代码
# 在agent配置里开启日志关联
plugin:
  logback:
    pattern: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{tid}] %-5level %logger{36} - %msg%n"

这样日志平台里每条日志都带Trace ID,搜Trace ID能搜出整条链路的日志,点Trace ID能看可视化链路图。 两者打通之后,排查效率才真正起飞。


踩过的坑

落地过程不是一帆风顺的,这几个坑值得说。

坑1:Agent版本必须和服务端匹配。 我们用9.x的Agent配9.x的OAP没问题,但后来升级UI时不小心把OAP升到了10.x,Agent还是9.x,结果采集数据全丢了,UI上啥都看不到。升级时必须Agent和OAP一起升,版本要匹配。

坑2:Agent对性能有损耗,注意压测。 加了Agent之后,每个请求都要采集和上报数据,理论上会有性能损耗。我们在测试环境压测过,P99损耗在3%-5%左右,可接受。但如果你本来就卡在性能边缘,这个损耗要考虑进去。

坑3:采样率别拉满。 全量采集数据量很大,存储成本高,而且压垮OAP。我们的策略是:核心链路100%采样,非核心链路10%采样。 SkyWalking支持按服务配置采样率。

坑4:异步线程和消息队列的链路要单独处理。 我们一开始发现,有些请求的链路在异步任务那里断了------Trace ID没传过去。原因是线程池里的新线程不带上下文。SkyWalking对@Async和RocketMQ有自动支持,但自定义线程池需要手动传递上下文,这个要单独验证。


落地后的实际效果

一年下来,最直观的变化:

排查时间: 平均40分钟 → 5分钟。以前拼日志,现在看链路图,定位慢接口和异常一步到位。

架构梳理: 全链路追踪的拓扑图(哪些服务调了哪些服务、调用量多少)成了我们架构评审的必备材料,新同学看拓扑图就能快速理解系统。

容量规划: 追踪数据里的耗时分布,帮我们定位了好几个隐藏的慢调用------比如某个服务调第三方接口没设超时,平时不显眼,压测时才暴露,追踪数据直接把它揪出来了。

大促保障: 大促期间我们建了个监控大屏,实时看全链路各环节的耗时和错误率,哪个环节顶不住了立刻知道。


结尾

全链路追踪这东西,不上线之前觉得"可有可无",上了线就回不去了。它不是锦上添花的监控工具,而是微服务架构下的基础设施------排查问题、梳理架构、容量规划、大促保障,全都靠它。

如果你还在用"翻日志拼链路"的方式排查问题,强烈建议搞一套。SkyWalking是开源免费的,Agent无侵入,投入产出比极高。

如果这篇对你有用,点个关注。后面我还会写更多微服务治理和性能优化的实战内容。

相关推荐
回家路上绕了弯1 小时前
ZCode 入门教程:从打开项目到完成一次 Java 代码修改
后端
薛定谔的算法1 小时前
M03:面向对象编程(OOP)
后端
SamDeepThinking1 小时前
new Thread()之后发生了什么?
java·后端·面试
晚安日记wanna1 小时前
Vue3 script setup 的四层追问答到第三层才算过关
前端·vue.js·面试
亦暖筑序1 小时前
AgentScope Java 实战:Agent 的状态存在哪、怎么恢复、怎么隔离?
人工智能·后端·agent
斯维赤1 小时前
Spring AI | Function Calling 是什么?
java·后端
devpotato1 小时前
限流、熔断、降级:三者核心区别一文讲清
java
不灭的黄金瞳1231 小时前
Java数据类型与变量
java·开发语言·intellij-idea
yunwei371 小时前
eBPF 教程:BPF 调度器入门
linux·后端·性能优化