RabbitMQ? Kafka? RocketMQ?
消息队列是什么
消息队列是分布式系统中重要的组件,它可以看作是一个存放消息的容器,我们可以产生消息供别人使用,也可以取出别人产生的消息供自己使用
消息队列的作用
老生常谈的问题了,应当张口就来:异步、解耦、削峰
异步
假设我们有一个订单系统,用户支付完成,流程就结束了,但后来搞了个积分系统以后,产品经理要求在用户支付完成后在积分系统内增加积分,过两天又为了用户体验要求在支付完成后给用户发送短信,一周后又提了个用户支付完成后邮件发送电子发票的需求,导致整个流程就变的比较复杂,如图
假设每个环节都耗时 200ms,原来 200ms 就能结束的流程现在变为了 800ms,再有后续的操作的话时间还会更长,但对于用户来说,需要关注的只是支付这一个动作,如果支付完了还得同步等待剩余流程的话,用户体验会非常不好
在用户看来,增加积分、发送短信、发送邮件稍微晚那么几秒也没有关系,而且这三个流程可以同时执行,没有必要的先后顺序,那么我们可考虑将系统做一下改进,如图
改进完成后,用户只用了 200ms 进行支付操作,省下的流程都变为了 异步 操作
解耦
使用线程
乍一看上述的三个流程可以用线程来做,因为线程也可以实现异步,但用线程的话会面临一个问题:强耦合
每次增加一个流程要调用一个接口或者接入 SDK,流程修改完成后还重新发布系统,如果流程多了那么我们不禁要发问了:“我就是个订单系统,发短信和发邮件和我有毛关系啊?!”
不仅如此,如果线程里的三个流程是线性执行的,前面的流程如果报错了会影响后面的逻辑;如果分别用了三个线程去做三个逻辑,第一是浪费资源,其次如果报错了还是免不了负责各个系统的程序员小哥来找你调试,本来能按时下班的,这下又要加班了
使用消息队列
- 用户支付以后,订单系统把支付成功的消息扔进消息队列
- 其余系统从消息队列拉取订单系统发布的消息,各自走各自的流程
- 如果有新的流程加入,只需在消息队列里订阅订单系统发送的支付成功的消息,订单系统无需改动
可能有同学会问:“订单系统的流程是走完了,那如果积分系统流程失败了应该怎么办?”,这就涉及到分布式事务了,但对于订单系统来说,将支付成功的消息发送到消息队列就是完成流程了,积分系统的流程成功与失败应该是积分系统处理的事情,这样就做到了 解耦
削峰
每天 0:00 到 12:00,订单系统风平浪静,每秒并发请求数量就 50 个, 12:00 ~ 13:00 ,每秒并发请求数量突然会暴增到 5k+ 条,但是系统是直接对接 MySQL 的,大量的请求涌入 MySQL,每秒钟执行约 5k 条 SQL
一般的 MySQL,扛到每秒 2k 个请求就差不多了,如果每秒请求到 5k 的话,MySQL 可能直接就挂了,导致系统崩溃,用户也就没法再使用订单系统了。但是高峰期一过,到了下午的时候,就成了低峰期,每秒中的请求数量可能也就 50 个请求,对整个系统几乎没有任何的压力
这个短暂的高峰期积压是没有问题的,因为高峰期过了之后,每秒钟就 50 个请求进 MQ,但是订单系统依然会按照每秒 2k 个请求的速度在处理。所以说,只要高峰期一过,订单系统就会快速将积压的消息给解决掉,这样就实现了 削峰
常用消息队列的比较
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级 | 万级 | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | μs级 | ms 级 | ms 级 |
可用性 | 高,基于主从架构实现高可用 | 同 ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到 0 丢失 | 同 RocketMQ |
功能支持 | 功能极其完备 | 基于 erlang 开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
社区活跃度 | 低 | 中 | 高 | 高 |
常用消息队列的选择
-
RocketMQ
阿里出品贡献给了 Apache,通过双 11 海量数据的考验,基础架构研发实力较强的公司推荐使用
但社区有突然黄掉的可能(参考当年的 Dubbo 2013-2017 年停更),不过已经捐给了 Apache,可能性不大
-
Kafka
大数据领域的实时计算、日志采集等场景,用 Kafka 是全世界这个领域的事实性规范
-
RabbitMQ
吞吐量低,使用 erlang 开发,如果不懂 erlang 的话将无法深入研究源码,二次开发维护成本巨大
-
ActiveMQ
不推荐,吞吐量低,社区也不是很活跃
使用消息队列可能产生的问题
-
重复消费
-
顺序消费
-
消息丢失
-
分布式事务
-
系统可用性
需要根据具体的 MQ 制定相应的解决方案