上个月记录了一下集群消息转发问题的现象:
假设 Client_A连接MQ_A,消费TOPIC_A。消息下发时,出现Client_A接收不到消息的情况。
- Client_A连接的MQ_A上只有这个Client_A一个消费者消费TOPIC_A上的消息。
- 查看TOPIC的订阅者信息,除了Client_A外,还可能出现该MQ转发到其他MQ上的虚拟消费者,表示发到这个TOPIC的消息需要被转发给其他MQ
- 集群内其他所有MQ上的TOPIC_A上查看订阅者,均未出现类似的虚拟消费者,表示消息不会被转发到MQ_A,所以Client_A无法收到消息。
- 重启Client,Client会自动飘到集群内其他的MQ上,此时可以正常消费。
- 指定MQ_A要求Client_A重启后连接到MQ_A,也可以正常消费。
最近开始尝试解决这个问题。一开始还是需要再深挖一下原因,于是我修改了一下DemandForwardBridgeSupport这个类,加了一些日志来观察集群消费者建立的过程。这个类的主要作用就是负责建立集群之间的订阅,当消费者连接到集群中某台MQ后,该台MQ会发送一个advisory message给集群内其他的MQ。
在修改源码增加日志后发现,当集群负载增加时,会出现advisory message没有被集群中部分MQ收到的现象。比如集群中8台MQ,当消费者建立连接到一台MQ时,集群中有4台MQ收到advisory message,有3台没有收到,可是生产者往往就连接在那没收到的3台MQ上(墨菲定律T_T),导致了集群转发的异常。
这个问题出现的场景一般是大量客户端与集群建立连接时。在官方JIRA上提了这个BUG,他们建议我升级到最新版本5.15试试,如果还出现他们再看= =
于是我今晚把一整套环境升级到5.15版本,然后再次尝试了一下。虽然看源码发现已经有了一些优化,但是问题仍然存在。
由于在DemanForwardBridgeSupport中采用的是监听器的方式(Listener),advisory message消息确认有从源头发出(集群中有MQ收到),那可能的原因应该是监听器所在的连接的异常,但是再往下挖水就太深了……
利用已有的能力,我暂时想到了几个方法:
- 将networkTTL设置为2。这样消息就可以支持被转发经过两个MQ Broker。也就是说Producer->A->B->C->Consumer。虽然中间多经过一层,但是如果能保证消息的可靠性,牺牲一点性能还是可以允许的。
- 修改源码,自己增加一个机制判断,如果advisory message被漏了,则建立一个多层的传输通道。
- 修改源码,每来一个consumer,则发多条advisory message,保证集群中所有MQ都收到。
- 提BUG给ACTIVEMQ JIRA。。。。
- 为MQ增加一个插件,插件访问一个共享文件系统或者缓存,通过遍历消费者和其所连接的MQ的方式来发现没有被正常建立的集群连接,发现后重启AGENT。
每一个都是耗时巨大的工程……