zookeeper

1 zookeeper是什么

参考文献:Zookeeper可以干什么
zookeeper为分布式应用程序提供一致性协调服务,包括配置维护、域名服务、分布式锁、集群管理等。

  • 配置维护
    同一个应用程序在不同服务器上的配置信息相同。将应用程序的配置信息存储在Zookeeper的某个结点上,让所有需要修改的服务器监控该信息的状态。
  • 域名服务
    服务特别多的时候,如果我们在本地保存服务的地址的时候将非常不方便,但是如果我们只需要访问一个大家都熟知的访问点,这里提供统一的入口,那么维护起来将方便得多了。
  • 分布式同步(指的是分布式锁,也叫共享锁)
    多个服务器同时收到客户端的指令,发生了并发情形,系统会出现并发操作,这时可以使用共享锁。(只有得到锁的客户端才能对数据进行修改,其余客户端只能等待。)
    .
    锁服务可以分为两类,一个是保持独占,另一个是控制时序。
    独占:把一个znode看作一把锁。所有客户端都去创建这个节点,创建成功的那个客户端也就拥有了这把锁。用完删掉自己创建的这个节点就释放出锁。
    对于第二类, 作为锁的节点已经存在,所有客户端在它下面创建临时顺序编号目录节点,编号最小的获得锁,用完删除。
  • 集群管理
    在集群中,有新的节点加入进来,也有老的节点退出集群。这个时候,集群中其他机器需要感知到这种变化。
    多个服务器组成一个集群,需要知道每台服务器的状态。Zookeeper的Leader结点就相当于集群的“总管”。
    例如:Kafka集群中的每个Broker就通过Zookeeper协调其他Broker,当Kafka集群中新增了Broker或者某个Broker失效,Zookeeper服务就把这个变换通知生产者和消费者,生产者和消费者就会据此协调与其他Broker的工作。
  • 队列管理
    传统的单进程中,使用队列在多线程间共享或传递数据。
    分布式环境下,也需要一个类似单进程队列的组件,用来实现跨进程、跨主机、跨网络的数据共享和数据传递,这就是我们的分布式队列。
    .
    zookeeper可以通过顺序节点实现分布式队列。
    Zookeeper可以处理两种类型的队列:同步队列、先入先出队列。
    同步队列:当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。
    先入先出队列:队列按照 FIFO 方式进行入队和出队操作。

zookeeper的架构及各节点的作用

角色 分工 数量
client客户端 请求发起方 不限
observer观察者 接受用户读写请求,写转发给leader,读直接返回(选主过程不参加投票) 不限
follower跟随者 接受用户读写请求,写转发给leader,读直接返回(选主过程参加投票) 奇数个(不可过多)
leader领导者 负责提议,更新系统状态 1个

如果客户端想要读取特定的znode,它将会向具有znode路径的节点发送读取请求,并且节点通过从其自己的数据库获取来返回所请求的znode。为此,在ZooKeeper集合中读取速度很快。

如果客户端想要将数据存储在ZooKeeper集合中,则会将znode路径和数据发送到服务器。连接的服务器将该请求转发给leader,然后leader将向所有的follower重新发出写入请求。如果只有大部分节点成功响应,而写入请求成功,则成功返回代码将被发送到客户端。 否则,写入请求失败。绝大多数节点被称为 Quorum 。

2 zookeeper的leader选举

(1)服务器启动时的leader选举
(2)服务器运行时的leader选举

  • 服务器启动时的leader选举
    (1)每个服务器发出一个投票,包括两个字段(myid,zxid),zxid是当前的leader编号,若没有leader就是0。
    (2)检查来自其他服务器的投票,检查是否是本轮投票,是否来自Looking状态的服务器。
    (3)比较投票
    优先检查zxid,如果zxid比较大的服务器优先作为leader。
    如果zxid相同,比较myid,myid大的服务器作为leader服务器。
    (4)重新投票
    如果自己的myid比较大,不需要更新自己的投票,直接投出去即可。
    如果对方的myid较大,需要更新自己的投票,然后再投出去。
  • 服务器运行时的leader选举
    (1)如果leader挂掉了,整个集群暂停对外服务,余下的非Observer服务器将自己的服务器状态变更为Looking,然后开始选举。
    (2)每个服务器发出一个投票,与启动时不同,此时zxid的值不同。后面的都与启动时相同了。

比较Kafka与zookeeper架构中leader与follower两种角色的差异

参考文献
[1] 比较Kafka与zookeeper架构中leader与follower两种角色的差异
[2] kafka 数据一致性-leader,follower机制与zookeeper的区别;

  • zookeeper
    leader 负责数据的读写,而follower只负责数据的,如果follower遇到写操作,会提交到leader;
    .
    其客户端根据链接的follower不同,可能读取到不同的数据。这是由于副本没有完全同步,存在时间差的原因。由于follower分担了读取数据的压力,zookeeper只要保留全局leader即可,不再进行细分。
  • Kafka
    只有leader 负责读写,follower只负责备份
    由kafka的使用场景决定,其读取数据时更关注数据的一致性
    从leader读取和写入可以保证所有客户端都得到相同的数据,

