这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记
0、引入-消息队列
- 案例1:系统崩溃
- 解决方案:解耦
- 此时,就算记录存储发生了故障或宕机,请求也会放到消息队列里面,不会引起业务的故障。
- 案例2:服务处理能力有限
- 解决方案:削峰
-
案例3:链路耗时长尾
-
解决方案:异步
- 案例4:日志如何处理
- 解决方案:
- 总结:消息队列(MQ):指保存消息的一个容器,本质上是一个队列。但是这个队列需要支持,高吞吐、高并发、并且高可用。
1、前世今生
- 业界消息队列对比:
2、消息队列-Kafka
2.1、使用场景:
- 放日志信息数据
- 放Metrics数据:采集程序运行状态数据
- 放用户行为数据
2.2、如何使用Kafka
- 创建集群
- 新增Topic:设置分区数量
- 编写生产者逻辑
- 编写消费者逻辑
2.3、基本概念
-
Topic:逻辑队列,每一个不同的业务场景就是一个topic
-
Cluster:物理集群,每个集群可以建立多个不同的topic
-
Producer:生产者,负责将业务消息发送到Topic
-
Consumer:消费者,负责消费Topic中的消息
-
ConsumerGroup:消费组,不同组Consumer消费进度互不干涉
-
Partition:一个Topic有多个分区,可以并发执行,因此可以提高吞吐量
-
Offset:消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增(保证消息的顺序性)。
- Replica:每个分片有多个Replica, Leader Replica将会从ISR中选出(leader负责写入读取,follower赋值leader的数据,“尽可能”保证一致以达到容灾的目的)。如果某个时刻,服务器发生了宕机,就从ISR中选择一个副本选择为一个leader,保证高可用。
2.2 数据复制
- 图中有4个broker,代表了kafka集群中的节点
- 图中1个broker有2个topic
- 图中controller,集群的大脑,负责将集群中的所有副本和broker进行分配
2.5 kafka架构
- ZooKeeper:负责存储集群的元信息,包括分区分配信息等。
2.6 一条消息的自述(看kafka工作流程)
- Q:如果发送一条消息,等到其成功后再发一条有什么问题?
- A: 吞吐率低(有限时间内发送的消息很少)
2.6.1、producer发送数据
- 问题:如果消息量很大,网络带宽不够用如何解决?
2.6.2、broker存储数据
- 采取顺序写(所有消息都是末尾添加),以提高写入效率:
2.6.3、broker寻找消息
- 偏移量索引文件:
- 时间戳索引文件
2.6.4、broker继续优化
- 传统数据拷贝:
- 从磁盘拷贝到内核态,再拷贝到用户态,内核态才能使用到这份数据
- 从磁盘拷贝到内核态,再拷贝到用户态,内核态才能使用到这份数据
- Broker-零拷贝:
2.6.5、Comsumer-消息的接收端
- 手动分配(预定义好consumer的分配方式):
- 问题1:每个consumer接受一部分partion,当一个consumer出现问题,对应partition的数据流就断掉了,不能自动容灾。
- 问题2:consumer增加或减少的时候,不方便调度partition。
- 好处:快
- 自动分配
- 由Coordinator(协调者)帮助某个consumer group的各个consumer分配partition
- 由Coordinator(协调者)帮助某个consumer group的各个consumer分配partition
- 自动分配的Consumer Rebalance(略)
- consumer去申请一个负载最低的一个broker作为coordinator;
- coordinator选取一个consumer为leader(计算分配的策略);
- consumer发起SyncGroupRequest,同步集群上的数据;
- consumer在一定间隔内发起“心跳”,告诉coordinator它还正常工作中,以防止consumer发生宕机;
总结:
- 为什么kafka支持高吞吐?
- Producer:批量发送、数据压缩;
- Broker:顺序写,消息索引,零拷贝;
- Consumer:Rebalance
kafka-数据复制问题(节点变动时,都会发生)
- kafka-重启操作
- 重启节点特别多的时候,出现负载均衡问题
- 重启节点特别多的时候,出现负载均衡问题
- kafka-替换、扩容、缩容
- kafka-负载不均衡
- 带来数据复制的问题,IO增加,成本增加
kafka-问题总结
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖page cache
- Cotroller和Coordinator和Broker在同一进程中,大量IO会造成其性能下降
3、消息队列-BMQ
- BMQ: 兼容Kafka协议,存算分离,云原生消息队列
- 增加了Proxy(对于写请求,proxy不做任何处理,让broker做写入;对于读请求。proxy直接对分布式存储系统读取);
- 将Controller和Coordinator独立出来了;
- 存算分离,在底层增加了一个分布式存储系统
3.2、运维操作对比
3.3、HDFS写文件流程
- HDFS利用DataNode存储
3.4、BMQ文件结构
- BMQ的一个partition的segment分配在不同节点上,Kafka分配在一个节点上
3.4、BMQ-Broker-Partition状态机
- 目的:解决脑裂问题,保证对于任意分片在同一时刻只能在一个Broker上存活,防止乱序;
3.5、BMQ-Broker-写文件流程
3.5、BMQ-Broker-写文件failover
3.6、BMQ-proxy
- 读取流程
- wait:在有很多consumer的场景下,避免consumer不断发送fetch request请求
- wait:在有很多consumer的场景下,避免consumer不断发送fetch request请求
3.7、BMQ-多机房部署
- 目的:除了防止单机故障,也要防止机房级带来的影响(比如,机房断电);
3.8、BMQ-高级特性
3.9、BMQ-高级特性-泳道消息
- 解决主干泳道流量隔离问题以及泳道资源重复创建问题。
3.10、BMQ-高级特性-Databus
3.11、BMQ-高级特性-Mirror
3.12、BMQ-高级特性-Index
- 2种查询方案(下图右侧)
3.13、BMQ-高级特性-Index
3.14、BMQ-高级特性-parquet
- 什么是列式存储?
4、消息队列-RocketMQ
- 使用场景
4.1、基本概念
4.2、RocketMQ架构
4.3、RocketMQ存储模型
- 每一个broker只有一个commitlog
4.4、RocketMQ高级特性-事务场景
- 保证库存-1和订单记录+1具有事务特性(都需要成功)