问题环境
openstack newton版本
rabbitmq 3.6.5
pika 0.10.0
问题现象
rabbimq日志报错信息:”Missed heartbeats from client, timeout: 60s”
问题分析
- rabbitmq使用心跳机制来保持连接,在正常场景下,客户端通过发送心跳包来告知服务端自己存活。如果服务端连续两次(间隔heartbeat/2)发送心跳客户端均无回应,服务端会断开与客户端的连接,这也就是rabbitmq日志报错的原因。
- 对客户端来说,需要在心跳超时时间内向服务端发送信息以完成心跳,然而python与rabbitmq的通讯模块pika.BlockingConnection不支持在执行回调任务时,并行发送心跳包,一旦耗时任务超过heartbeat timeout(默认60s),服务端就会认为连接丢失而主动断开连接,客户端只在完成耗时任务继续使用这个队列的时候才会发现已断开。
相关配置
服务端配置,/etc/rabbitmq/rabbitmq.conf
# heartbeat: 心跳超时判定时间(s)
{rabbit,{heartbeat, 60}}
客户端配置
import pika
# heartbeat_interval: 心跳超时判定时间
parameters = pika.ConnectionParameters('host', 'port', heartbeat_interval=10)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
最终heartbeat选取原则:rabbitmq建立连接时会从服务端和客户端的配置中挑选最小值作为该连接的心跳超时时间。
解决方案1
rabbitmq在3.5.5以前的版本heartbeat默认为580s,3.5.5之后才改为60s,这样就就出现了很多这样问题。
因此,可考虑修改heartbeat,改为200s甚至更大的值,这会很大程度上减少该问题发生。
解决方案2
方案1虽然可以很大程度避免问题出现,但总归不能完全消除。
因此可以考虑改用tcp的keepalive机制:
- rabbitmq服务端关闭heartbeat机制,并启用tcp keepalive
# heartbeat: 设置0,代表关闭心跳服务
# tcp_listen_options.keepalive: 设置true打开tcp keepalive
{rabbit, [
{heartbeat, 0},
{tcp_listen_options,
[binary,
{packet, raw},
{reuseaddr, true},
{backlog, 128},
{nodelay, true},
{linger, {true, 0}},
{exit_on_close, false},
{keepalive, true}]
}}
- rabbitmq客户端关闭heartbeat机制
# 修改/etc/neutron/neutron.conf,/etc/nova/nova.conf,
# /etc/glance/glance-api.conf,/etc/cinder/cinder.conf,
# 添加:
[oslo_messaging_rabbit]
heartbeat_timeout_threshold=0
3 .配置linux系统的tcp keepalive参数,由传输层做tcp连接保活检测,效率更高,且与应用层服务互不干扰,但灵活性差(内核级别配置,全局生效)。配置方式可参考:https://blog.csdn.net/dackchen/article/details/97535297
主要是三个内核配置项,一个参考值:
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 5
参考链接:
https://www.cnblogs.com/mingao/p/10626297.html
http://doc.okbase.net/quqi99/archive/230499.html
https://github.com/pika/pika/pull/956