上周跟老周在公司楼下吃夜宵,他灌了半瓶冰啤酒才缓过来——大促前三天,支付链路偶发超时,每次复现都像抽盲盒,查了两天服务器日志、数据库慢查询、甚至把Nginx的访问日志翻了个底朝天,连运维同学都把磁盘IO磨出了火星,愣是没找到根因。最后临时把刚部署了一周的链路追踪平台拉出来,点进去看了十分钟,问题直接跳出来:优惠券服务的重试逻辑在第三方接口超时的时候,没做指数退避,连续打了二十多次请求把自己的线程池占满,后面的支付请求全卡在调用优惠券那一步排队。

说出来你可能不信,这是我今年碰到的第七起“靠日志查了几天找不到根因,上了链路追踪十分钟解决”的案例。很多人对链路追踪的认知还停留在“微服务架构的配套工具”,觉得只要上了Spring Cloud或者Dubbo就必须搭一套,不然就不算云原生。真的。不是。
那些没被日志记录下的“隐形卡壳点”
不少团队会说,我有全量日志、有Prometheus监控、有APM工具,足够覆盖问题排查场景了。真不够。
你查日志的时候,只能看到自己服务打出的“调用优惠券接口超时”,但你不知道这个超时是发生在网络传输层丢包,还是对方服务内部的某个分支逻辑卡了,还是对方已经正常返回了但你的客户端因为连接池满了没收到响应。之前有个做连锁零售的客户,他们的订单创建接口P99延迟一直飘在2s以上,开发团队写了三个月的性能优化PR,又是加数据库索引又是优化SQL执行计划,结果延迟一点没降。上了链路追踪才发现,是序列化的时候把订单里关联的所有商品详情、用户等级、优惠券信息全查出来塞进了返回体,光对象序列化就花了800ms,真正的数据库写入操作只花了30ms。之前三个月的优化,全做在了无关的地方。

更常见的坑是异步任务的上下文断裂。很多开发写代码的时候,习惯把耗时操作丢到自定义线程池里异步执行,却忘了把traceId从主线程透传到异步线程里,结果查链路的时候,异步任务的片段直接跟主调用链断开,跟没埋点一样。我上次帮客户排查的时候,他们的异步发券服务的trace全是断的,找了半天才发现是开发同学自己写的线程池,没加上下文传递的拦截器,白瞎了之前花了一周时间做的全量埋点。
落地别上来就全量埋点 先盯最疼的那几个接口
我见过太多团队,一上来就搞全链路100%采样,所有服务不管是核心的还是边缘的,全把埋点打上,结果跑了不到一个月,平台存的trace数据把ES集群的磁盘占满了,存储成本高到财务找上门,真出事的时候,检索个关联trace还要等十几秒,根本等不及。
正确的打开方式真的没那么复杂。一开始别贪多,就挑三个最影响用户体验的核心接口:支付、订单创建、商品详情。先把这几个接口的上下游依赖全链路打通,核心接口采样率直接拉到100%,跑两周,把平时用户反馈最多的超时、报错场景全摸清楚。等这几个核心链路的常见问题解决得差不多了,再慢慢把核心链路的采样率降到10%,把那些非核心的内部服务、边缘接口逐步加进来。

这里必须提一个最容易被忽略的细节:跨线程调用的时候一定要做好trace上下文透传。不管是用线程池、异步注解还是消息队列,只要是跨线程、跨进程的调用,都要确保traceId能顺着请求流传下去,不然你搭的链路追踪就是个断的串,查问题的时候照样抓瞎。
别指望链路追踪能解决所有问题
说句实在话,这工具真不是万能的。
比如你业务逻辑本身的bug,比如计算优惠的时候多算了满减金额、库存扣减的时候没做幂等,这种链路追踪根本看不到——它只能帮你定位“请求在哪个环节花了多久、抛了什么错、走了哪条分支”,但业务逻辑对不对,还是得靠你自己的代码质量和测试覆盖度。还有本地开发调试的场景,你根本不需要上链路追踪,自己在IDE里打个断点就解决了,别上来就全链路联调,纯纯浪费时间。
更有意思的是,我碰到过不少团队,花了几十万买了商业版的链路追踪工具,结果连最基本的告警规则都没配——比如某个核心接口的P99延迟超过2s就发企业微信通知,结果每次都是用户打电话到客服投诉了,才有人想起来去平台上翻trace。那钱真的全白花了。
老周上周给我发消息,说现在他们团队排查支付超时的平均时间,从原来的4小时降到了15分钟。之前熬大夜查日志的日子,总算到头了。