消息队列的使用场景
消息队列做为中间件在大型系统中使用非常广泛,典型的使用场景有四种:异步处理,应用解耦,流量削锋和消息通讯四个场景。
1.异步处理
异步处理是指一个业务操作,可以把某段耗时的逻辑异步执行来节省响应时间。
例如用户注册业务,需要把用户信息入库然后给用户发短信和邮件。传统的做法有两种:串行操作和并行操作。
- 串行操作

串行操作通常比较耗时,需要按照顺序把业务走完才给用户响应。
-
并行操作
并行操作.png
并行操作相对要好一些,因为发邮件和发短信并没有顺序要求,可以让它们同时执行,全部执行成功后给用户响应。这样的操作通常都会开启多个线程去做,这种做法不能做到高可靠。
-
消息队列异步处理
消息队列.png
使用消息队列可以做到快速响应和高可靠,注册业务只需要把用户数据写入到数据库并把消息成功投递到消息队列即可。消息队列来保证这个消息一定会执行成功,从而达到高可靠的目的。
2.应用解耦
应用解耦是指两个系统之间不进行强依赖,也就是上游系统不依赖下游系统的直接返回结果。这里的不依赖并不是指下游系统不管执行不执行成功都没有关系,而是上游系统只负责执行自己的业务并保证消息投递成功即可,下游系统来保证接收到消息并一定执行成功,两个系统相互解耦。
举个例子:有一个订单系统和一个库存系统

传统的做法通常是下单系统完成下单之后需要调用库存系统扣减库存,如果调用库存系统接口失败则下单也会失败。

使用消息队列后两个系统就相互解耦了,订单系统只要保证自己的业务执行完成并成功写入消息队列即可,并不实时依赖库存系统的返回结果。但这个需要保证订单系统执行完业务后一定要投递消息成功,库存系统订阅到消息后一定要消费成功。如何做到两个保证后面会讲到。
3.削峰填谷
削峰填谷是指有大量业务处理不过来的时候可以把这些请求缓存起来逐步处理,或者是将短暂一段时间的业务挤压放在后面非业务高峰期再执行。
比较多的应用场景就是秒杀活动:

秒杀业务通常会在一个短暂的时间内产生大量的请求,服务器接收到消息先把请求写入到消息队列,超过消息队列长度限制则直接返回错误消息给用户。写入到消息队列的消息逐步处理,这样就不会应用或者数据库崩溃。
4.消息通讯
消息通讯是指消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。

客户端A和客户端B可以是点对点的也可以是,一对多的。消息队列具有低延迟,A和B可以相互订阅同一个MQ,互相订阅对方发送的消息。
主流消息队列对比
目前在国内主流的消息队有RabbitMQ、ActiveMQ 、 RocketMQ、Kafka。下面是网络上的一张对比表格可以提供参考。
对比内容 | RabbitMQ | ActiveMQ | RocketMQ | Kafka |
---|---|---|---|---|
所属机构/公司 | GoPivotal | Apache | Alibaba | Apache |
是否开源 | 开源 | 开源 | 开源 | 开源 |
技术文档 | 多 | 多 | 少 | 中等 |
集群 | 支持简单集群 | 支持简单集群 | 支持高级集群 | 支持高级集群 |
负载均衡 | 支持 | 支持 | 支持 | 支持 |
客户端支持语言 | 多种 | 多种 | 多种 | 多种 |
开发语言 | ErLang | Java | Java | Scala && Java |
批量操作 | 不支持 | 支持 | 支持 | 支持 |
有序性支持 | 单客户端有序 | 支持 | 支持 | 支持 |
管理界面 | 较好 | 一般 | 命令行界面 | 命令行界面 |
消息延时 | 微秒级 | 微秒级 | 毫秒级 | 毫秒级 |
事务支持 | 不支持 | 支持 | 支持 | 不支持 |
社区活跃度 | 高 | 高 | 中 | 高 |
商业支持 | 无 | 无 | 阿里云 | 无 |
协议支持 | AMQP等多种 | AMQP等多种 | 自定义协议 | 自有协议,HTTP |
消息丢失概率 | 低 | 低 | 无 | 无 |
可用性 | 主从 | 主从 | 分布式 | 分布式 |
单机吞吐量 | 万级 | 万级 | 十万级 | 十万级 |
部署难度 | 低 | 低 | 低 | 中 |
消息存储 | 内存、磁盘 支持少量堆积 | 内存、磁盘、数据库 支持少量堆积 | 磁盘 支持大量堆积 | 内存、磁盘、数据库 支持大量堆积 |
消费方式 | push/pull | push/pull | push/pull | pull |
ActiveMQ
- 非常成熟,功能强大,在早些年业内大量的公司以及项目中都有应用
- 现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ 5.x维护越来越少,几个月才发布一个版本
- 主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用
RabbitMQ
- erlang语言开发,性能极其好,延时很低;
- 社区相对比较活跃,几乎每个月都发布几个版本分
- 比较适合做业务,在国内一些互联网公司近几年用rabbitmq也比较多一些,但是问题也是显而易见的,RabbitMQ确实吞吐量会低一些,这是因为他做的实现机制比较重。
- erlang开发,很难去看懂源码,基本职能依赖于开源社区的快速维护和修复bug。
RocketMQ
- 接口简单易用,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是ok的,还可以支撑大规模的topic数量,支持复杂MQ业务场景
- 而且一个很大的优势在于,源码是java,我们可以自己阅读源码,定制自己公司的MQ,可以掌控
- 社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码
Kafka
- kafka的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展
- 同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量
- Kafka支持复制,支持事务,对消息的重复、丢失、错误没有严格要求,也就说kafka有可能会丢消息,对数据一致性要求比较高的业务不太适合使用
网友评论