zookeeper在HBase中的作用

Zookeeper在Hbase中的工作原理和三次寻址详解

  • 解决HMaster的单点故障问题: Hbase中可以启动多达10个HMaster,通过ZooKeeper的Master Election机制保证任何时刻只有一个HMaster在运行。
  • 解决实时监控HRegionServer在线问题:HRegionServer的上、下线信息并及时通知HMaster,若有HRegionServer崩溃可以通过ZooKeeper来进行分配协调。
  • 解决快速Region寻址问题:ZooKeeper中存储了-ROOT-表的地址、HMaster的地址、HRegionServer地址、HBase的Schema和表的元数据,当Client连接到HBase时,需要首先访问ZooKeeper以获取这些核心数据。
    .
    元数据的原理介绍
    用户表被按行键分隔成不同的HRegion来保存,用户表的HRegion元数据被存储在.META表中,该表在HBase中也以HRegion的形式来进行存储。随着.META表中增多后,它也会被拆分成多个HRegion来保存,.META表中各个HRegion ID及其映射信息组成了HBase的-ROOT表,由ZooKeeper来记录-ROOT表的位置信息。-ROOT表永远不会被分割且只有一个HRegion,这样可以保证经过三次跳转就可以定位到任意一个HRegion:客户端访问用户数据时,首先访问ZooKeeper获得-ROOT表的位置,然后访问-ROOT表获得.META表的位置,最后根据.META表中的信息确定用户数据存放的位置。

zookeeper在Kafka中的作用

1、Broker注册

Broker是分布式部署并且相互之间相互独立,但是需要有一个注册系统能够将整个集群中的Broker管理起来,此时就使用到了Zookeeper。在Zookeeper上会有一个专门用来进行Broker服务器列表记录的节点:

/brokers/ids

每个Broker在启动时,都会到Zookeeper上进行注册,即到/brokers/ids下创建属于自己的节点,如/brokers/ids/[0…N]。

Kafka使用了全局唯一的数字来指代每个Broker服务器,不同的Broker必须使用不同的Broker ID进行注册,创建完节点后,每个Broker就会将自己的IP地址和端口信息记录到该节点中去。其中,Broker创建的节点类型是临时节点,一旦Broker宕机,则对应的临时节点也会被自动删除。

2、Topic注册

在Kafka中,同一个Topic的消息会被分成多个分区并将其分布在多个Broker上,这些分区信息及与Broker的对应关系也都是由Zookeeper在维护,由专门的节点来记录,如:

/borkers/topics

Kafka中每个Topic都会以/brokers/topics/[topic]的形式被记录,如/brokers/topics/login和/brokers/topics/search等。Broker服务器启动后,会到对应Topic节点(/brokers/topics)上注册自己的Broker ID并写入针对该Topic的分区总数,如/brokers/topics/login/3->2,这个节点表示Broker ID为3的一个Broker服务器,对于"login"这个Topic的消息,提供了2个分区进行消息存储,同样,这个分区节点也是临时节点。

3、生产者负载均衡

由于同一个Topic消息会被分区并将其分布在多个Broker上,因此,生产者需要将消息合理地发送到这些分布式的Broker上,那么如何实现生产者的负载均衡,Kafka支持传统的四层负载均衡,也支持Zookeeper方式实现负载均衡。

(1) 四层负载均衡,根据生产者的IP地址和端口来为其确定一个相关联的Broker。通常,一个生产者只会对应单个Broker,然后该生产者产生的消息都发往该Broker。这种方式逻辑简单,每个生产者不需要同其他系统建立额外的TCP连接,只需要和Broker维护单个TCP连接即可。但是,其无法做到真正的负载均衡,因为实际系统中的每个生产者产生的消息量及每个Broker的消息存储量都是不一样的,如果有些生产者产生的消息远多于其他生产者的话,那么会导致不同的Broker接收到的消息总数差异巨大,同时,生产者也无法实时感知到Broker的新增和删除。

(2) 使用Zookeeper进行负载均衡,由于每个Broker启动时,都会完成Broker注册过程,生产者会通过该节点的变化来动态地感知到Broker服务器列表的变更,这样就可以实现动态的负载均衡机制。

4、消费者负载均衡

与生产者类似,Kafka中的消费者同样需要进行负载均衡来实现多个消费者合理地从对应的Broker服务器上接收消息,每个消费者分组包含若干消费者,每条消息都只会发送给分组中的一个消费者,不同的消费者分组消费自己特定的Topic下面的消息,互不干扰。

5、分区 与 消费者 的关系

