一个让我差点把键盘砸了的现场
三年前做一个分布式采集系统,十几个节点通过一条总线互相发数据。测试环境跑得好好的,一上现场就出问题:大约每半小时左右,系统整体吞吐量会突然掉到几乎为零,持续十几秒到半分钟,然后自己恢复。恢复后数据是补上来了,但时间戳全乱了,后端做时序对齐的模块直接罢工。
最开始的排查方向全是错的。我盯着应用层的日志看,发现那个时间段里每个节点都在疯狂打印“重传”记录。当时第一反应是:网络质量差,丢包了。于是换线、加屏蔽、降波特率,折腾了一周,现象依旧。
后来抓了一段总线上的原始波形才看明白——不是“丢包导致重传”,而是“重传导致更多丢包”。这是一个正反馈循环,一旦触发,整个信道就被重传报文淹没,真正的有效数据反而挤不进去。我把这个链条画在白板上,足足盯了十分钟,才意识到自己一直在治标。
这篇就聊聊这个因果链的完整梳理方法,以及现场到底该怎么断链。
先分清:是“报文丢了”还是“报文被丢了”
这两个说法听起来像文字游戏,但工程上区别巨大。
“报文丢了”通常指物理层或链路层没能把帧完整送达,比如信号衰减、干扰、碰撞。而“报文被丢了”是接收方收到了,但因为缓冲区满、校验失败、序号不连续等原因主动丢弃。
现场排查第一步,就是判断你面对的是哪一种。方法很土但有效:在发送端和接收端的链路层各挂一个计数器,分别记录“发出帧数”和“收到帧数”。注意,不是看应用层的收发计数,那里面掺杂了重传和去重逻辑,会掩盖真相。
如果发出和收到的差值约等于零,但应用层还在报重传,那问题出在接收方的处理路径上——报文到了,但没被正确消费。这时候你去换线、调天线,全是白费力气。</