线上基础服务为了避免单点问题,一般在其搭建之时都会建立集群以避免机器宕机等极端情况发生时业务能不受影响。比如Redis 3.0之后集群的按照一致性哈希的方式将key-value的存储分布在各个机器作为master节点,每个master节点还要增加额外的slave节点来避免单点问题。
同样的,RabbitMQ也提供了节点集群的方式。RabbitMQ集群的节点是不区分master和slave的,各个节点互为镜像。但最近发生了一起线上事故,其中一台消息队列节点挂掉了,一时无法恢复,结果导致了线上所有依赖消息队列的服务都无法正常工作。
明明配置了集群,为什么一台节点挂掉,其他节点不能提供队列服务呢?从MQ的日志中发现了下面的情况。
=ERROR REPORT====9-Mar-2018::11:51:12===
**Node rabbit@d2 not responding **
**Removing(timedout) connection **
=INFO REPORT====9-Mar-2018::11:51:12===
rabbit on node rabbit@d2 down
=INFO REPORT====9-Mar-2018::11:51:12===
node rabbit@d2 down: net_tick_timeout
=WARNING REPORT====9-Mar-2018::11:51:12===
closing AMQP connection <0.23105.46>(10.115.33.48:47240->10.115.33.21:5672):
connection_closed_abruptly
=WARNING REPORT====9-Mar-2018::11:51:12===
closing AMQP connection <0.23251.46>(10.115.33.48:47357->10.115.33.21:5672):
connection_closed_abruptly
=INFO REPORT====9-Mar-2018::11:51:15===
Mirrored queue 'distribute_queue'in vhost 'web':Slave saw deaths of mirrors
=INFO REPORT====9-Mar-2018::11:51:15===
Mirrored queue 'distribute_queue'in vhost 'web':Promoting slave to master
=INFO REPORT====9-Mar-2018::11:51:15===
Mirrored queue 'distribute_queue'in vhost 'web':Synchronising:46 messages to synchronise
=INFO REPORT====9-Mar-2018::11:51:15===
Statistics database started.
=INFO REPORT====9-Mar-2018::11:51:15===
Mirrored queue 'distribute_queue'in vhost 'web':Synchronising: all slaves already synced
=ERROR REPORT====9-Mar-2018::11:51:15===
connection <0.22397.46>, channel 2- soft error:
{amqp_error,not_found,
"home node 'rabbit@d2' of durable queue 'task_queue' in vhost 'web' is down or inaccessible",
'queue.declare'}
从日志可以看出,distribute_queue可以正常提供服务,但是task_queue则不能访问。原来之前已经对distribute_queue做过额外的队列高可用配置,所有未做此配置的队列,当所在节点挂掉时当不能提供服务。
因此,再对RabbitMQ做集群时,不光要做节点集群,还要将所有队列的高可用配置都做了,才能确保不出现单点问题。这和一般集群的搭建方式有很大不同,需要注意。