消费组 (Consumer Group):
consumer group 下有多个 Consumer(消费者)。
对于每个消费者组 (Consumer Group),Kafka都会为其分配一个全局唯一的Group ID,Group 内部的所有消费者共享该 ID。订阅的topic下的每个分区只能分配给某个 group 下的一个consumer(当然该分区还可以被分配给其他group)。
同时,Kafka为每个消费者分配一个Consumer ID,通常采用"Hostname:UUID"形式表示。

在Kafka中,规定了每个消息分区 只能被同组的一个消费者进行消费,因此,需要在 Zookeeper 上记录 消息分区 与 Consumer 之间的关系,每个消费者一旦确定了对一个消息分区的消费权力,需要将其Consumer ID 写入到 Zookeeper 对应消息分区的临时节点上,例如:

/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]

其中,[broker_id-partition_id]就是一个 消息分区 的标识,节点内容就是该 消息分区 上 消费者的Consumer ID。

6、消息 消费进度Offset 记录

在消费者对指定消息分区进行消息消费的过程中,需要定时地将分区消息的消费进度Offset记录到Zookeeper上,以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息消费。Offset在Zookeeper中由一个专门节点进行记录,其节点路径为:

/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]

节点内容就是Offset的值。

7、消费者注册

消费者服务器在初始化启动时加入消费者分组的步骤如下

注册到消费者分组。每个消费者服务器启动时,都会到Zookeeper的指定节点下创建一个属于自己的消费者节点,例如/consumers/[group_id]/ids/[consumer_id],完成节点创建后,消费者就会将自己订阅的Topic信息写入该临时节点。

对 消费者分组 中的 消费者 的变化注册监听。每个 消费者 都需要关注所属 消费者分组 中其他消费者服务器的变化情况,即对/consumers/[group_id]/ids节点注册子节点变化的Watcher监听,一旦发现消费者新增或减少,就触发消费者的负载均衡。

对Broker服务器变化注册监听。消费者需要对/broker/ids/[0-N]中的节点进行监听,如果发现Broker服务器列表发生变化,那么就根据具体情况来决定是否需要进行消费者负载均衡。

进行消费者负载均衡。为了让同一个Topic下不同分区的消息尽量均衡地被多个 消费者 消费而进行 消费者 与 消息 分区分配的过程,通常,对于一个消费者分组,如果组内的消费者服务器发生变更或Broker服务器发生变更,会发出消费者负载均衡。

以下是kafka在zookeep中的详细存储结构图:

zookeeper_第1张图片

zookeeper的负载均衡算法有哪些?

轮询:将请求按照顺序分发到每台服务器上,当其中一台服务器出现故障时,就不参加下一次的轮询,直至恢复正常。
比率:给每台服务器分配一个加权值为比例,根据比例来分配请求。
优先权:给所有的服务器分组,然后给每个组设置优先权,所有的请求先分配到优先权最高的服务器组,当该组出现故障后,请求再分配都次级优先权高的服务器组。
最少连接数:将请求分配到连接数最少的服务器
最快响应时间:将请求分配到响应时间最快的服务器

3 服务器状态

服务器具有四种状态,分别是LOOKING、FOLLOWING、LEADING、OBSERVING。
  LOOKING:寻找Leader状态。当服务器处于该状态时,它会认为当前集群中没有Leader,因此需要进入Leader选举状态。
  FOLLOWING:跟随者状态。表明当前服务器角色是Follower。
  LEADING:领导者状态。表明当前服务器角色是Leader。
  OBSERVING:观察者状态。表明当前服务器角色是Observer。

4 投票数据结构

每个投票中包含了两个最基本的信息,所推举服务器的SID和ZXID,投票(Vote)在Zookeeper中包含字段如下
  id:被推举的Leader的SID。
  zxid:被推举的Leader事务ID。
  electionEpoch:逻辑时钟,用来判断多个投票是否在同一轮选举周期中,该值在服务端是一个自增序列,每次进入新一轮的投票后,都会对该值进行加1操作。
  peerEpoch:被推举的Leader的epoch。
  state:当前服务器的状态。

5 zookeeper是如何保证事务的顺序一致性的?

zookeeper采用了全局递增的事务Id来标识,所有的proposal(提议)都在被提出的时候加上了zxid,zxid实际上是一个64位的数字,高32位是epoch(时期; 纪元; 世; 新时代)用来标识leader周期,如果有新的leader产生出来,epoch会自增,低32位用来递增计数。当新产生proposal的时候,会依据数据库的两阶段过程,首先会向其他的server发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。

6 Watcher机制

Watcher机制包括客户端线程、客户端WatcherManager和zookeeper服务器三部分。
客户端向zookeeper服务器注册Watcher,同时将这个Watcher对象存储在客户端的WatcherManager中。
服务器的指定事件触发了这个Watcher,服务器就会向客户端发送一个通知,客户端从WatcherManager中取出对应的Watcher对象来执行回调逻辑,从而实现分布式的通知功能。

zookeeper在HBase中的应用

你可能感兴趣的:(hadoop)