分别了解了【Kafka从入门到放弃系列 四】Kafka架构深入——生产者策略和【Kafka从入门到放弃系列 五】Kafka架构深入——消费者策略后我们来了解下Zookeeper是如何进行管理的。
Kafka高效读写数据
Kafka是如何保证高效读写数据的呢,有三点支持:分布式读写、顺序写磁盘以及零拷贝技术,其实前两点在之前的blog中也有提到
- 分布式读写,我们提到的各种策略都是为了满足分布式的可靠高效读写
- 顺序写磁盘,Kafka 的 producer 生产数据,要写入到 log 文件中,写的过程是一直追加到文件末端,为顺序写。同样的磁盘,顺序写能到 600M/s,而随机写只有 100K/s。这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。
- 零拷贝技术,简单来说就是数据不需要经过用户态,传统的文件读写或者网络传输,通常需要将数据从内核态转换为用户态。应用程序读取用户态内存数据,写入文件 / Socket之前,需要从用户态转换为内核态之后才可以写入文件或者网卡当中,而Kafka使用零拷贝技术让数据直接在内核态中进行传输。详细原理可以参照Kafka是如何利用零拷贝提高性能的
通过以上这几种技术可以实现Kafka的高并发读写
Zookeeper管理
在基于 Kafka 的分布式消息队列中,ZooKeeper 的作用有:Producer端注册及管理、Consumer端注册及管理以及Kafka集群策略管理 等。
Producer端注册及管理
在Producer端Zookeeper能够实现:注册并动态调整broker,注册并动态调整topic,Producers负载均衡。
注册并动态调整Broker
broker是注册在zookeeper中的,还记得在分布式集群搭建的时候,我们在zk的配置文件中添加的服务节点,就是用来注册broker的。
- 存放地址:为了记录 broker 的注册信息,在 ZooKeeper 上,专门创建了属于 Kafka 的一个节点,其路径为 /brokers
- 创建节点: Kafka 的每个 broker 启动时,都会到 ZooKeeper 中进行注册,告诉 ZooKeeper 其 broker.id,在整个集群中,broker.id 应该全局唯一,并在 ZooKeeper 上创建其属于自己的节点,其节点路径为
/brokers/ids/{broker.id}
; 创建完节点后,Kafka 会将该 broker 的 broker.name 及端口号记录到该节点; - 删除节点:该 broker 节点属性为临时节点,当 broker 会话失效时,ZooKeeper 会删除该节点,这样,我们就可以很方便的监控到broker 节点的变化,及时调整负载均衡等。
当然注册完Broker还需要注册Topic
注册并动态调整Topic
在 Kafka 中,所有 topic 与 broker 的对应关系都由 ZooKeeper 进行维护,在 ZooKeeper 中,建立专门的节点来记录这些信息,其节点路径为 /brokers/topics/{topic_name}
前面说过,为了保障数据的可靠性,每个 Topic 的 Partitions 实际上是存在备份的,并且备份的数量由 Kafka 机制中的 replicas 来控制。
Producers负载均衡
对于同一个 topic 的不同 partition,Kafka会尽力将这些 partition 分布到不同的 broker 服务器上,这种均衡策略实际上是基于 ZooKeeper 实现的。
- 监听broker变化,producers 启动后也要到 ZooKeeper 下注册,创建一个临时节点来监听 broker 服务器列表的变化。由于ZooKeeper 下 broker 创建的也是临时节点,当 brokers 发生变化时,producers 可以得到相关的通知,从改变自己的 broker list。
- 监听topic变化,topic 的变化以及broker 和 topic 的关系变化,也是通过 ZooKeeper 的 Watcher 监听实现的
当broker变化以及topic变化的时候,zookeeper能监听到,并控制消息和分区的分布。
Kafka集群策略管理
除了生产者涉及的管理行为,在我们前面提到的故障转移机制以及分区策略等内容中相关的其它管理行为也是由Zookeeper完成的
- 选举leader,Kafka 为每一个 partition 找一个节点作为 leader,其余备份作为 follower,如果 leader 挂了,follower 们会选举出一个新的 leader 替代,继续业务
- 副本同步,当 producer push 的消息写入 partition(分区) 时,作为 leader 的 broker(Kafka 节点) 会将消息写入自己的分区,同时还会将此消息复制到各个 follower,实现同步。
- 维护ISR,如果某个follower 挂掉,leader 会再找一个替代并同步消息
所有的这些操作都是Zookeeper做的。
Consumer端注册及管理
在Consumer端Zookeeper能够实现:注册并动态调整Consumer,Consumer负载均衡。
注册并动态调整consumer
在消费者端ZooKeeper 做的工作有那些呢?
- 注册新的消费者分组,当新的消费者组注册到 ZooKeeper 中时,ZooKeeper 会创建专用的节点来保存相关信息,其节点路径为
/consumers/{group_id}
,其节点下有三个子节点,分别为 [ids, owners, offsets]。
- ids 节点:记录该消费组中当前正在消费的消费者,记录分组下消费者
- owners 节点:记录该消费组消费的 topic 信息,
/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]
,其中,[broker_id-partition_id]
就是一个消息分区的标识,节点内容就是该 消息分区上消费者的Consumer ID,这样分区和消费者就能关联起来了。关联分区和消费者 - offsets 节点:记录每个 topic 的每个分区offset,在消费者对指定消息分区进行消息消费的过程中,需要定时将分区消息的消费进度Offset记录到Zookeeper上,以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能从之前进度继续消息消费。Offset在Zookeeper中由一个专门节点进行记录,其节点路径为:
/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]
节点内容就是Offset的值,记录消费者offset,当然新版本的不记录在zookeeper中
- 注册新的消费者,当新的消费者注册到 Kafka 中时,会在
/consumers/{group_id}/ids
节点下创建临时子节点,并记录相关信息。 - 监听消费者分组中消费者的变化,每个消费者都要关注其所属消费者组中消费者数目的变化,即监听
/consumers/{group_id}/ids
下子节点的变化。一但发现消费者新增或减少,就会触发消费者的负载均衡。
其实不光是注册consumer,还包括对消费者策略的管理,例如Consumer负载均衡
Consumer负载均衡
Consumer在启动时会到 ZooKeeper下以自己的 Consumer-id 创建临时节点 /consumer/[group-id]/ids/[conusmer-id]
,并对 /consumer/[group-id]/ids
注册监听事件:
- 监听消费者列表,当消费者发生变化时,同一 group 的其余消费者会得到通知。
- 监听broker列表,消费者还要监听 broker 列表的变化。
然后按照我们之前提到的策略进行排序和消费