可能的一些作用:
- 非核心逻辑异步化,追求高性能
- 解除耦合,Event Driven 事件驱动设计
- 实现广播
- 削峰填谷,把峰值流量缓冲下来,后面慢慢处理
具体可以用于:
- 分布式事务,单方生产,多个消费业务逻辑
- 数据复制:通过消息队列,将数据复制到多个目的地(多维度数据表、ES、Hadoop、搜索等)
- 日志同步:多个app生产日志并放入队列,然后消费队列完成日志的离线与实时处理
- 延迟队列:可靠的延迟队列,分布式环境定时器
- 广播通知:Cache失效通知
消息队列的缺点
系统可用性降低:系统引入的外部依赖越多,越容易挂掉,本来你就是A系统调用BCD三个系统的接口就好了,人ABCD四个系统好好的,没啥问题,你偏加个MQ进来,万一MQ挂了咋整?MQ挂了,整套系统崩溃了,你不就完了么。
系统复杂性提高:硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已
一致性问题:A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。
主流消息队列对比
特性 | ActiveMQ | RabbitMQ | RocketMQ | kafka |
---|---|---|---|---|
单机吞吐量 | 万级,吞吐量比RocketMQ和Kafka要低了1个数量级 | 同ActiveMQ | 10万级,可支撑高吞吐 | 10w量级 |
topic数量对吞吐量的影响 | topic可达几百几千,吞吐小幅下降,一大优势 | topic从几十到上百,吞吐大幅下降;单机支持topic不宜过多,如有需要可以加更多机器 | ||
MasterSlave | 主-从 | 主-从 | 物理Master-Slave | 逻辑上Master-Slave,按照Partition |
分布式消息事务 | 支持 | 支持 | 不支持 | |
延迟消息 | 支持 | 不支持 | ||
消息投递实时性 | RocketMQ使用长轮询,同Push方式实时性一致,消息的投递延时通常在几个毫秒 | Kafka使用短轮询方式,实时性取决于轮询间隔时间 | ||
消费失败重试 | RocketMQ消费失败支持定时重试,每次重试间隔时间顺延 | Kafka消费失败不支持重试 | ||
消息顺序 | RocketMQ支持严格的消息顺序,在顺序消息场景下,一台Broker宕机后,发送消息会失败,但是不会乱序 | 支持 | Kafka支持消息顺序,但是一台Broker宕机后,就会产生消息乱序 | |
主从选举 | 不需要选举NameServer | KRaft选举 | ||
时效性 | ms | us,最大特点,延迟低 | ms | ms |
可用性 | 高,基于主从架构实现高可用性 | 同ActiveMQ | 非常高,分布式架构 | 非常高,分布式,单数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 较低概率丢数据 | 经过参数优化配置,可以做到0丢失 | 同RocketMQ | |
功能支持 | 极其完备 | 基于erlang开发,所以并发能力很强,性能极其好,延时很低 | MQ功能较为元善,还是分布式的,扩展性好 | 功能较为简单 |
总体优劣势 | 早期使用,社区不活跃 | 吞吐低,语言不熟,开源社区活跃,小公司 | 阿里品牌保障(利弊)要求技术研发力量,大公司 | 大数据领域 |
Master/Slave概念差异
Kafka:Master/Slave 是个逻辑概念,1 台机器同时是 Master 和 Slave。
RocketMQ:Master/Slave 是个物理概念,1 台机器只能是 Master 或者 Slave。
参考:https://blog.csdn.net/wdj_yyds/article/details/123534023
分布式消息队列评价指标
可靠
分布式消息队列提供更好的可靠性,主要体现在:
- 消息会被持久化到分布式存储中。这样避免了单台机器存储的消息由于机器问题导致消息的丢失;
- 不佳的网络环境中,保证只有当消息的接收者确实收到消息时才从队列中删除消息。
可扩展
可扩展性体现在访问量和数据量两个方面:
访问量:分布式消息队列服务,会随着访问量的增减而自动增减逻辑处理服务器;
数据量:当数据量扩大时,后端分布式存储会自动扩容。
安全
安全体现在以下两个方面:
同时使用消息队列的业务之间不会互相干扰。如果有多个业务同时在使用消息队列,对于单机的消息队列服务,一个业务的消息操作可能会影响其他业务的正常运行。比如,一个业务的消息操作特别频繁,占据了消息队列的绝大部分服务时间,也占据了这台服务器的绝大部分网络IO,导致其他业务无法正常地与消息队列通信。而且甚至可能由于服务控制不当,导致机器崩溃,服务停止,业务也跟着停止。分布式消息队列则不会出现这个问题:
(1)监控措施完善,系统性能指数会控制在一定范围之内,而且有任何异常也会报警;
(2)当访问量和数据量增大时,分布式消息队列服务可以自动扩展。各业务的消息内容是安全存储的,其他业务不能访问到非自身业务的数据。
一方面是业务需要密钥来访问消息队列;另一方面,消息是被加密存储的。
简单实用
简单实用体现在:
- 透明:接收者和发送者无需知道具体的消息队列的服务器地址,服务器的增减对接收者和发送者透明。
- 实用:对于两个服务之间不能通信的网络情况,消息队列为他们提供了恰到好处的桥梁。
如何保证消息不丢
生产端不丢消息
生产端如何保证不丢消息呢?确保生产的消息能到达存储端。
如果是RocketMQ消息中间件,Producer生产者提供了三种发送消息的方式,分别是:
- 同步发送
- 异步发送
- 单向发送
生产者要想发消息时保证消息不丢失,可以:
- 采用同步方式发送,send消息方法返回成功状态,就表示消息正常到达了存储端Broker。
- 如果send消息异常或者返回非成功状态,可以重试。
- 可以使用事务消息,RocketMQ的事务消息机制就是为了保证零丢失来设计的
存储端不丢消息
如何保证存储端的消息不丢失呢? 确保消息持久化到磁盘。大家很容易想到就是刷盘机制。
刷盘机制分同步刷盘和异步刷盘:
生产者消息发过来时,只有持久化到磁盘,RocketMQ的存储端Broker才返回一个成功的ACK响应,这就是同步刷盘。它保证消息不丢失,但是影响了性能。
异步刷盘的话,只要消息写入PageCache缓存,就返回一个成功的ACK响应。这样提高了MQ的性能,但是如果这时候机器断电了,就会丢失消息。
Broker一般是集群部署的,有master主节点和slave从节点。消息到Broker存储端,只有主节点和从节点都写入成功,才反馈成功的ack给生产者。这就是同步复制,它保证了消息不丢失,但是降低了系统的吞吐量。与之对应的就是异步复制,只要消息写入主节点成功,就返回成功的ack,它速度快,但是会有性能问题。
消费阶段不丢消息
如何保证消息顺序
消费者执行完业务逻辑,再反馈会Broker说消费成功,这样才可以保证消费阶段不丢消息。
消息队列保证顺序性整体思路就是这样啦。比如Kafka的全局有序消息,就是这种思想的体现: 就是生产者发消息时,1个Topic只能对应1个Partition,一个 Consumer,内部单线程消费。
但是这样吞吐量太低,一般保证消息局部有序即可。在发消息的时候指定Partition Key,Kafka对其进行Hash计算,根据计算结果决定放入哪个Partition。这样Partition Key相同的消息会放在同一个Partition。然后多消费者单线程消费指定的Partition。
如何实现消息事务
下面是RabbitMQ/RocketMQ消息事务的实现机制
- 生产者产生消息,发送一条半事务消息到MQ服务器
- MQ收到消息后,将消息持久化到存储系统,这条消息的状态是待发送状态。
- MQ服务器返回ACK确认到生产者,此时MQ不会触发消息推送事件
- 生产者执行本地事务
- 如果本地事务执行成功,即commit执行结果到MQ服务器;如果执行失败,发送rollback。
- 如果是正常的commit,MQ服务器更新消息状态为可发送;如果是rollback,即删除消息。
- 如果消息状态更新为可发送,则MQ服务器会push消息给消费者。消费者消费完就回ACK。
- 如果MQ服务器长时间没有收到生产者的commit或者rollback,它会反查生产者,然后根据查询到的结果执行最终状态。