首页 / 业界 / 正文

链路追踪的一线踩坑实录

上周三夜里十一点,我还在新街口那家24小时咖啡店改方案,微信直接弹了炸群消息。
是之前合作的生鲜配送团队,大促期间订单系统炸了。
用户点了提交订单,付完钱,跳回页面显示支付超时。但支付渠道那边的账单已经扣了钱。
客服后台被投诉刷爆,运维一开始查网关,CPU正常,QPS正常,所有指标都绿得晃眼。查订单服务,日志里压根没收到支付回调的记录。找支付渠道的同事对接,人家说回调早在十分钟前就发出来了,日志里存得明明白白。
就这么来回扯了三个小时,最后才定位到——消息队列的一个消费节点悄悄挂了,没触发告警,回调消息全堵在队列里,没人处理。
真的。那三个小时里,整个团队的人都在翻各自的服务日志,像大海捞针一样找那笔扣款的记录。

分布式微服务订单链路追踪故障排查示意图


之前的监控为什么没用


很多人觉得,我上了Prometheus,搭了Grafana,所有服务的CPU、内存、接口延迟都看得到,就够了。
真不是。
之前那个生鲜团队就是这样,每个服务的指标面板做得漂漂亮亮,但是没人知道一个请求从用户点提交,到网关路由,到订单服务生成订单,到调用支付接口,到支付回调异步通知,到库存服务扣减库存,整个流程里,哪一步卡了壳。
说白了,之前的监控都是给单个服务做体检,但是没人知道一个人从进门到挂号到拿药,哪一步被堵在了走廊里。

别把链路追踪当监控的附属品


他们不是没试过接链路追踪。
去年为了赶项目进度,花了一周时间把Jaeger部署起来,给所有服务塞了SDK,拉了个面板看整体延迟,就完事了。
结果真出故障的时候,根本搜不到那笔失败请求的链路。
为什么?
因为他们的traceId没有穿透到异步链路里。
支付回调是走消息队列的,生产者那边压根没把traceId放到消息头里,消费者这边也没做解析,所以整个链路直接断成了两截。支付那边的trace和订单这边的trace对不上,就算你把所有链路都拉出来,也凑不成一个完整的请求路径。

微服务traceId跨消息队列透传流程示意图
微服务traceId跨消息队列透传流程示意图


很多人上链路追踪,就只给同步调用的接口接SDK,异步的消息队列、定时任务、甚至前端的埋点,全都不管。最后出来的链路都是碎的,跟没接差不多。
别信那些说链路追踪就是给监控加个维度的鬼话。它的核心就是把一个请求的全生命周期串起来,不管中间走了多少个服务,多少个异步队列,只要traceId没丢,你就能顺着线摸到出问题的地方。

落地的时候别贪大求全


我后来给他们提的建议,不是把所有服务都接进链路追踪,而是先把核心链路捋清楚。
什么是核心链路?就是用户从提交订单到收到货的这一条必经路径:网关、订单服务、支付服务、消息队列、库存服务,就这五个。
先把这五个服务的链路打通,确保traceId全链路透传,不管是同步调用还是异步发消息,traceId都要跟着走。然后给每个链路的节点打标签,比如订单号、用户ID、支付渠道、商品ID,这样出问题的时候,你直接搜订单号,就能把整个链路拉出来。
哪一步延迟高,哪一步报错,哪一步堵了消息,一眼就能看到。
别贪多。
我见过很多团队一上来就给所有服务接SDK,包括那种半年才用一次的内部报表服务,光SDK适配就花了两周,结果大半年都没出过一次问题,纯纯浪费人力。
你要是真的把所有边缘服务都接进来,光每天存链路数据的存储成本,都能让运维同事追着你骂三条街。

这周他们又出了个小问题。
用户下单后,库存扣了,但是订单没生成。
这次只用了四分钟就定位到了——订单服务的数据库连接池打满了,有个慢SQL占了三个连接,导致新的请求拿不到连接,直接报错。
搁以前,这个问题至少要花半小时才能查到。
说实话,我之前也觉得链路追踪是大厂才用得起的东西,直到自己踩过那种来回扯的故障,才知道这东西就是给普通人省头发的。
当然也不是万能的。
比如代码里的空指针,要是没打日志,链路里也只会显示一个500错误,还是得结合日志看。别指望它能直接给你把bug改了。
对吧?你要是真的试过三个小时翻几百兆日志找一个错误,你就知道链路追踪有多香了。