这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天
今日笔记内容: 消息队列原理与实践
消息队列的应用案例
- 系统崩溃(解耦)
- 服务能力有限(消峰)
- 调用链路耗时长尾(异步)
- 日志存储
消息队列(MessageQueue), 指保存消息的一个逻辑队列, 需要支持高吞吐, 高并发与高可用
发展历程
- TIB: 1985年, 服务于金融机构和新闻机构
- IBM MQ/WebSphere, 193年, 商业消息队列
- MSMQ: 微软发布于1997年
- JMS: 2001, JavaApi
- AMQP(高级消息队列协议)/RabbitMQ: 2004年
- Kafka: 2010年 Linked开源
- RocketMQ: 2011年阿里团队开源
- Pulsar: 2012年Yahoo
Kafka
分布式, 分区, 多副本的日志提交服务, 高吞吐场景下表现出色
使用场景
- 搜索
- 直播
- 订单
- 支付 收集
- 日志
- metrics
- 用户行为
Kafka基本概念
![[Pasted image 20230209123952.png]]
-
Topic: 逻辑队列, 不同topic相互隔离, 可以不同业务场景对应一个topic
-
Cluster: 物理集群
-
Broker: 集群中单个节点
-
Producer: 消息生产者
-
Consumer: 消息消费者
-
ConsumerGroup: 消费者组, 同一个组的消费者共享消费进度, 提升消息处理速度
-
Partition: topic内部可以有多个分片, 不同分片可以并行处理
-
Offset: 消息在partition中的相对位置, 可以作为消息的唯一id, partition中严格递增
-
Replica: partition的副本, 复制信息用于容灾
kafka集群依赖ZooKeeper做集群管理, 存储集群的元信息
Kafka的高吞吐架构
- Producer发送
- 批量发送
- 消息压缩
- Broker的存储架构
- 末尾添加, 顺序写
- /Topic/Partition/Segment/(log|index|tiemindex)
- 消息索引
- SendFile系统调用0拷贝, 直接将文件内容发送到网卡
- Consumer消费组织
- Lov-Level:手动分配: 不够灵活
- Hight-Level: 节点变更, 自动负载均衡
文件组织: Segment是存储日志数据的基本文件单元, 每个Segment以存储的第一个日志的offset命名, 包含.log, .index, .timeIndex 三个文件, 通过二分查找找到小于offset的最大文件, 查找其日志内容
日志拷贝带来的问题: 节点重启, 集群节点变更出现时, 需要同步拷贝缺失的日志问题, 且为了保证集群的高可用, 拷贝的并发度不能设置太高, 导致耗时增加. Partition负载不均衡, 需要切换不同节点时, 也会面临同样问题 问题总结:
- 运维成本高
- 对于负载不均衡的场景, 解决方案复杂
- 没有自己的缓存, 依赖OS page cache
- Controller, Coordinator 和 Broker 在同一进程中, 大量IO会造成其性能下降
BMQ(ByteMQ)
支持kafka协议, 存算分离架构, 云原生消息队列 ![[Pasted image 20230209175721.png]]
通过引入Proxy层, 大大降低了运维操作的耗时
RocketMQ
低延迟, 强一致性, 高性能, 高可靠, 万亿级别容量和灵活的可拓展性, 在一些实时场景中运用较广
| 名称 | Kafka | RocketMQ |
|---|---|---|
| 逻辑队列 | Topic | Topic |
| 消息体 | Message | Message |
| 标签 | 无 | Tag |
| 分区 | Partition | ConsumerQueue |
| 生产者 | Producer | Producer |
| 生产者集群 | 无 | Producer Group |
| 消费者 | Consumer | Consumer |
| 消费者集群 | Consumer Group | Consumer Group |
| 集群控制器 | Controller | NameServer |
存储模型: 所有消息存储到一个CommitLog中, 根据不同的Queue加入到对应ConsumerQueue
高级特性:
- 事务场景: 事务消息检测下游消费情况, 如果超时没有完成消费, 触发回滚逻辑, 消息不再会被消费, 类似于两阶段提交
- 延迟发送
- 处理失败: 消息重试, 死信队列