理论篇:消息队列
介绍
优点:解耦,异步,削峰
解耦:需要数据,自行去MQ取(订阅topic),降低耦合
异步:避免同步调用的时间开销
削峰:处理不过来的消息堆积在MQ中,高峰期过后再处理
缺点:
- 可用性降低,引入MQ,MQ可能宕机
- 复杂性增加,MQ的重复消息、顺序消息、丢失消息等问题
- 一致性,producer(认为成功)和consumer(实际失败)产生不一致
MQ对比
MQ:ActiveMQ,RabbitMQ,Kafka,RocketMQ
ActiveMQ,吞吐低 + 社区活跃低
RabbitMQ,erlang开发
RocketMQ
Kafka,大数据领域的实时计算和日志采集等场景的优选方案
- 吞吐量
- 延迟
- 可用性
- 消息可靠性
- 功能
- 社区支持
问题:重复消费
充分必要条件:保证幂等性。
方案1:数据库唯一约束
方案2:redis
问题:顺序消费
如何实现:顺序入队和顺序消费。
方案1:一个queue一个consumer,或者consumer端用内存队列排队
方案2:消费端,多个内存队列,相同key的哈希到对应内存队列,每个内存队列一个线程消费
问题:消息丢失/可靠性
场景:生产丢失、MQ丢失、消费丢失
场景 | Ex | RabbitMQ | Kafka |
---|---|---|---|
生产丢失 | 网络异常 | 1. 事务(同步)(吞吐降低) 2. confirm(异步) | 略(消息生产模式) |
MQ丢失 | MQ收到消息,宕机 | 开启持久化 | 略(MQ收到消息模式) |
消费丢失 | 消费者收到消息未处理,宕机 | ack(手动确认,默认为自动确认) | 关闭自动提交offset |
Kafka避免消息丢失:
流程:Producer生产消息,发往Kafka,Kafka返回确认,然后Consumer取消息并消费。
Producer丢失:send失败,即消息没有到Kafka。
Kafka丢失
Consumer丢失:关闭自动提交offset即可
如何解决?
生产和broker丢失处理 | 解释 |
---|---|
acks=0 | 不重试。producer发送消息,不管结果(失败就会丢失) |
acks=1 | producer发完消息,等待leader返回确认就成功(若leader crash,followers没有同步,则丢失) |
acks=all | followers同步完leader才返回确认给producer |
除了acks=all外,还有其他配置:重试、自定义回调、副本数量、同步最少副本个数等
HA
RabbitMQ HA:
- 单机模式
- 普通集群模式:节点之间元数据相同,消息只有一份。(节点间存在临时消息传递,仅解决吞吐量问题)
- 镜像集群模式:HA。MQ的broker之间数据复制备份,实现HA
Kafka HA:
- 分区+副本
写:producer写leader,leader将数据写入本地磁盘,然后followers主动来leader pull
一种模式:leader写完成,ack producer
另一种模式:followers全部pull完,ack leader,然后leader ack producer
读:consumer读leader(leader返回ack的消息才允许被消费)
扩展/伸缩
针对:broker,partition(kafka)
比如:
- 集群部署、分布式部署
- Kafka的分片和副本
case:消息积压
方案:临时紧急扩容。(比如按原来10倍的速度消费数据)
- 修复consumer,确保可以消费,然后停掉
- 扩容消费
- 新建topic,partition扩到原来的x=10倍,queue是原来的y=10倍
- 临时分发程序:将原来topic的数据都转到新建topic
- y=10倍的机器部署consumer,每批consumer消费一个queue
- 恢复
积压的数据丢失:积压时间大于TTL 存活时间,数据丢失。
- 查询丢失数据,待消息少时重新导入这批丢失数据,处理。
case:死信队列
死信:1.消息被拒绝;2.消息过期;3.队列到达最大长度;
使用:定时任务,比如10s后执行任务,设置消息过期时间为10s
TTL,time to live,生存时间
说明:死信交换机中的消息,是可以消费的。
TODO
RabbitMQ
https://www.cloudamqp.com/blog/2018-12-10-a-walk-through-of-the-design-and-architecture-of-rabbitmq.html
架构
Product+Broker+Consumer
X: Exchange
工作模式/消息模型
参考:https://www.rabbitmq.com/getstarted.html
- simple:一对一
- work queues
- pub/sub
- routing
- topics
- RPC
总结下:
- pub/sub就是fanout,广播;
- routing就是direct,路由键(routing key)完全匹配;
- topics就是routing key+通配符
RocketMQ
https://github.com/apache/rocketmq/blob/master/docs/cn/concept.md
架构
Product+Name Server+Broker+Consumer
工作模式
Kafka
分区+复制
##### 架构
Product+ZK+Broker+Consumer
工作模式
生产者,topic,消费者组(消费者1,消费者2, …)
说明:同一消费者组的消费者共享消息。
参考
https://www.rabbitmq.com/getstarted.html
https://www.rabbitmq.com/ttl.html
面试官问我:什么是消息队列?什么场景需要他?用了会出现什么问题?