kafka系列:kafka各组件详解

1、producer生产者

 

1.1 写入方式

    producer 采用 push 模式将消息发布到 broker,每条消息都被 append 到 patition 中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障 kafka 吞吐率)。

1.2 消息路由

    producer 发送消息到 broker 时,会根据分区算法选择将其存储到哪一个 partition。其路由机制为:
    (1) 指定了 patition的id,则直接使用;

    (2)未指定 patition 但指定 key,通过对 key 做hashcode,然后和分区数做模运算,得到分区索引;

    (3) patition 和 key 都未指定,使用轮询选出一个 patition;

1.3数据写入流程

 

kafka系列:kafka各组件详解_第1张图片

    流程说明:
    1. producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的 leader
    2. producer 将消息发送给该 leader
    3. leader 将消息写入本地 log
    4. followers 从 leader pull 消息,写入本地 log 后 leader 发送 ACK

    5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset) 并向 producer 发送     ACK

 

1.4 producer delivery guarantee

     一般情况下存在三种情况:
    1. At most once 消息可能会丢,但绝不会重复传输
    2. At least one 消息绝不会丢,但可能会重复传输
    3. Exactly once 每条消息肯定会被传输一次且仅传输一次

    当 producer 向 broker 发送消息时,一旦这条消息被 commit,由于 replication 的存在,它就不会丢。但是如果 producer 发送数据给 broker 后,遇到网络问题而造成通信中断,那 Producer 就无法判断该条消息是否已经 commit。虽然 Kafka 无法确定网络故障期间发生了什么,但是 producer 可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了 Exactly once,但目前还并未实现。所以目前默认情况下一条消息从 producer 到 broker 是确保了 At least once,可通过设置 producer 异步发送实现At most once。

2、broker

    2.1 存储方式

    物理上把 topic 分成一个或多个 patition(对应 server.properties 中的 num.partitions=3 配置),每个 patition 物理上对应一个文件夹(该文件夹存储该 patition 的所有消息和索引文件),如下:

kafka系列:kafka各组件详解_第2张图片

 

2.2 存储策略

无论消息是否被消费,kafka 都会保留所有消息。有两种策略可以删除旧数据:
1. 基于时间:log.retention.hours=168
2. 基于大小:log.retention.bytes=1073741824
需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关。

2.3 topic 创建与删除

2.3.1 创建 topic

创建 topic 的序列图如下所示:

kafka系列:kafka各组件详解_第3张图片

 

流程说明:

    1. controller 在 ZooKeeper 的 /brokers/topics 节点上注册 watcher,当 topic 被创建,则 controller 会通过 watch 得到该     topic 的 partition/replica 分配。

    2. controller从 /brokers/ids 读取当前所有可用的 broker 列表,对于 set_p 中的每一个 partition:
2.1 从分配给该 partition 的所有 replica(称为AR)中任选一个可用的 broker 作为新的 leader,并将AR设置为新的 ISR
2.2 将新的 leader 和 ISR 写入 /brokers/topics/[topic]/partitions/[partition]/state
    3. controller 通过 RPC 向相关的 broker 发送 LeaderAndISRRequest。
 

2.3.2 删除 topic

删除 topic 的序列图如下所示:

kafka系列:kafka各组件详解_第4张图片

    流程说明:
    1. controller 在 zooKeeper 的 /brokers/topics 节点上注册 watcher,当 topic 被删除,则 controller 会通过 watch 得到该     topic 的 partition/replica 分配。

    2. 若 delete.topic.enable=false,结束;否则 controller 注册在 /admin/delete_topics 上的 watch 被 fire,controller 通过回调向对应的 broker 发送 StopReplicaRequest。

 

 

3、kafka HA

3.1 replication

    如图所示,同一个 partition 可能会有多个 replica(对应 server.properties 配置中的 default.replication.factor=N)。没有 replica 的情况下,一旦 broker 宕机,其上所有 patition 的数据都不可被消费,同时 producer 也不能再将数据存于其上的 patition。引入replication 之后,同一个 partition 可能会有多个 replica,而这时需要在这些 replica 之间选出一个 leader,producer 和 consumer 只与这个 leader 交互,其它 replica 作为 follower 从 leader 中复制数据。

Kafka 分配 Replica 的算法如下:
    1. 将所有 broker(假设共 n 个 broker)和待分配的 partition 排序
    2. 将第 i 个 partition 分配到第(i mod n)个 broker 上
    3. 将第 i 个 partition 的第 j 个 replica 分配到第((i + j) mode n)个 broker上

3.2 leader failover

    当 partition 对应的 leader 宕机时,需要从 follower 中选举出新 leader。在选举新leader时,一个基本的原则是,新的 leader 必须拥有旧 leader commit 过的所有消息。

kafka 在 zookeeper 中(/brokers/.../state)动态维护了一个 ISR(in-sync replicas),由3.3节的写入流程可知 ISR 里面的所有 replica 都跟上了 leader,只有 ISR 里面的成员才能选为 leader。对于 f+1 个 replica,一个 partition 可以在容忍 f 个 replica 失效的情况下保证消息不丢失。

 

当所有 replica 都不工作时,有两种可行的方案:
    1. 等待 ISR 中的任一个 replica 活过来,并选它作为 leader。可保障数据不丢失,但时间可能相对较长。
    2. 选择第一个活过来的 replica(不一定是 ISR 成员)作为 leader。无法保障数据不丢失,但相对不可用时间较短。
kafka 0.8.* 使用第二种方式。

kafka 通过 Controller 来选举 leader,流程请参考5.3节。

 

3.3 broker failover

kafka broker failover 序列图如下所示:

kafka系列:kafka各组件详解_第5张图片
    流程说明: 
    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节所描述)
        4.3 将新 leader、ISR、controller_epoch 和 leader_epoch 等信息写入 state 节点
    5. 通过 RPC 向相关 broker 发送 leaderAndISRRequest 命令

 

3.4 controller failover

     当 controller 宕机时会触发 controller failover。每个 broker 都会在 zookeeper 的 "/controller" 节点注册 watcher,当 controller 宕机时 zookeeper 中的临时节点消失,所有存活的 broker 收到 fire 的通知,每个 broker 都尝试创建新的 controller path,只有一个竞选成功并当选为 controller。

 

当新的 controller 当选时,会触发 KafkaController.onControllerFailover 方法,在该方法中完成如下操作:
    1. 读取并增加 Controller Epoch。
    2. 在 reassignedPartitions Patch(/admin/reassign_partitions) 上注册 watcher。
    3. 在 preferredReplicaElection Path(/admin/preferred_replica_election) 上注册 watcher。
    4. 通过 partitionStateMachine 在 broker Topics Patch(/brokers/topics) 上注册 watcher。
    5. 若 delete.topic.enable=true(默认值是 false),则 partitionStateMachine 在 Delete Topic Patch(/admin/delete_topics) 上注册 watcher。
    6. 通过 replicaStateMachine在 Broker Ids Patch(/brokers/ids)上注册Watch。
    7. 初始化 ControllerContext 对象,设置当前所有 topic,“活”着的 broker 列表,所有 partition 的 leader 及 ISR等。
    8. 启动 replicaStateMachine 和 partitionStateMachine。
    9. 将 brokerState 状态设置为 RunningAsController。
    10. 将每个 partition 的 Leadership 信息发送给所有“活”着的 broker。
    11. 若 auto.leader.rebalance.enable=true(默认值是true),则启动 partition-rebalance 线程。
    12. 若 delete.topic.enable=true 且Delete Topic Patch(/admin/delete_topics)中有值,则删除相应的Topic。

你可能感兴趣的:(kafka)