消息队列理论
作用
- 流量削峰:削峰填谷
- 异步处理:将同步请求转换为异步,并且请求放入队列后,可以有多个消费者消费,提升整体的响应时间
- 服务解耦:服务方只需要把消息放入消息队列,下游谁需要就由谁订阅,下游系统的增减,不影响服务方。(openStack整个服务间的交互全都采用mq,默认rabbitMq)
基本概念
两种模型
- 队列模型(Quene):一个队列可以有多个生产者和消费者。但消费者之间是竞争关系,每条消息只能被一个消费者所消费。RabbitMq采用队列的方式解决一条消息被多个消费者接收,是通过Exchange模块将消息发送至多个队列
- 主题模型(Topic,发布/订阅模型):生产者将消息发往一个topic主题中,所有订阅了这个topic的订阅者都能消费这条消息。RabbitMq采用队列模型,RocketMq和kafka采用发布订阅模型,activeMq支持两种模型
producer/broker/consumer
- 为了提高并发度,Topic模式往往还会引入队列或者分区的概念,即消息发往Topic下的某个队列或分区中。RocketMq叫队列,kafka中叫分区。如某个Topic有5个队列,那么该主题的并发度就提高为5,可以有五个消费者并行消费该主题的消息。一般可以采用轮询或者hash取余的方式将消息分配到不同的队列当中
- 为了提高消费者的并发度,消费者通常都有消费者组(consumer group)的概念,消费者都是属于某个消费者组的。一个消息会发往多个订阅了这个topic的消费者组。这个消息实际上是写到了topic下的某个队列中,消费者组中的某个消费者对应消费一个队列的消息,同一消费者组下的应用,可以认为是同一应用的集群,一个topic下的一个队列,只会对应消费组下的一个实例(或一个线程),如果实例数大于队列数,则有的实例是不会分配消息的。
- 物理上一条消息处理副本拷贝以外,一条消息在broker中只会有一份,每个消费组有自己的消费点位(offset)来标识消费到的位置。offset之前的消息是被这个消费组消费过的,这个offset是队列级的,每个消费组都会维护订阅的topic下的每个队列的offset
怎么保证消息不丢失
- 生产者:可靠消息,本地消息表与本地事务同一个线程,消息表记录消息发送状态,失败定时重试
- broker:刷盘后,或者至少有两个节点都写入成功后再返回生产者消息发送成功
- 消费者:业务处理完成后再更新offset,为缩短时间可批量处理,或先做消息持久化再异步处理
处理重复消息
幂等机制: 版本号、业务流水号、业务状态等
如何保证消息有序性
- 全局有序: 一个topic下一个队列,性能低,实际诉求少。
- 部分有序: 一个topic下多个队列,可以按照一定的规则,把需要局部保持顺序的消息路由到一个队列,由一个消费者消费
处理消息堆积
原因: 生产者的生产速率与消费者的消费速率不匹配 优化:1. 优化消费者的处理性能;2. 增加topic队列和消费者数量,即水平扩容,注意一个topic下的队列只会分配给一个消费者。
rocketMq消息消费
- 消费者和broker的消息获取,有推拉两种模式,activeMq用推的模式。RocketMq和kafka均采用拉的模式,通过长轮询的方式,通过消费者等待消息,当有消息时broker会直接返回消息,如果没有消息,则会采用延迟处理的方式,并且为了保证消息实时性,当有新消息到来时,会及时返回消息
RocketMq事务消息
- rocketmq事务消息事务开始时小发起一个半消息,本地事务执行后,根据执行结果发送消息的提交或者回滚,半消息对消费者是不可见的,消息提交后才放入正常队列供消费者消费。
- 生产者发送的提交或回滚有可能会失败,因此需要producer暴露一个接口,供broker定时查询事务状态。
RocketMq
原理
参考文章
特点
- 吞吐量高:单机吞吐量可达十万级
- 可用性高:分布式架构
- 消息可靠性高:经过参数优化配置,可以做到消息零丢失
- 功能较为完善,分布式架构易于扩展
- 支持10亿级别的消息堆积,不会因为堆积导致性能下降
- 稳定性高,经过阿里双11考验
- Java语言实现
部署
常见消息队列对比
|