目录
架构原理
架构
工作流程
控制器
存储机制
kafka高性能的秘密
Kafka系列:
kafka 2.4.1单机版部署及使用
kafka监控系统kafka eagle安装使用
滴滴开源的kafka-manager编译及部署使用
kafka管理监控系统 CMAK(yahoo的kafka-manager)部署及使用
Kafka系列(一)、2.6.0版本kafka集群搭建
注意:
- kafka的副本数量不能大于broker节点数量。kafka的副本数量和HDFS的副本数量是有区别的。
- HDFS的副本数量表示为最大副本数量,当DataNode节点数量小于设置的副本数量时没有任何问题,当新增DataNode时候如果副本数量没达到要求会自动复制副本。
- 而kafka的副本数量表示为该topic的副本数量,当副本数量大于broker节点数量时会报错,这是因为分区是以目录存储在各个broker节点的data目录下,命名为:topicName-分区编号。当副本数量大于broker节点时就表示在同一个Broker节点的data目录下有两个一样的文件夹,这是不允许的。
- kafka的分区数量可以大于broker节点数量,当分区数量大于broker节点数量时,在broker节点的data目录下会有同一个topic的两个分区的数据,如:topicName-0,topicName-1。
- 消费者组内的消费者的数量不要设置大于该消费者组订阅的所有topic的分区总数,这是由于该消费者组订阅的topic的每个分区只能被消费者组内的一个消费者所消费,当消费者组内的消费者数量大于订阅的topic的总分区数量时就会造成有消费者没有分区数据消费的情况,会造成资源的浪费。
- kafka只保证分区内有序,不能保证全局有序。每个分区内有自己的Offset,并不是全局的offset。
在上图中我们也可以看出,生产者只会往分区副本中的Leader发送数据,消费者也只会从分区副本中的Leader读取数据,分区副本中的Follower从Leader内同步数据,尽量保持和Leader副本的数据一致。当多个消费者在同一个消费者组的时候,组内的每个消费者不能消费同一个分区数据,即某个topic内的某个分区只能被在同一消费者组内的一个消费者所消费,当跨消费者组时,可以被其他消费者组内的消费者消费。消费者每当消费一条数据都会往kafka记录一个offset偏移量,记录该消费者所消费的topic分区已经消费到的位置,便于下次重新消费时可以继续消费。(在0.90版本之前该offset信息是维护在zk内,在0.90之后不建议再使用zk保存该offset信息,而是维护在kafka内的一个系统topic中:__consumer_offsets)。Broker和消费者组都会向ZK进行注册,将元数据信息维护在ZK内。
kafka中的消息以topic进行分类,同时消费者和生产者都是面向topic读写消息的,更细粒度的来说,它们面对的是topic内分区的主副本,topic仅仅是逻辑上的划分,而partition是物理上存储的划分。
在上面我们提到消费者和生产者都是直接面向topic内分区的主副本,从副本从主副本同步数据,因此从副本的数据和主副本的数据会有延迟,如上图显示了一个topicA有两个分区,每个分区有2个副本(leader和follower),其中分区0的主副本内的offset为0~8,分区0的从副本的offset为0~5,分区1的主副本内的offset为0~6,分区1的从副本的offset为0~3。
每个分区在物理上是按文件夹区分的,在分区文件夹内有多个.log和.index文件,同名的.log和.index一一对应,.log文件内存储着生产者发送给该分区的实际数据和offset,每当生产者发送数据都会追加到.log文件的末端,.index内存储着.log文件的索引数据以提升消费者查询数据的性能。消费者从.log文件消费数据之后会往__consumer_offset这个系统topic内记录自己已读取的offset(偏移量)。
上面提到了消费者和生产者都是直接面向topic内分区(partition)的主副本(Leader),从副本(Follower)从主副本同步数据,当Leader副本出现故障时会进行选举,将某一个Follower副本升级为Leader副本继续提供读写服务。这里就涉及到了Controller(控制器)。
集群内broker通过zk内的/broker/ids 节点互相通信:
在前一篇安装Kafka集群的时候我们在配置文件中并没有指向其他的kafka节点,但却能搭建集群,是因为server.properties 文件内配置了zk服务器,每个kafka broker节点通过配置的zk服务器注册到zk内的/broker/ids 节点内,在该节点内的broker自动成为一个kafka集群。
集群内broker通过zk内的/controller 节点成为控制器节点:
同时当broker启动时会去抢占zk内的一个临时Znode节点/controller,抢占成功的broker自动成为该kafka集群的Controller节点,在一个时间点内,一个kafka集群内只允许有一个Controller节点,当该controller节点发生故障时,其他broker节点也会去抢占该临时节点,抢占成功的Broker又会自动成为controller节点。
kafka通过zk内的/controller_epoch 节点保证控制器的唯一性和操作一致性:
在zk内还有一个和控制器相关的永久节点/controller_epoch,它记录着控制器变更的次数(纪元),初始值为1,每发生一次控制器节点的变更该值都会加1,每个和控制器交互的请求都会携带上controller_epoch这个值,如果请求的controller_epoch值小于控制器内存中的controller_epoch值,则认为这个请求是向已经过期的控制器所发送的请求,该请求就会被认定为无效的请求。如果请求的controller_epoch值大于控制器内存中的controller_epoch值,那么则说明已经有新的控制器当选了(脑裂),旧的控制器会主动下线。因此,Kafka通过controller_epoch来保证控制器的全局唯一性,进而保证相关操作的一致性。
Controller节点除了要负责和其他Broker节点一样的工作之外还需要负责下面的工作:
在上面提到kafka的topic是逻辑概念,partition是真实存储的物理概念,kafka通过 分段 + 索引 的方式提升查找效率。在磁盘上每个分区的数据是以文件夹的形式存储在broker节点的/data目录下,在每个partition(分区)下划分为多个segment(段),每个segment又分为一个.index文件和一个.log文件,.log文件内存储着生产者发送给该分区的实际数据和offset,每当生产者发送数据都会追加到.log文件的末端,.index内存储着.log文件的索引数据以提升消费者查询数据的性能。log文件大小在server.properties文件中可以配置。log.segment.bytes=1073741824(默认1GB),每当log文件达到配置的阈值就会新增一个segment(log文件和index文件)。
如上图展示了一个分区下的两个segment,其中segment-0已满配置的1GB大小,新来的数据进入segment-1。
命名方式:.index和.log文件名以当前segment所包含的最小的Offset值,长度20,不足的部分以0补全,如segment-0表示该段是从offset-0开始记录,segment-1表示该段从offset-667788开始记录。
.index文件:包含了.log数据文件的索引,建立offset到数据实际物理地址之间的映射关系,方便快速定位消息所在的物理文件位置。.log文件内各个消息体大小不一,非常影响检索的效率,而.index文件是固定格式长度的,因此利用二分查找法可以快速定位索引数据;
.log文件:存储实际消息数据,每条消息有固定格式:偏移量offset(8 Bytes)、消息体的大小(4 Bytes)、循环冗余校验crc32(4 Bytes)、版本号magic(1 Byte)、编码压缩attributes(1 Byte)、key length(4 Bytes)、key(K Bytes)、消费消息长度payload length(4 Bytes)等字段,通过这些值可以确定一条消息的大小;
定位数据的步骤:例如我们想要找offset为667790这条数据。
希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!