图解kafka - 设计原理解析 (2)

log-segment

index采用稀疏存储的方式,它不会为每一条message都建立索引,而是每隔一定的字节数建立一条索引,避免索引文件占用过多的空间。缺点是没有建立索引的offset不能一次定位到message的位置,需要做一次顺序扫描,但是扫描的范围很小。

索引包含两个部分(均为4个字节的数字),分别为相对offset和position。相对offset表示segment文件中的offset,position表示message在数据文件中的位置。

总结:Kafka的Message存储采用了分区(partition),磁盘顺序读写,分段(LogSegment)和稀疏索引这几个手段来达到高效性

Partition and Replica

一个topic物理上分为多个partition,位于不同的broker上。如果没有 replica,一旦broker宕机,其上所有的patition将不可用。

每个partition可以有多个replica(对应server.properties/default.replication.factor),分配到不同的broker上,其中有一个leader负责读写,处理来自producer和consumer的请求;其它作为follower从leader pull消息,保持与leader的同步。

如何分配partition和replica到broker上

将所有Broker(假设共n个Broker)和待分配的Partition排序

将第i个Partition分配到第(i mod n)个Broker上

将第i个Partition的第j个Replica分配到第((i + j) mode n)个Broker上

根据上面的分配规则,若replica的数量大于broker的数量,必定会有两个相同的replica分配到同一个broker上,产生冗余。因此replica的数量应该小于或等于broker的数量。

leader选举

kafka 在 zookeeper 中(/brokers/topics/[topic]/partitions/[partition]/state)动态维护了一个 ISR(in-sync replicas),ISR 里面的所有 replica 都"跟上"了 leader,controller将会从ISR里选一个做leader。具体流程如下:

1. controller 在 zookeeper 的 /brokers/ids/[brokerId] 节点注册 Watcher,当 broker 宕机时 zookeeper 会 fire watch 2. controller 从 /brokers/ids 节点读取可用broker 3. controller决定set_p,该集合包含宕机 broker 上的所有 partition 4. 对 set_p 中的每一个 partition 4.1 从/brokers/topics/[topic]/partitions/[partition]/state 节点读取 ISR 4.2 决定新 leader 4.3 将新 leader、ISR、controller_epoch 和 leader_epoch 等信息写入 state 节点 5. 通过 RPC 向相关 broker 发送 leaderAndISRRequest 命令

当ISR为空时,会选一个 replica(不一定是 ISR 成员)作为leader;当所有的 replica 都歇菜了,会等任意一个 replica 复活,将其作为leader。

ISR(同步列表)中的follower都"跟上"了leader,"跟上"并不表示完全一致,它由 server.properties/replica.lag.time.max.ms 配置,表示leader等待follower同步消息的最大时间,如果超时,leader将follower移除ISR。

配置项 replica.lag.max.messages 已经移除

replica同步

kafka通过"拉模式"同步消息,即follower从leader批量拉取数据来同步。具体的可靠性,是由生产者(根据配置项producer.properties/acks)来决定的。

In Kafka 0.9, request.required.acks=-1 which configration of producer is replaced by acks=all, but this old config is remained in docs.(在0.9版本,生产者配置项 request.required.acks=-1 被 acks=all 取代,但是老的配置项还保留在文档中。ps: 最新的文档2.2.x request.required.acks 已经不存在了)

acks description
0   producer发送消息后直接返回,不会等待服务器确认  
1   服务器将记录写进本地log后返回,不会等待follower同步消息。leader宕机后可能丢失一部分未同步的消息  
-1/all   服务器将记录写进本地log后,等待所有ISR内的消息同步后返回。除非leader和所有的ISR都挂掉,否则消息不会丢失  

在acks=-1的时候,如果ISR少于min.insync.replicas指定的数目,将会抛出NotEnoughReplicas或NotEnoughReplicasAfterAppend异常。

Prodecer如何发送消息

Producer首先将消息封装进一个ProducerRecord实例中。

producer-record

消息路由

发送消息时如果指定了partition,则直接使用;

如果指定了key,则对key进行哈希,选出一个partition。这个hash(即分区机制)由producer.properties/partitioner.class指定的类实现,这个路由类需要实现Partitioner接口;

如果都未指定,通过round-robin来选partition。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzdzd.html