最近,我們有些在阿里雲上的應用總是有客戶端出現異常和信息推送不及時的情況,檢查mq日志,發現高峰期不停的有心跳超時,如下:
=ERROR REPORT==== 21-Dec-2016::12:38:00 ===
closing AMQP connection <0.909.1> (125.120.15.131:5060 -> 120.27.140.42:5672):
Missed heartbeats from client, timeout: 10s
=ERROR REPORT==== 21-Dec-2016::12:38:20 ===
closing AMQP connection <0.898.1> (125.120.15.131:5057 -> 120.27.140.42:5672):
Missed heartbeats from client, timeout: 10s
連接的心跳值可通過控制台看到,如下:
特研究了相關機制,默認情況下,在3.5.5版本之前,rabbitmq設置的默認與客戶端心跳時間為580秒,之后為60秒(如果時間間隔配置為0,則表示不啟用heartbeat檢測),兩者時間會每隔timeout / 2 進行一次心跳互通。
啟用心跳檢測后,rabbitmq會為每個tcp連接創建兩個進程用於心跳檢測(這可以通過rabbitmq.log看到每個客戶端確實有兩個連接,關閉的時候也是成對的方式),一個進程定時檢測tcp連接上是否有數據發送(這里的發送是指rabbitmq發送數據給客戶端),如果一段時間內沒有數據發送給客戶端,則發送一個心跳包給客戶端,然后循環進行下一次檢測;另一個進程定時檢測tcp連接上是否有數據的接收,如果一段時間內沒有收到任何數據,則判定為心跳超時,最終會關閉tcp連接。另外,rabbitmq的流量控制機制可能會暫停heartbeat檢測。
服務端可在可在配置文件rabbitmq.config中增加配置項{heartbeat,Timeout}進行配置,其中Timeout指定時間間隔,單位為秒。客戶端java則為:
ConnectionFactory cf = new ConnectionFactory(); // set the heartbeat timeout to 60 seconds cf.setRequestedHeartbeat(60);
.net則為
var cf = new ConnectionFactory(); // set the heartbeat timeout to 60 seconds cf.RequestedHeartbeat = 60;
如果超過2次心跳無響應,則會認為對方不可到達並關閉連接。此時,客戶端通常需要重新連接。具體視客戶端的不同而不同。
具體可見http://www.rabbitmq.com/heartbeats.html。
在我們的環境中,應該來說負載並不是特別的高,ping 1k的延時基本上都在20ms以內,照理設置10ms的心跳間隔足以,為什么還是會出現,還需要trace_on看下詳細的網絡包情況。