聊聊消息中间件的关键特性和问题总结


聊聊消息中间件的关键特性和问题总结

文章插图
 
今天闲聊下消息中间件的一些关键特性,对于消息中间件基础知识,包括各种开源消息中间件的比较选型文章,网上已经有很多,在这里就不再重复进行描述 。
因此这篇文章仅仅选择一些消息中间件的一些关键特性和实践中常遇到的问题进行总结 。
同时兼顾消息发布订阅和队列
聊聊消息中间件的关键特性和问题总结

文章插图
【聊聊消息中间件的关键特性和问题总结】点对点队列模式消息模式

聊聊消息中间件的关键特性和问题总结

文章插图
发布订阅模型Topic消息模型
消息中间件有一个关键能力,即1对多的消息发布订阅模式 。因此对于消息中间件也常说两个能力,一个是Queue消息队列能力,一个是Topiic消息主题能力 。对于消息Topic即消息主题模式,支持消息的发布订阅 。
对于Queue模式消息被消费掉即从队列中清除,不管是哪个消息端消费掉 。对于Topic模式,单个订阅端获取到消息,消息并不会清除,而是需要所有订阅端全部消费掉消息 。
那么我们来举一个最简单的场景,即ERP系统需要将消息分发给CRM和SRM两个系统 。因此启用了消息发布模式,建立了一个消息主题,比如会计科目分发消息 。同时SRM和CRM系统是消息的订阅方,因此在订阅端写了相应的监听程序来订阅消息 。如下:
聊聊消息中间件的关键特性和问题总结

文章插图
 
但是CRM和SRM都是集群部署,每个应用都有三个集群节点,每个节点在启动的时候都会对消息主题进行订阅和监控 。
那么当ERP分发会计科目的时候,如果常规模式就变成了该消息会被6个订阅端全部获取到 。这个时候对于CRM系统中集群三个点,获取到三次消息显然是重复的 。因此我们需要对于订阅端,在一个集群分组内部应该只要有一个节点获取到消息,消息就应该清除掉 。但是在不同的集群分组间,仍然应该是Topic模式 。
因此在消息中间件实现中,需要有一个针对集群节点的进一步分组能力,比如上面的CRM和SRM应该分为两个组,也就是常说的ClientID 。有了ClientID分组,就可以实现组间的Topic能力,而组内启用Queue模式 。
不同的消息中间件在这块的实现思路基本一致,即都需要有一个ClientID分组的概念 。
比如在ActiveMQ中实现了虚拟Topic的功能 。使用起来非常简单 。对于消息发布者来说,就是一个正常的Topic,名称以VirtualTopic.开头 。例如VirtualTopic.TEST 。
对于消息接收端来说,是个队列,不同应用里使用不同的前缀作为队列的名称,即可表明自己的身份即可实现消费端应用分组 。例如Consumer.A.VirtualTopic.TEST,说明它是名称为A的消费端,同理Consumer.B.VirtualTopic.TEST说明是一个名称为B的客户端 。
可以在同一个应用里使用多个consumer消费此queue,则可以实现上面两个功能 。又因为不同应用使用的queue名称不同(前缀不同),所以不同的应用中都可以接收到全部的消息 。每个客户端相当于一个持久订阅者,而且这个客户端可以使用多个消费者共同来承担消费任务 。
同时兼顾消息发布订阅和路由进一步来谈消息发布订阅,还是基于前面的场景,ERP分发会计科目消息,当前有SRM和CRM两个订阅端 。但是仍然会出现一些特殊的场景:
比如CRM接收到消息,但是自己处理出现问题导致消息丢失,需要让ERP系统重发消息 。其次就是某些会计科目可能只有SRM系统需要使用,需要定向只发送给SRM系统 。那么在这种情况下一个Topic主题往往并不能支持该需求 。当然对于不同的Route规则可以建立不同的Topic,但是如果路由规则复杂,这样会建立出大量的Topic本身也不现实 。
聊聊消息中间件的关键特性和问题总结

文章插图
 
而对于这种常见,类似主流的基于JMS的消息中间件往往并没有topic+路由规则的消息投递能力,对于这种情况只能够单独新实现接口来进行处理 。或者是消息仍然按传统规则进行分发,对于订阅端拿到消息如果确实自己不需要或已经存在,就自己丢弃掉 。
而对于RabbitMQ,可以看到专门有一个Topic Exchange模式 。Topic Exchange是根据routing key和Exchange的类型将message发送到一个或者多个Queue中,可以通过它来实现pub/sub模式,即发布订阅 。类似下图:
聊聊消息中间件的关键特性和问题总结


推荐阅读