消息队列|青训营笔记
这是我参与【第五届青训营】伴学笔记创作活动的第12天。
一、重点知识
- 消息队列的基础知识
- Kafka的实现方式,重要内容、问题
- BMQ的实现方式、重要内容、问题
- Rocket的实现方式
二、详细知识点
1. 走进消息队列
1.1 基础问题
- 系统崩溃:如果记录存储失效,如何反馈?
- 解耦:添加一个消息队列,由消息队列反馈至数据库
- 服务能力有限:庞大的请求量,处理订单服务器只能同时处理数个请求
- 削峰:添加消息队列,每次取出一定量的请求
- 发起订单后 链路耗时长尾:通知商家花费的时间长
- 异步:通过消息队列广播到不同状态
- 日志存储:日志如何处理
- 日志处理创建消息队列,stash后存入
1.2 消息队列基础
- 消息队列MQ
- 保存消息的一个容器
- 本质是一个队列
- 支持高吞吐、高并发、高可用
1.3 发展历程
- 早期TiB
- IBM MQ/WebSphere
- MSMQ
- JMS:JAVA API
- AMQP/RabbitMQ
- Kafka
- RocketMQ
- Pulsar
1.4 常见业界消息队列
- Kafka:分布式分区多副本日志提交服务,高吞吐下发挥较为出色
- RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量、灵活可拓展性,实时场景应用广
- Pulsar:下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体,存算分离
- BMQ:类似Pulsar
2. Kafka
2.1 使用场景
- 搜索服务、直播服务、订单服务、支付服务
- 日志信息
- 用户行为
- Metrics数据:程序运行中程序状态的采集
2.2 如何使用Kafka
- 创建集群
- 新增Topic
- 编写生产者逻辑
- 编写消费者逻辑
2.3 基本概念
- topic:逻辑队列,不同topic建立不同的队列
- cluster:物理集群,每个集群中可以建立不同topic
- producer:生产者,将业务消息发送到topic中
- consumer:消费者,消费topic中信息
- ConsumerGroup:消费者组,不同组消费者消费进度不干涉
- offset:消息在partition内的相对位置信息,唯一ID,在partition内部严格递增
- replica:副本数,每个分片有多个,leader会从ISR(In-Sync Replica)中选出
2.4 数据复制
- 多个broker节点
- leader向follower发送副本
- controller负责分配其他的broker
2.5 Kafka架构
- zookeeper负责存储原数据信息、分区信息
- cluster内存在broker
- 下不分配到不同的consumer group
2.6 一条消息的流程
- producer生产
- 如果等待成功后再返回,会发生延时:批量发送 batch
- 带宽不够用:数据压缩减少消息大小
- broker
- consumer消费
2.7 broker消息文件结构
- 切分为不同的日志段,方便基于时间点的切分
- LogSegment有日志、偏移量、时间戳等
2.8 Broker磁盘结构
- 移动磁头找到对应磁道磁盘转动,找到对应扇区,写入
- 寻道成本高
- 顺序写可以减轻读写成本
- 偏移量索引文件:二分找到小于目标offset的最大文件
- 二分找到小于目标offset的最大索引位置
- 二分找到小于目标时间戳最大索引位置
- 通过offset找到最终数据
2.9 broker传统数据拷贝(零拷贝)
- 内核态,从磁盘读取到read buffer,拷贝到应用空间(用户态)
- 需要反复拷贝到内核空间
- 由内核空间发送到消费者进程
- 通过sync file把磁盘读取到内核空间,内核空间发送到网卡再发送到消费者进程
2.10 Consumer——消息接受端
- Partition在Consumer Group中的分配
- 手动分配:手动进行分配,consumer与partition分配由业务决定
- 缺点:新加机器时没有额外的partition,需要停掉原本进程重新分配;导致数据中断
- 自动分配 Rebalance:Coordinator重新计算每个consumer的分片,以此达到稳定状态
- consumer发送寻找coordinator的request
- broker找到group coordinator
- group coordinator返回信息,同时设定一个consumer leader
- consumer leader将分配方案返回给coordinator
2.11 Kafka数据复制
- Kafka没有自己的缓存,依赖PageCache
2.12 Kafka重启操作
- 重启Leader:从follower中选一个为leader
- Leader切换,原leader需要追赶数据
- 数据同步完成后,leader回切
- 时间成本很大,因为需要一台一台重启
2.13 Kafka替换、扩缩容
- 新机器类似于重启,但需要从零开始追赶
- 缩容:需要分配到其他机器上
- 实际的时间成本很大
2.14 负载不均衡
- 如果partition大小不均,在迁移时会增加I/O问题
- 导致为了解决I/O问题引入新的I/O问题
- 因为在统一进程中,大量I/O导致性能下降
3. BMQ消息队列
3.1 简介
- 兼容kafka协议
- 存算分离
- 云原生消息队列
3.2 运维操作对比
- 利用proxy代理代替直接联系broker,减轻broker压力,同时方便添加和消除consumer
- 重启:kafka需要数据复制,BMQ秒级完成
- 替换:kafka需要数据复制,BMQ秒级完成
- 扩缩容:kafka需要数据复制,BMQ秒级完成
3.3 HDFS写文件流程
- 随机选取一定数量的datanode进行写入:根据副本数随机选择写入
3.4 BMQ文件结构
- Kafka可能会存在partition不均衡
- BMQ将partition分为segment,每个segment会写在不同的机器上;
- 最后不需要将partition全部分在一个节点
- 选取segment汇合成partition
3.5 broker-partition状态机
- 保证任意分片在同一时刻只在一个broker上存活
3.6 写文件流程
- 信息进行数据校验,存入buffer,存入writer thread 存入storage
- writer thread会写数据,然后flush,创建索引,创建checkpoint,存入新的segment file
- failover:如果datanode节点挂了导致写文件失败,可以重新更换节点,进行重新写入
3.7 Proxy
- 接受request,等待,存入cache,到达大小,返回数据
- miss,进入storage,打开file,寻找阅读
3.8 多机房部署
- proxy可以分别部署到多个broker上
- 每个机房处理全量的partition
- 在本地可以访问proxy
- broker需要全部机房加在一起才能成为一个topic的全部分片
3.9 泳道消息
- 解决主干泳道流量隔离问题以及泳道资源重复创建问题
3.10 Databus
- 使用原生SDK的问题
- 客户端配置较为复杂
- 不支持动态配置,更改配置需要停服
- latency不敏感业务,batch效果不佳
- 使用Databus
- 简化消息队列客户复杂度
- 解藕业务与topic
- 缓解集群压力,提高吞吐
3.11 Mirror
- 跨region读写的问题
- 使用mirror通过最终一致方式解决
- 使用mirror通过最终一致方式解决
3.12 Index
- 希望通过写入的logid和userid或其他业务字段进行消息查询应该怎么做?
- 创建索引表
- 直接在BMQ中数据结构化,异步构建索引,通过index query读出数据
3.13 Parquet
- 新型列式存储方式
- 在BMQ中通过parquet engine可以使用不同方式构建parquet格式文件
4. RocketMQ
4.1 基本概念
- 使用场景:低延时,针对电商、实时业务、业务峰值等
- 与kafka区别
- 拥有消息标签Tag:在topic下还能进行区分
- partition——consumerqueue
- 拥有生产者集群
- controller——nameserver
4.2 RocketMQ架构
4.3 存储模型
- 所有数据发送到broker的commitLog
- 根据分区,发送到不同的consumerqueue
- 在consumerqueue中只存储offset
4.4 事务场景
- 最终一致性
- 延迟发送/延迟消息:在consumerqueue提取后有scheduler进行延迟
- 消费重试,死信队列:消费失败,若没超过最大重试次数,则投递至scheduleTopic,schedule延时投递到retryTopic队列
- 若超过最大重试次数,发送到死信队列
三、课堂总结
本节课介绍了消息队列的相关知识。在大数据班的学习中,曾经学过Kafka相关的内容。而在本次课程中主要了解了Kafka、BMQ以及RocketMQ相关的知识。课程比较抽象,需要在课后结合代码进行进一步学习。