消息队列
定义
针对四个问题:
-
系统崩溃
解决方案:解耦
graph LR; User((user))-->a[搜索商品]-->b[搜索行为记录]-->c[点击商品]-->d[点击行为记录] b-->e[消息队列] d-->e-->f[存储服务]
-
服务处理能力有限
解决方案:削峰(只能处理10个请求就拿10个请求)
-
链路耗时长尾
-
日志如何处理
解决方案:
消息队列(MQ),指保存消息的一个容器,本质是个队列。但这个队列需要支持高吞吐、高并发、高可用
前生今生
Kafka
Metrics数据:在程序运行当中对程序进行一些状态的采集 (QPS、查询耗时、写入耗时等)
如何使用Kafka
graph TD;
a[创建集群]-->b[新增Topic]-->c[编写生产者逻辑]-->d[编写消费者逻辑]
基本概念
Topic:逻辑队列,不同Topic可以建立不同的Topic(每一个不同的场景就是一个topic)
Partition:Topic中的分区的概念,不同的分区可以并发处理消息
Cluster:物理集群,每个集群中可以建立多个不同的Topic
Producer:生产者,负责将业务消息发送到Topic中
Consumer:消费者,负责消费Topic中的消息
ConsumerGroup:消费者组,不同组Consumer消费进度互不干涉
offset:消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增
每个分片有多个Replica,Leader Replica将会从ISR中选出
Leader:主副本,从Replica1-Leader上进行生产和消费
Follwer:副本,与主副本保持一定的同步(offset/时间),如果差距太大将会被踢出ISR(In-Sync-Relicas)如Replica3。
如果Leader中发生了宕机,那么就可以从ISR的follower中继续为生产者和消费者进行服务。保证高可用。
数据复制
每个broker代表kafka集群中的一个节点,集群中有两个topic,topic1有两个partition,topic2有1个partition,每一个partition是3个replica的状态。
其中第二个broker扮演了controller的角色,controller是整个集群中的核心,负责分配broker、replica、partition。
每一个consumer group都是独立的,意味着每一个group都需要获得所需要的topic的全量数据
架构图
批量发送
通过batch操作
如果遇到消息量很大,网络带宽不够用,如何解决?
采用数据压缩(推荐ZSTD算法)
数据的存储
broker是如何将消息存储到本地磁盘中呢?
broker-磁盘结构
采取顺序写的方式进行写入,以提高写入效率
如何找到消息
consumer通过发送FetchRequest请求消息数据,Broker会将指定Offset处的消息,按照时间窗口和消息大小窗口发送给Consumer,寻找这个细节是如何做到的呢?
偏移量索引文件
每一个logsegment文件的命名方式都是以第一条消息的offset来命名的
通过offset进行索引
通过时间戳进行索引(二级索引表)
传统数据拷贝
Broker——零拷贝
传统的数据传输方式涉及多次数据拷贝操作。例如,当应用程序从磁盘读取数据时,数据首先被拷贝到内核缓冲区,然后再次被拷贝到用户空间缓冲区,最后才能被发送到网络。这些数据拷贝操作会占用CPU时间和内存带宽,对系统性能产生影响。
而零拷贝技术通过避免数据的不必要拷贝,将数据直接从源缓冲区传输到目标缓冲区,以减少数据拷贝的次数。在 Kafka 中,零拷贝技术主要应用在生产者和消费者之间的数据传输过程中。
具体来说,Kafka 利用操作系统提供的 sendfile() 系统调用或类似的机制,实现了零拷贝。在生产者端,Kafka 使用 sendfile() 将数据从磁盘直接传输到网络套接字,而无需经过额外的数据拷贝。在消费者端,Kafka 利用零拷贝技术将数据从网络套接字直接写入到内存缓冲区,避免了额外的数据拷贝操作。
通过使用零拷贝技术,Kafka 在数据传输过程中能够更高效地利用系统资源,减少了不必要的数据拷贝和上下文切换操作,提高了数据传输的吞吐量和性能,同时降低了CPU和内存的开销。这对于处理大量数据和实现低延迟的消息传递非常有益。
消息的接收端
low level(消费方式)
-
不能容灾,如果consumer3挂掉了,那么topic中的partition7和partition8的数据流断掉了
-
新建consumer时需要重新分配,启停之前正在消费的consumer
high level(消费方式)
自动分配
怎么达到具体的Rebalance?
- 消费者向集群中负载最低的broker发送findCoordinatorRequest,该broker将coordinator信息发送回consumer
- 消费者向coordinator发送JoinGroupRequest,形成consumer group,coordinator也会选取一台consumer作为leader
- consumer group中的leader向coordinator发送SyncGroupRequest并携带分配方案,其他consumer只需发送SyncGroupRequest。
- coordinator把分配方案发送给consumer group中的consumer
- consumer group中的consumer隔一段时间需要向coordinator发送心跳信号,如果一段时间某一个consumer没有心跳则被踢出group 重新进行分配partition
小结:
刚才总共讲了哪一些可以帮助kafka提高吞吐或者稳定性的功能?
Producer:批量发送、数据压缩
Broker:顺序写,消息索引,零拷贝
Consumer:Rebalance
kafka——数据复制问题
kafka集群升级业务时需要重启
重启代价过大
kafka—替换、扩容、缩容
跟重启类似,但替换和扩容都要从0开始追赶数据。
kafka— 负载均衡问题
kafka问题总结
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖Page Cache(文件系统自带)
- Controller 和 Coordinator 和 Broker在同一进程中,大量的IO会造成其性能下降。
BMQ
定义
BMQ为解决Kafka存在的问题应运而生。兼容Kafka协议,存算分离(可以将broker中的数据放到分布式存储系统中),云原生消息队列
Producer和Consumer基本和Kafka协议中的相同。
使用的分布式存储系统是HDFS
读写分离,存算分离,没有数据复制之后,性能大大提高
Kafka与BMQ操作性能对比
HDFS写文件流程
BMQ文件结构
BMQ(Balanced Message Queue)是一种用于解决 Kafka 负载不均衡问题的解决方案。Kafka 负载不均衡指的是 Kafka 集群中的分区(Partitions)在不同的 Broker 节点上分布不均匀,导致某些 Broker 节点负载过高,而其他节点负载较低的情况。
BMQ 通过以下方式解决 Kafka 负载不均衡问题:
- 动态分区分配:BMQ 采用动态的分区分配策略,能够根据当前 Broker 节点的负载情况,自动调整分区的分布,使得各个节点的负载更加均衡。
- 基于权重的分区分配:BMQ 引入了权重机制,通过为每个 Broker 节点分配不同的权重值,来影响分区的分配情况。具有较低负载的节点将被分配更多的分区,而具有较高负载的节点将被分配较少的分区,从而实现负载均衡。
- 动态调整机制:BMQ 在运行时会根据实时的负载情况动态调整分区的分配。当某个节点的负载过高或过低时,BMQ 将根据预先设定的策略进行重新分配,以使得负载更加均衡。
- 容错机制:BMQ 考虑了 Kafka 集群的容错性,在进行分区分配时会考虑到故障节点的情况,避免将分区分配给故障节点或无法正常提供服务的节点。
通过上述机制,BMQ 能够有效地解决 Kafka 负载不均衡的问题,提高集群的整体性能和稳定性。它能够动态地调整分区的分配,使得各个节点的负载均衡,并考虑到节点故障情况,保证了系统的可用性和可靠性。
Broker—Partition状态机
对于partition来讲的话,最终是写在HDFS中的。不同broker中的partition(可能不止一个)向controller争夺写入HDFS的权利。写入的过程可能存在问题,首先Recover保证云数据和真实数据保持一致。
Broker——写文件流程
Broker—写文件 failover
如果DataNode节点挂了或者是其他原因导致我们写文件失败,应该如何处理?
换一个可用的DataNode,创建一个新的segment
Proxy(读文件)
设置时间窗口,降低请求压力
多机房部署
Proxy是全量的,每一个Broker保存一部分的partition。如果A机房宕机了,那么其相应的broker中的partition会rebalance到其他两个broker中去。
BMQ高级特性
泳道消息:
——产生原因
BOE测试:多人同时测试,需要等待上一个人测试完成
每多一个测试人员,都需要重新搭建一个相同配置的Topic,造成人力和资源的浪费。
PPE验证:
泳道应运而生
Databus
直接使用原生SDK会有什么问题?
- 客户端配置较为复杂
- 不支持动态配置,更改配置需要停掉服务
- 对于latency不是很敏感的业务,batch效果不佳
Mirror
Index
graph LR;
Producer-->BMQ-->Consumer
Query By:
- Offset
- Timestamp
如果希望通过写入的LogId、UserId或者其他业务字段进行消息的查询,应该怎么做?
直接在BMQ中将数据结构化,配置索引DDL,异步构建索引后,通过Index Query服务读出数据
Parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等)
RocketMQ
使用场景:针对电商业务线,其业务设计广泛,如注册、订单、库存、物流等;同时,也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等(低延时)
基本概念
架构
存储模型
密集索引
高级特性
事务消息
事务的两阶段提交
延迟发送
graph TD;
员工((员工))-->提前编辑菜单-->消息队列-->定时发送-->接收菜单
延迟消息原理: