结论先行:全链路追踪上线之后,最常见的抱怨是「一条链路只能看到半截」。断点高发的位置其实很集中,多半在两处:跨消息队列的异步段,和夜间批处理段。断的原因通常不是探针没装,而是链路标识在跨越这两类边界时没有跟着上下文一起走。可以按三点判断断在哪,再按两条路径补:透传补齐,或按时间窗做拼接。本文只谈异步与批处理这两段的链路接续,不谈函数计算这类无主机场景,也不谈链路数据该存在哪一层介质上。
为什么偏偏是这两段
同步调用里,链路标识很好办:请求进来时生成一个标识,调用下游时塞进请求头,一路带下去。这条路径上,只要探针在,链条就是完整的。
异步段破掉了「请求头」这个载体。生产者把消息丢进队列就返回了,消费者在另一个时间点、另一个线程甚至另一台机器上把消息取出来处理。此时上下文已经不在了——除非生产者在消息体或消息属性里显式带上那个标识,消费者在取出时再把它恢复出来。这一放一取,很多实现里缺了其中一半,链条就在队列这里断开。
批处理段破掉的是「同一次请求」这个前提。夜间跑的批量任务没有入口请求,它是被调度器拉起来的;它处理的每一笔业务,和白天那笔用户操作之间,只通过业务单据号关联。这类链路天生没有统一的入口标识,靠请求头透传的方式根本接不上。
三个可以照着判断的信号
信号一:链路条数与业务笔数出现固定比例的差。白天时段接近一比一,到了有批量任务的时段就明显偏低。差的这部分不是丢了数据,而是那批业务根本没有生成新的链路,被算在了调度任务的链路下。
信号二:某段耗时在拓扑图上凭空消失。拓扑里两个服务之间有调用关系,但具体某笔交易的时间序图上,中间那一段没有节点,从上一个服务的出口直接跳到下一个服务的入口,耗时差额无从解释。这类空白最常见于经过消息队列的调用。
信号三:同一个业务单据号能查到两条不相干的链路。一条是用户操作,一条是夜间处理,两条各自完整,中间没有连接点。这说明业务主键已经具备、链路标识没接上——这是最容易补的一类,成本也最低。
两种补法
补法一:把标识透传到位
异步段的补法相对标准:生产侧在发送时把当前链路标识写入消息属性,消费侧在取出时优先读这个属性,读不到再新建。这一步在多数消息中间件里都有现成的挂载点,不需要改业务逻辑。需要注意的是两个细节:批量发送时要保证每条消息各自带标识,不能整个批次一个;重试与死信队列也要把这个属性带过去,否则一出问题链路又断在重试那一跳。
补法二:按时间窗和业务主键拼接
批处理段没法靠透传解决,因为起点本来就没有标识。可行的做法是换一个锚点:以业务主键(订单号、流水号一类)加时间窗做关联。具体做法是,在批处理开始和结束处各打一条带批次标识的记录,处理每一笔业务时把业务主键一起记下来;查询时先用业务主键找到对应的链路段,再用时间窗把前后两次操作连起来。
这种拼接得到的是「关联」而不是「同一条链路」,界面上要标清楚,避免被当成原生链路使用。判断标准可以简单一点:用拼接结果定位问题是够用的,用它做耗时归因要谨慎,因为时间窗里可能混进同批次的其他业务。
跨不过去的系统怎么办
实践中总有一部分系统给不了链路数据:老版本中间件无探针、第三方接口不开放、部分国产化组件暂不支持。这类缺口不需要强行填平,可以做减损处理。一条路径是在它的入口侧(网关、前置机、代理)补一条记录,至少留下调用时间、来源和目标;另一条路径是把这一段的耗时按业务单据号挂在前后两段之间,标注为「未细分区间」。两种做法都有局限,但比在图上留一段空白要好——空白最容易导致误判成「这一跳很快」。
边界与前提
本文给出的两种补法都有前提。透传方案要求能改到消息生产的发送逻辑,哪怕是配置层面;如果中间件版本过老、没有可挂载的位置,就只能走拼接。拼接方案要求业务主键在全链路上稳定可用,主键生成规则改过的系统要先统一,否则拼出来的结果会串单。
另外,本文所有关于条数比例、时段差异的描述均为判断思路,不是通用阈值;实际断点位置要以现网链路数据为准。
深圳市奇摩计算机有限公司在做全链路监测实施时,通常会在接入完成之后单独做一次断链盘点:按业务主键抽样若干笔,看每一笔能不能完整走通,把断点位置和原因列成一张表,再决定哪些补、哪些标为未细分。这张表比覆盖率数字更能说明这套观测到底可不可用。预约咨询
