0. 背景
前段时间线上一台服务器突然无法登录的情况。
1. 排查过程
从服务器运行日志发现,有个服务陷入了endless loop。每5秒出现一条告警打印。
1 | [56.35 I] [0 skynet] :A message from [ :00000000 ] to [ :0000002c ] maybe in an endless loop (version = 1431) |
进入skynet控制台,ping 2c这个地址也没有返回。初步判断该服务陷入某种死循环。
1 | skynet> ping 2c |
查看机器运行cpu并没有什么负载,没有一个cpu处于满载状态。说明不像陷入了循环。
1 | > top |
可以简要得出结论:
- 处于endless loop中,ping没有返回,说明3b这个服务的协程一直没有让出,怀疑死循环
- cpu又没有负载,特别是没有某一个核心处于高负载中,也就是cpu让出来了,说明协程不处于死循环中
至此可以推测3b服务陷入某种io中,让出了cpu却未让出lua协程。
2. 查看代码逻辑
此服务lua逻辑不多,c代码逻辑比较多。服务启动了一个用于RabbitMQ代理的AMQP客户端,用于跟一个RabbitMQ服务器进行数据交互。rabbitmq-c客户端是一个开源c库。https://github.com/alanxz/rabbitmq-c
此时可以怀疑网络IO的问题了
因为用的版本比较旧,怀疑是库的问题,且推测已经做了修复,先看了一眼库的issues。
- https://github.com/alanxz/rabbitmq-c/pull/557
- https://github.com/alanxz/rabbitmq-c/pull/614
- https://github.com/alanxz/rabbitmq-c/issues/380
- https://github.com/alanxz/rabbitmq-c/issues/788
3. 重现
线上偶发,出现频率很低,大约一年出现一次。推测是网络IO的问题,怀疑在某些极端网络条件下,出现丢包情况。导致rabbitmq-c获取数据介于某种中间状态。故,先设置mq连接的丢包率尝试复现。
1 | sudo iptables -A INPUT -p tcp --sport <port> -m statistic --mode random --probability 0.5 -j DROP |
- 丢包率太低(低于30%)无法复现
- 丢包率太高(高于70%)也不容易复现,会触发断线重连
- 丢包率适中的时候,大约两三个小时能触发一次。
进入gdb调试,获取堆栈
1 | (gdb) |
从堆栈可以看到:
- skynet的某一个工作线程(也就是出问题service)卡在了poll函数。
- 从参数timeout=-1可以看到,poll是没有超时时间的,直到读取到数据为止(或网络完全断开?)
4. 再次重现
由于无法查看 mq.so 的参数。看了默认情况下rabbitmq-c 的编译是release版本的。需要调整为debug版本重新编译。
1 | # rabbitmq-c/CMakeLists.txt:36 |
堆栈
1 | (gdb) bt |
参数
1 | (gdb) frame 1 |
5. 原因
超时设置的地方
#3 0x0000715e50235e66 in wait_frame_inner (state=0x715d47114380, decoded_frame=0x715e51bfa3d0, timeout=0x0) at librabbitmq/amqp_socket.c:846
https://github.com/alanxz/rabbitmq-c/blob/master/librabbitmq/amqp_socket.c#L778C16-L778C31
1 |
|
这里是在timeout_deadline和心跳超时取最小值。但是不凑巧这里都是UINT64_MAX。
5.1. 心跳超时设置
项目未开启心跳,原因是在select io模型下开启心跳有异常。
5.2. 作者修复
作者在该处确实有改动。但是这里代码没有区别,最终取到的都是UINT64_MAX。
作者的大量建议都是开启心跳超时检测来解决该问题。
6. 尝试开启心跳
其实已经使用poll模型了。select模型超时会coredump的问题可能并不会出现。
6.1. 仍然复现
1 | (gdb) thread 8 |
参数
1 | (gdb) frame 1 |
从参数可以看出来心跳超时仍然是UINT64_MAX。这是为什么呢。
因为重连登录的时候,心跳尚未赋值,仍然会在登录的时候出现类似的情况。
6.2. 修复
https://github.com/alanxz/rabbitmq-c/commit/7f92d532360dd254bf0484085e7a51b812cc578f
作者为登录添加了一个超时时间。
7. 如何修复
- 开启超时心跳;
- 登录增加超时参数。
1 | cd 3rd/rabbitmq-c |



