消息队列
约 1350 字大约 5 分钟
1. 什么是消息队列?
- mq:消息队列是一种先进先出的数据结构.
2. 为什么使用消息队列?消息队列优缺点?
- 解耦:假设A系统要发送数据到B,C,D系统,如果E系统需要数据然后,D系统不需要了,此时A系统需要维护下游系统的调用,耦合性太高,引入消息队列后可以减少A系统维护成本
- 异步:同步很花费并且业务时效性不大的操作,可以使用异步来提升效果,比如发送微信通知
- 削峰、限流:解决高并发情况
- 系统可用性降低
- 系统复杂度提高
- 一致性问题
3. 消息队列协议
- AMQP、MQTT、STOMP、XMPP协议
4. 消息队列有几种消费语义?
- 消息至多被消费一次(At most once):消息可能会丢失,但绝不重传。
- 消息至少被消费一次(At least once):消息可以重传,但绝不丢失。
- 消息仅被消费一次(Exactly once):每一条消息只被传递一次。
5. Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么优缺点?
![mq.png](https://290ff162.telegraph-image-eg9.pages.dev/file/523ea7439c3ef3a12016b.png)
- 中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。
- 如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。
- RabbitMQ延时最低,消息可靠性高,高可用,但扩展性较差。
6. 如何保证消息的不被重复消费/幂等性?
- 框架层统一封装:由 Producer 生成唯一标识。使用关系型数据库,增加一个排重表,使用消息编号作为唯一主键。需要让插入记录和业务逻辑在同一个事务
- 业务层实现:先查询数据库,判断数据是否已经被更新过。如果是,则直接返回消费完成,否则执行消费。
7. 如何防止消息丢失/可靠性传输
8. 如何保证消息的顺序性?
9. 如何保证消息队列的高可用?
10. 消息积压如何解决
- 临时紧急扩容,具体操作步骤和思路如下:
- 先修复consumer的问题,确保其恢复消费速度
- 新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量
- 然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
- 接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
- 这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
- 等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息
11. 为什么kafka最高吞吐量
- kafka采用顺序读写磁盘,写时分文件顺序写,读时按offset顺序读
- Kafka利用了操作系统本身的Page Cache而不是JVM空间内存
- Kafka 的生产和消费两个过程都使用了零拷贝(zero copy):
- 网络数据持久化到磁盘(Producer 到 Broker使用了mmap)
- 磁盘文件通过网络发送(Broker 到 Consumer使用了sendfile+DMA采集)
- 数据压缩
- Kafka使用了批量压缩,即将多个消息一起压缩而不是单个消息压缩。(如果每个消息都压缩,压缩率相对较低。)
- Kafka允许使用递归的消息集合,批量的消息可通过压缩的形式传输并且在日志中也可保持压缩格式,直到被消费者解压缩
- Kafka支持多种压缩协议,包括Gzip、Snappy、LZ4
- 批量传输
- 在向Kafka发送数据时,可以启用批次发送,这样可以避免在网络上频繁传输单个消息带来的延迟和带宽开销。假设网络带宽为10MB/S,一次性传输10MB的消息比传输1KB的消息10000万次显然要快得多。
- 并行
- 由于不同 Partition 可位于不同机器,因此可以充分利用集群优势,实现机器间的并行处理。
- 由于 Partition 在物理上对应一个文件夹,即使多个 Partition 位于同一个节点,也可通过配置让同一节点上的不同 Partition 置于不同的磁盘上,从而实现磁盘间的并行处理,充分发挥多磁盘的优势。