zookeeper介绍

zk的数据结构

zk类似于linux文件系统的树结构,树的基本组成单位是一个个Znode结点,每一个节点可以通过路径来标识,每个znode都由value值和next指针构成,如果znode的value值为空,那么该节点只相当于一个目录,Znode分为两种类型

  • 时节点(Ephemeral):当客户端和服务端断开连接后,所创建的Znode(节点)会自动删除
  • 持久节点(Persistent):当客户端和服务端断开连接后,所创建的Znode(节点)不会删除

查看zk树结构的命令是ls,查看zk节点值的命令是get

zk监听器

  • 监听Znode节点的数据变化
  • 监听子节点的增减变化

zk的应用

zk的底层实现主要就是依靠监听器+ zk的数据结构,可以应用于以下几点

  • 基于zookeeper实现统一配置管理
  • 统一命名服务
  • 分布式锁
  • 集群状态感知

临时节点与持久节点

Node 可以分为持久节点和临时节点两类。所谓持久节点是指一旦这个 ZNode 被创建了,除非主动进行 ZNode 的移除操作,否则这个 ZNode 将一直保存在 ZooKeeper 上。而临时节点就不一样了,它的生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。

事件监听器

Watcher(事件监听器),是 ZooKeeper 中的一个很重要的特性。ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。

zk分布式架构

ZooKeeper 采用的是主从模式,有主节点和从节点。从设计模式的角度,它是一个基于观察者模式设计的分布式服务管理框架,负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,ZooKeeper 就将负责通知已经注册的那些观察者做出相应的反应。

zk架构中的角色

ZooKeeper 中的角色包括 Leader、Follower、Observer。Leader 是集群主节点,主要负责管理集群状态和接收用户的写请求;Follower 是从节点,主要负责集群选举投票和接收用户的读请求;Observer 的功能与 Follower 类似,只是没有投票权,主要用于分担 Follower 的读请求,降低集群的负载。

zk在kafka中的体现

相关配置

kafka的启动文件server.properties中,会指定注册zk服务或zk集群的地址,默认连接的zk地址是localhost:2181

<!- 启动了一个brokerId = 0 的kafka服务 -->
kafka-server-start.bat ..\..\config\server.properties

所以启动kafka前一点要保证zk服务或集群是运行中的,否则kafka无法成功启动

观察kafka启动日志会发现kafka启动的第一时间就是与zk建立一次连接并生成一个临时session会话

Zookeeper对Kafka的作用 zookeeper kafka关系_java


kafka启动时,与zk建立会话的过程中,kafka会主动在zk的 /broker/ids路径下注册生成临时结点 /broker/ids/0,并且把会话信息存入到结点的value中,如下,会话信息中包括

  • 监听协议(plaintxt纯文本协议)
  • 连接点ip和port,即kafka地址,我这边默认是loocalhost:9092

需要注意

1、每次使用完毕需要主动关闭kafka服务

kafka-server-stop.bat ..\..\config\server.properties

只有我们主动关闭kafka服务时才会去删除这个zk中存储的结点 /broker/ids/0,否则下次启动kafka时发现上次会话创建的结点 /broker/ids/0还在,就会报错

Zookeeper对Kafka的作用 zookeeper kafka关系_zookeeper_02


此时需要通过连接zk客户端,手动删除这个临时结点的方式来解决报错

deleteall /brokers/ids/0

kafka leader选举

Kakfa Broker集群受Zookeeper管理。所有的Kafka Broker节点一起去Zookeeper上注册一个临时节点,kafk集群中的所有服务会以共同注册zk中的/controller来竞争kafka的leader角色,因为只有一个Kafka Broker会注册成功,其他的都会失败,所以这个成功在zk的/controller目录上注册临时节点的这个Kafka Broker会被选举为Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。也就是为/Controller节点在ZooKeeper注册Watch。

zk中监听器对kafka的作用(记录ISR)

zk的监听器会监听其他的Kafka Broker的所有信息,一旦有一个broker宕机了,这个kafka broker controller会读取该宕机broker上所有的partition在zookeeper上的状态,并选取ISR列表中的一个replica作为partition leader(如果ISR列表中的replica全挂,选一个幸存的replica作为leader; 如果该partition的所有的replica都宕机了,则将新的leader设置为-1,等待恢复,等待ISR中的任一个Replica“活”过来,并且选它作为Leader;或选择第一个“活”过来的Replica(不一定是ISR中的)作为Leader),这个broker宕机的事情,kafka controller也会通知zookeeper,zookeeper就会通知其他的kafka broker。

