消息队列是分布式系统中一个十分重要的概念,尤其是目前微服务(Micro-service)架构兴起,有一些微服务架构是使用消息队列来实现的。在现在的系统设计中,消息队列越来越频繁地被使用。
消息队列是生产值消费者模式的一个典型应用,在高并发多线程的设计中,我们通过消息队列来解耦(de-couple)生产者和消费者,以达到流量控制、业务解耦等需求,实现异步通信。所以一般消息队列会涉及到以下概念:
- 生产者(Producer):生产者发布消息;
- 消费者(Consumer):消费者接受处理生产者发布的消息;
- 中介(Broker):接受生产者发出的消息,存储和并转发消息给消费者。broker一般是消息队列本身,而生产者和消费者是使用消息队列的应用。
常见的消息队列有RabbitMQ、RocketMQ、Kafka、ActiveMQ等。
生产者发布消息到队列,消费者从读取队列里面的消息进行处理。对于单个消息来说,不可重复使用,只能有一个消费者能处理该消息。
生产者发布消息到消息队列,一般叫做topic,消费者向消息队列订阅不同的topic,所有订阅该topic的消费者都能得到该消息。
优点
总结起来就是四个词:解耦,提速,广播,削峰。实现异步通信,提升系统性能。具体参考下面使用场景。
缺点
增加系统复杂性(another layer of complexity),万一消息队列服务出错,可能导致系统瘫痪。
大型分布式系统通常会使用消息队列,下面是一些常用的使用场景:
-
异步处理:当不同模块之间允许异步处理(不需要等待并立即获得结果)可以使用消息队列,比如用户下单之后,需要发送确认短信,完成支付,提醒仓库发货等等,这种情况下可把系统分成下单服务,短信服务和配送服务,用户下单后将事件写入消息队列然后马上返回,其他服务从消息队列读取订单,慢慢做其他处理,不影响用户体验。
-
流量控制(削峰):比如抢票,如果预定系统和支付系统强耦合,当某个时段大量并发用户抢票的时候,会给支付系统带来很大压力,支付系统一般吞吐量比其他系统小,通过消息队列,可以把订票的订单放在队列里(如果队列过长,可以直接返回错误给用户让用户重试),支付系统以固定的速率读取消息队列订单,保证稳定。
总而言之,就是当需要提升系统性能时,检查系统是否存在可以使用异步操作的逻辑,如果存在的话便可以使用消息队列。
消息队列主要分为两种,一种是log-based的,比如Kafka,一种是Queue(FIFO)-based的,比如 RabbitMQ, ActiveMQ 等。它们最大的区别是分发方式不同,log-based的消息队列,
log-based的消息队列的特性:
- 消息按照先后顺序被处理完,同一个partition里面保证有序。
- 高吞吐,log-based的queue直接把新消息加到文件末尾,吞吐十分快
- 可以保存过去的记录,log就是过去消息的记录,可以replay
- 一个consumer监听一个partition的消息,如果某一条消息需要花大量时间处理,后面的消息都会被block
Queue-based的消息队列的特性:
- 不能保证有序,比如当前队列有a,b两条消息,a分给consumer1, b分给consumer2,有可能b先被处理完。
- 存在某些消息需要花大量时间处理的情况,可以增加consumer的数量同时处理剩下的消息,不会被block
- 消息被处理后就会删除