zhanggao / learnNotes

2 stars 2 forks source link

MQ #37

Open zhanggao opened 4 years ago

zhanggao commented 4 years ago

极客时间 消息队列高手课

zhanggao commented 4 years ago

主流消息队列区别

RabbitMQ 消息堆积时性能会急剧下降,正常情况性能也过差,客户端支持的语言基本是所有消息队列中最多的。 RocketMQ 中规中矩,没有特别的优点,也没有特别的缺点,性能好、延时低。 Kafka 与周边生态的兼容性是最好的,由于攒一波再发的特性导致延时过高,不适合在线业务场景。

zhanggao commented 4 years ago

主题+队列(kafka主题+分区)的概念

RabbitMQ 使用的是队列模型,如果一个消息要被多个消费者消费,那Exchange模块就将消息投递到多个队列中,每个队列都保存一份完整的消息数据。

RocketMQ和Kafka使用的是标准的发布订阅模型。 RocketMQ 每个主题包含多个队列,通过多队列来保证多实例并行发布和消费,只能在队列层面保证消息的有序,不能在主题层面保证消息的有序。 一个主题对应多个队列,一个队列可以被多个消费者消费,会为每个消费者保存一个消费位置。 image

队列的数量最好是Consumer的倍数

Kafka和RocketMQ完全一致,唯一的区别是,RocketMQ中的队列在Kafka中叫分区

极客时间 主题和队列的区别

zhanggao commented 4 years ago

分布式事务

Kafka和RocketMQ 1.开启本地事务 2.发送半消息(包含消息所有内容) 3.执行本地写数据逻辑 4.提交或者回滚 5.消息队列投递消息 第4步失败的问题:RocketMQ投递方实现反查功能;Kafka直接抛出异常让用户自行处理;

zhanggao commented 4 years ago

如何确保消息不丢失

1、检测消息丢失: Producer给每个消息加递增的序号,在Cusumer检测序号是否递增。 由于消息队列只保证分区有序,多个Producer递增也不太方便,可以每个Producer各自递增并指定队列发送,Cusumer在Producer纬度检测序号。

2、确保消息可靠传递: 生产阶段,Producer给Broker发送消息后,Broker给Producer回一个确认,确认超时或者失败Producer重试; 储存阶段,将Broker配置成落盘再发确认,如果是集群则配置成同步到至少两个以上节点再发确认; 消费阶段,Consumer执行完业务逻辑再发送消费确认,Broker如果没收到消费确认,下次拉的时候还会返回同一条消息。

无论是Broker还是Consumer都是有可能收到重复消息的。

zhanggao commented 4 years ago

重复消费

至多一次、至少一次、恰好一次。 绝大多数消息队列都是至少一次,然后Consumer处理重复消费问题。 至少一次+幂等性=恰好一次

常用幂等性方法: 1、MySql的唯一性约束(例如每次转账有个转账id,一个id只能写成功一次),Redis的setnx; 2、每个数据增加一个版本号属性,更新时比较版本号; 3、每条消息指定唯一的全局性id,消费时检测id有没有消费过,消费后记录id。

zhanggao commented 4 years ago

消息积压了怎么办

优化性能避免积压: 1、优化发送端性能; 2、优化消费端性能,必须保证消费性能高于发送; 3、扩容消费端,扩容消费端的同时必须扩容队列(Kafka的分区)的个数,对应消费者来说,每个队列只支持单线程消费,Consumer数量超过队列数是没有意义的;

真的积压了: 扩容消费端、降级优先级低的消息

zhanggao commented 4 years ago
zhanggao commented 4 years ago