zk中临时节点对kafka的意义

每个Broker服务器在启动时,都会到Zookeeper上进行注册,即创建/brokers/ids/[0-N]的节点,然后写入IP,端口等信息,Broker创建的是临时节点,所以一旦Broker下线,对应Broker节点也就被删除了,因此我们可以通过zookeeper上Broker节点的变化来动态表征Broker服务器的可用性,Kafka的Topic也类似于这种方式。

kafka和zookeeper的整体架构

在Kafka的设计中,选择了使用Zookeeper来进行所有Broker的管理,kafka配置文件中有关kafka和zookeeper的配置如下,意思是每个broker上的本地zookeeper都会注册整个kafka集群的服务信息

zookeeper.connect=localhost:2181

kafka在zk上的配置总览

/brokers/ids专门用来进行kafka集群服务器列表记录的点;
/brokers/topics专门用来记录kafka集群服务器中的全部topic;
   /brokers/topics/{topicName}:记录名为xxx的topic
        /brokers/topics/topic-n/partitions:记录每个topic下的全部分区信息,包括一个【offse】
             /brokers/topics/topic-n/partitions/{partitionNo}:0代表0号分区,1代表1号分区,以此类推
                  /brokers/topics/topic-n/partitions/{partitionNo}/state:存储中央控制器controller选取次数、leader partition所在broker的id,leader选举此时,初始时0,isr信息

/controller:kafka 存储服务器集群注册到zookeeper时成为controller的broker这个节点信息
/controller_epcho:kafka 存储服务器集群注册到zookeeper时成为controller的broker这个节点信息

Zookeeper对Kafka的作用 zookeeper kafka关系_java_03

注意点

0.9之前offset存储在zk下,也就是consumer相关的信息存在zk下的/consumers目录下了,但是0.9版本后consumer的信息存储在了brokers上的一块内存中了 /brokers/topics/__consumer_offsets/下存储,其中offset时以topic的分区为单位进行存储的

/brokers/ids目录下生成的节点是临时结点,存储的是kafka服务的连接信息
/brolers/topics下存储kafka的topic信息,是永久性节点,例如创建了name为test的topic

kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test

消费者生产者负载均衡

生产者需要将消息合理的发送到分布式Broker上,这就面临如何进行生产者负载均衡问题。对于生产者的负载均衡,Kafka支持传统的4层负载均衡,zookeeper同时也支持zookeeper方式来实现负载均衡。

  • 根据生产者的IP地址和端口来为其定一个相关联的Broker,通常一个生产者只会对应单个Broker,只需要维护单个TCP链接。这样的方案有很多弊端,因为在系统实际运行过程中,每个生产者生成的消息量,以及每个Broker的消息存储量都不一样,那么会导致不同的Broker接收到的消息量非常不均匀,而且生产者也无法感知Broker的新增与删除。
  • 使用zookeeper进行负载均衡
    很简单,生产者通过监听zookeeper上Broker节点感知Broker,Topic的状态,变更,来实现动态负载均衡机制,当然这个机制Kafka已经结合zookeeper实现了。

kafka日志数据分离操作

原因:kafka中的数据存储配置字段为logs.dir,容易让人误解为日志,事实上kafka的日志和数据都是存在/kafka/logs下的,需要手动进行分离,但并非一定要分离,看个人爱好

  • 删除kafka集群下kafka/logs文件夹
  • 删除zk集群下的zookeeper/zkData中的version文件

数据分离后创建一个分区数何副本数都为2的topic first,那么/kafka-data下会生成first-0和first-1两份数据文件分别代表first两个分区的文件,另外的两个副本分别在其它位置,这里起到了数据库的作用,在一段时间内存储数据 => 主题是逻辑上的,分区时物理上的

kafka的每个分区数据如果不加以控制就会无限堆积,所以kafka的分区存在分片机制即每超过1g就进行分片segement,每个分片单独具有一个log和一个index,log是实实在在存储数据的,index可以看着是log的索引

Zookeeper对Kafka的作用 zookeeper kafka关系_java_04


00000000000000170410.log这个文件记录了第170411到~(下一个log文件编号)的消息。

00000000000000170410.index:假设这个消息中有N条消息,第3条消息在index文件中对应的是348,也就是说在log文件中,第3条消息的偏移量为348。

zk作用小结

  • zk 为 Kafka 提供了元数据的管理,例如一些 Broker 的信息、主题数据、分区数据等等
  • zk辅助kafka中leader选举,

kafka新版本