RabbitMQ 匿名隊列斷開問題定位分析
1 問題現象
平台中,服務的信息交互通過RabbitMQ進行。在實際的使用中,發現系統啟動后,就會出現status 監控的mq connection斷開,服務實例無法接收web端的控制命令。
2 問題分析
經過查看日志信息,系統與mq斷開時有如下異常日志打印:
2018-06-20 19:19:44,335 [Thread-140618412050176] connection.py[line:1952] INFO Disconnected from RabbitMQ at 10.25.73.2:5672 (505): UNEXPECTED_FRAME - expected content header for class 60, got non content header frame instead 2018-06-20 19:19:44,336 [Thread-140618412050176]blocking_connection.py[line:472] ERROR Connection close detected; result=BlockingConnection__OnClosedArgs(connection=>, reason_code=505, reason_text='UNEXPECTED_FRAME - expected content header for class 60, got non content header frame instead') Unhandled exception in thread started by >>>> Traceback (most recent call last): File "/root/.local/lib/python3.5/site-packages/pika/adapters/blocking_connection.py", line 1780, in start_consuming self.connection.process_data_events(time_limit=None) File "/root/.local/lib/python3.5/site-packages/pika/adapters/blocking_connection.py", line 707, in process_data_events self._flush_output(common_terminator) File "/root/.local/lib/python3.5/site-packages/pika/adapters/blocking_connection.py", line 474, in _flush_output result.reason_text) pika.exceptions.ConnectionClosed: (505, 'UNEXPECTED_FRAME - expected content header for class 60, got non content header frame instead')
經過網上搜索,問題的原因為多線程向channel發送消息會導致此問題。
3 使用架構分析
系統架構如下:
Status實例與MQ有兩個channel:
- 服務控制:exchange的類型為fanout,用來接收web端的控制命令
- 狀態上報:channel定期向另外一個exchange發送消息上報服務的狀態
使用機制:
- 服務控制 channel創建后,啟動一個線程來消費channel的消息。
- 狀態上報 channel每隔15秒上報一次status信息
- 心跳機制,每隔30秒心跳線程會使用控制和狀態的channel發送心跳信息。
分析到這里,問題比較明了,服務控制channel存在多線程使用的情況。心跳線程和任務消費線程會同時使用同一個channel,導致出現UNEXPECTED_FRAME的錯誤,同時導致mq的connect斷開。
4 解決方案
接收消息的channel屬於長連接,不發送心跳也不會中斷。把接收消息的channel從heartbeat中去除,只使用發送消息的channel發送心跳。
5 同connect多個channel收發問題
5.1 問題描述
同一個MQ connect創建多個channel,有接收消息的,有發送消息的,這樣的使用場景,也會出現UNEXPECTED_FRAME錯誤,導致connection斷開連接。
5.2 解決方案
收發消息的channel分別用兩個connect創建,防止出現異常
