对于消息队列,应该都不陌生。市场上很多类型的消息队列,五花八门。选择自己适合场景的消息队列并不容易。如何选择呢?这篇文章不会很简单的对比所有的队列的优劣,会从消息队列的本身的方式与优缺点,让大家觉得需不需要使用消息队列。
消息队列的架构模式
消息代理定义:消息代理是一种架构模式,用于消息验证、变换、路由。调节应用程序的通信,极小化互相感知(依赖),有效实现解耦合。例如,消息代理可以管理一个工作负荷队列或消息队列,用于多个接收者,提供可靠存储、保证消息分发、以及事务管理。来自维基百科(https://zh.wikipedia.org/wiki/%E6%B6%88%E6%81%AF%E4%BB%A3%E7%90%86)。
简单的来说,消息代理是消息队列的一种架构模式,一般消息队列都会使用。包括:ActiveMQ、Kafka、RocketMQ、RabbitMQ等。
消息代理的方式
消息代理的方式有:直接点对点方式、发布订阅、定制路由规则。
直接点对点方式
这种方式中,生产者发送(放入)消息,消费者直接消费消息。在消息代理的角度,路由由队列名称定位,生产者与消费者只需要知道队列名称即可。如下图,展示了一个生产者放入消息队列,一个消费者负责消费。
当然,如果流量大,则可以多个生产者与消费者。由于都使用同一消息队列名称,所以可以在生产与消费应用程序端添加多个实例,提高处理速度。如下图,生产者A、B都负责放入同一个队列,而消费者A、B负责争抢同一个队列,谁争抢到谁先消费当前消息。
这种方式的应用场景有包括:邮件、短信、视频处理、图片处理、与第三方应用对接等。
发布订阅
发布订阅的方式很常见,也最常使用。这种方式在也有生产者与消费者,生产者把消息放入消息队列的某个主题中,如果想要获取此消息则订阅此消息即可。订阅方即消费者,可以有多个消费者订阅同一个主题。这种方式与上一种区别在于,当生产者放入一条消息ABC到主题X中,如果由两个消费者订阅了主题X,那么此消费者们都会收到消息ABC。如果有n个消费者订阅了主题X,那么会有n个消费者消费此消息。如下图所示。
这种方式在队列中是如何处理的呢?生产者把消息ABC放入主题X中后,消息队列知道有两个消费者订阅了主题X。那么消息队列会把消息ABC复制多一份,即一共两份。然后各自把消息发送到各自的订阅者中。如下图显示。
发布订阅模式的应用场景有许多,如使需求是一个消息需要分批处理则会使用此方式。例如下单成功后的统计与消息推送。即商城有下单需求,下完单后需要短信消息推送与统计下单信息。
发布订阅的好处在于消费端扩展性非常强。订阅者可以不断地增加,如上面的例子如果再加一个发送email的动作,那么不影响原有的基础上,增加email消费者C。
定制路由方式
这种方式是队列可以定制路由,通过定制的路由决定消息如何路由到队列中。
相对于上面2种方式,定制路由方式较少用到,但是也会有场景使用到。并不是所有队列都支持此方式。定制路由能增强消费者订阅消息的灵活性,从而实现系统可以采用配置实现新需求。
消息协议有三种AMQP、STOMP、JMS。这里不详细介绍。
消息队列的优势
优势有异步处理、削峰、提高可用性、解耦。
异步处理
异步处理是消息队列使用得最多的方式之一。异步处理,可以是线程,可以是硬件,也可以是队列。这里当然说的是队列。队列异步处理专门用于耗时处理等资源密集型工作,任何缓慢的操作都可以考虑使用消息队列来做异步处理。
异步处理的应用场景有:发短信、发eamil、图片处理、视频处理、生成excel等。
削峰
削峰提高了应用程序的可用性。使程序能平稳运行。削峰也叫流量削峰,旨在流量超过程序处理时让流量平稳地在应用程序中处理。在队列的削峰处理中,生产者将所有的流量进入队列,队列的消费者一个一个地平缓进行处理,多余的消息在队列中。为系统的可能性提供了保障,避免了过大流量进入而影响到系统宕机等意外情况发送。
即使系统无法立即处理所有请求也不会崩溃。峰值过后,系统很快自动回复到平常状态。如下图(来自网络)。
提高可用性
提高可用性指的是提高应用程序的可用性。在消息队列里有生产者与消费者,他们之间无需知道对方的位置在哪里,只需知道消息的协议、消息类型格式即可。所以,当我们的生产者部署的应用与消费者部署的应用不相同时,可提高可用性。即消费者所在应用宕机或生产者所在应用宕机,都不会影响对方,应用也不会崩毁。当你部署多个生产者或者消费者的应用时,其中一台宕机也不会影响整个应用程序,只会影响吞吐量而已。
解耦
这里的解耦是指隔离了队列的生产者与消费者。
有如下场景,用户注册成功后需要发送email验证码验证邮箱的真实性。这里用户注册提供一个API到界面层,此API首先生成用户信息,然后调用队列生产者去告诉队列我需要发送email。最后消费者端的程序接收到消息并且发送email。这里消费者与生产者隔离,解耦了生产者与消费者,生成者只需要把消息放入队列,消费者只需要等待通知,如有通知则消费并发送email。
消息队列的挑战与缺点
消息队列好用,但是也带来了挑战。其一是消息队列的异步性为程序增加了难度与时间。
以前同步处理一条龙处理下去,现在异步必须分开生产者与消费者。从而增加了开发的难度与时间。
其二是消息顺序性的保证。消息顺序性保证是一个大课题,很多消息队列内部已经支持。在应用程序设计上,尽量避免对消息顺序性的要求。
其三是幂等性。很多需求都需要消息队列重试,所以有些队列重试时要保证幂等性。幂等性可在应用程序上控制,保证队列消费多次而处理一次。
总结
消息队列内部实现极其复杂,市场上不管是开源的还是程序的应用,都带给我们及其的便利。
我们需不需要使用队列,考虑是否需要进行异步处理、削峰、提高程序可用性、解耦程序。如果只考虑异步处理,则用其它方式也可以实现,队列只不过是其一方法。
队列带给我们很多好处,但也需要考虑其带给我们的挑战,挑战包括增加难度与开发时间、避免消息有顺序依赖、幂等性。
所以我们在考虑使用队列前,做好所有的研究看是否值得。一般队列的好处是远远大于缺点的。
可以关注本人的公众号,多年经验的原创文章共享给大家。