这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天
消息队列及应用场景
定义:保存消息的一个容器,本质是个队列,但需要支持高吞吐、高并发、并且高可用
应用场景:
- 解耦
- 削峰
- 异步处理
- 处理日志
Kafka
基本概念
Topic: Kakfa中的逻辑队列,可以理解成每一个不同的业务场景就是一个不同的topic,对于这个业务来说,所有的数据都存储在这个topic中
Cluster: Kafka的物理集群,每个集群中可以新建多个不同的topic
Producer:顾名思义,也就是消息的生产端,负责将业务消息发送到Topic当中
Consumer:消息的消费端,负责消费已经发送到topic中的消息
Partition:通常topic会有多个分片,不同分片直接消息是可以并发来处理的,这样提高单个Topic的吞吐
Broker:服务代理节点。对于 Kafka 而言,Broker 可以简单地看作一个独立的 Kafka 服务节点或 Kafka 服务实例。大多数情况下也可以将 Broker 看作一台 Kafka 服务器,前提是这台服务器上只部署了一个 Kafka 实例。一个或多个 Broker 组成了一个 Kafka 集群。
上面这幅图代表着kafka中副本的分布图。图中Broker代表每一个kafka的节点。所有的Broker节点最终组成了一个集群,上图中整个集群,包含了4个Broker机器节点。集群有两个Topic,分别是Topic1和Topic2,Topic1有两个分片,Topic2有1个分片,每个分片都是三副本的状态。这里中间有一个Broker同时也扮演了Controller的角色,Controller是整个集群的大脑,负责对副本和Broker进行分配
如何高效处理数据
Producer:批量发送、数据压缩
批量发送可以减小io次数,从而增加发送能力。
但是如果消息体很大,网络带宽不够用,可以通过压缩来减小消息体的大小,目前支持Snappy,Gzip,lz4,zstd等压缩算法
Broker:顺序写,消息索引,零拷贝
Producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入
如上图所示,在每个broker中都分布着不同的topic的不同分片
在存储数据时,移动磁头找到对应磁道,磁盘转动,找到对应扇区,最后写入。寻道成本比较高,因此顺序写可以减少寻道所带来的时间成本。
Consumer通过发送FetchRequest请求消息数据,Broker 会将指定Offset处的消息,按照时间窗口和消息大小窗口发送给Consumer,寻找数据这个细节是如何做到的呢?
- 通过二分查找的方式寻找数据,文件名是文件中第一条消息的offset,因此只需要找到小于目标offset的最大索引位置,然后通过遍历的方式找到目标offset即可。
也可以通过时间戳来索引文件,只不过多加了一层索引,也就是通过二分找到时间戳对应的offset然后重复之前的步骤即可。
Consumer: Rebalance
对于一个Consumer Group来说,多个分片可以并发的消费,这样可以大大提高消费的效率,但需要解决的问题是,Consumer和Partition的分配问题,也就是对于每一个Partition来讲,该由哪一个Consumer来消费的问题。对于这个问题,我们一般有两种解决方法,手动分配和自动分配:
-
第一,手动分配,也就是Kafka中所说的Low Level消费方式进行消费,这种分配方式的一个好处就是启动比较快,因为对于每一个Consumer来说,启动的时候就已经知道了自己应该去消费哪个消费方式,就好比图中的Consumer Group1来说,Consumer1去消费Partition1,2,3,Consumer2去消费456, Consumer3去消费78。这些Consumer再启动的时候就已经知道分配方案了,但这样这种方式的缺点又是什么呢,想象一下,如果我们的Consumer3挂掉了,我们的7,8分片是不是就停止消费了。又或者,如果我们新增了一台Consumer4,那是不是又需要停掉整个集群,重新修改配置再上线,保证Consumer4也可以消费数据,其实上面两个问题,有时候对于线上业务来说是致命的。
-
第二,自动分配,这里也叫做High Level的消费方式,简单的来说,就是在我们的Broker集群中,对于不同的ConsumerGroup来讲,都会选取一台Broker当做Coordinator,而Coordinator的作用就是帮助Consumer Group进行分片的分配,也叫做分片的rebalance,使用这种方式,如果ConsumerGroup中有发生宕机,或者有新的Consumer加入,整个partition和Consumer都会重新进行分配来达到一个稳定的消费状态