消息队列
1.为什么要用消息队列
解耦,异步,削峰 (1)解耦 如果系统中存在A,B,C,D四个子系统,A系统需要绑定请求至BCD,若业务需要,B不再需要接收来自于A的请求,或者新增E系统对接A系统,则需要频繁修改A系统代码,大大增加了系统的耦合性,如果加入消息队列,A系统只需要把数据发送至mq,下游系统选择消费即可。 (2)异步 一个完整的请求,需要在ABC中进行写库操作,写A库50ms,写B库100ms,写C库80ms。则请求总共花费50+100+80=230ms;若引用消息队列,则A库写库完成后回传结果,B,C异步操作。总耗时50ms。(考虑补偿机制) (3)削峰 一个系统高峰期的qps为5000,但mysql能承受的qps大概在2000左右。倘若不引用消息队列,则mysql容易宕机;引入消息队列后,将消息存放在消息队列中,下游数据操作按照2000qps进行调用,等高峰期过后,可以继续消费。
2.MQ缺点
(1)系统可用性降低。若引入mq后,ABCD系统都依赖于mq,mq宕机后,则系统崩溃 (2)系统复杂性提高。需要考虑消息丢失,消息重复消费,消息保持顺序性消费等问题。 (3)数据一致性问题。如果有个订单系统,库存,订单等操作必须保持一致性,若中途宕机,则需要回滚/补偿等操作
消息队列选型对比
对比
(1)单机吞吐量 ActiveMQ/RabbitMQ:万级 RocketMQ/Kafka:十万级 (2)时效性 RabbitMQ微妙级,其他都是毫秒级,但是毫秒级就用户体验而言已经足够 (3)可用性 ActiveMQ,RabbitMQ :主从结构 ,可用性高 RocketMQ/Kafka:分布式架构,拓展性和可用性极高 (4)消息可靠性 ActiveMQ: 一定情况下存在丢消息的可能(较低概率) RabbitMQ:基于私信队列机制,消息一般不会丢失 RocketMQ/Kafka:通过配置可以实现消息的0丢失
总结
ActiveMQ偶尔会有消息丢失的情况发生,且社区不够活跃; RabbitMQ基于erlang语言开发,二开难度大。但有实用的后台管理界面,方便操作; RocketMQ,阿里开发,体系成熟,支持分布式; Kafka:scala开发,仅支持一些核心功能,支持大吞吐量,但会有消息重复消费的情况出现,多用于大数据处理
3.消息队列保持可用性
RabbitMQ
普通集群模式
(1)上游发送消息至RabbitMQ集群,MQ会随机选取一个实例进行数据的存储,其他的实例只会同步元数据。如果消费的并非是存储实际数据的实例,则需要通过元数据拉取对应存储消息的queue。 (2)频繁的拉取数据会造成性能的消耗,若某台机器宕机,可能会导致整套集群不可用;若开启MQ持久化,也必须要等到数据恢复后才可使用
镜像集群
镜像集群模式与普通集群不同的是,生产者生产消息后,所有的queue都会同步元数据和实际数据。
好处在于任何一台机器宕机,都能保证消息消费的可用性。但是同步数据的性能消耗太大,如果新增一个节点,也会同步queue中的所有消息,服务器压力大,且没有线性拓展性。
Kafka
Kafka属于分布式消息队列,由多个broken组成,每个broken可看做一个节点;当创建一个topic时,topic会划分为多个partition,每个partition存在于不同的broken中,这样每个机器上可以存放topic中的一部分数据。
Kafka0.8以前,如果一个broken宕机,则该机器上的partition中存放的数据丢失。不可读也不可写。 Kafka0.8以后,增加lHA机制,也就是replica副本机制。每个partition上的数据都会同步到其他机器上,同步完成后会从所有的replica副本中选举出leader,与消费者和生产者交互。倘若某个leader宕机,则会从剩下的replica副本中重新选举leader,实现了高可用性。但要注意数据一致性。
|