0%

zookeeper I

成功的奥秘在于目标的坚定。——迪斯雷利

zookeeper一般的使用场景

分布式一般都会考虑到分布式锁,而zookeeper是用在分布式锁里很常用的。

大致来说,zk的使用场景如下:

(1)分布式协调:这个其实是zk很经典的一个用法,简单来说,就好比,你A系统发送个请求到mq,然后B消息消费之后处理了。那A系统如何知道B系统的处理结果?用zk就可以实现分布式系统之间的协调工作。A系统发送请求之后可以在zk上对某个节点的值注册个监听器,一旦B系统处理完了就修改zk那个节点的值,A立马就可以收到通知,完美解决。

zookeeper一开始的定位就是做分布式协调。让多个系统协调起来,某个系统要感知另一个系统当前的处理结果和状态。

分布式协调如下图:

01_zookeeper的分布式协调场景.png

(2)分布式锁:对某一个数据连续发出两个修改操作,两台机器同时收到了请求,但是只能一台机器先执行另外一个机器再执行。那么此时就可以使用zk分布式锁,一个机器接收到了请求之后先获取zk上的一把分布式锁,就是可以去创建一个znode,接着执行操作;然后另外一个机器也尝试去创建那个znode,结果发现自己创建不了,因为被别人创建了。。。。那只能等到另一个机器执行完,把锁释放掉,后来的机器才能执行。

分布式锁如下图:

02_zookeeper的分布式锁场景.png

(3)元数据/配置信息管理:zk可以用作很多系统的配置信息的管理,比如kafka、storm等等很多分布式系统都会选用zk来做一些元数据、配置信息的管理,包括dubbo注册中心也支持zk

举例,服务A在三台机器上,这些数据放到了dubbo数据中心,然后dubbo会基于zookeeper的元数据来保存这个配置信息,此后只要数据有了变化,zookeeper会实时监听,并且把更新的数据告诉调用者。

实际上,消息队列Kafka,流式计算引擎Storm,都基于zookeeper的元数据管理。

03_zookeeper的元数据_配置管理场景.png

(4)HA高可用性:就是实现主备系统。这个应该是很常见的,比如hadoop、hdfs、yarn等很多大数据系统,都选择基于zk来开发HA高可用机制,就是一个重要进程一般会做主备两个,主进程挂了立马通过zk感知到切换到备用进程

04_zookeeper的HA高可用性场景.png

临时节点名字是active,具体可以被设置成active是worker01或者work02。

一开始设置成了worker01,那么只由worker01工作,但是如果worker01挂掉了,那么这个临时节点会被ZK删除掉,然后重新定义一个新的active节点,并且赋值为worker02。

Zookeeper内部原理(面试重点)

Zookeeper选举机制(详细算法参考paxos)

选举机制,即如何选出集群中的Leader(集群中只有一个Leader,其他都是follower)。

1)半数机制:只有集群中半数以上机器存活,集群才能可用。所以zookeeper适合安装奇数台服务器

举个例子,如果你集群中有5台机器,那么挂掉2台还可以工作,挂掉3台就不行了。如果集群有6台机器,那么挂掉3台也不可以工作了,所以一般建议配成奇数台机器。

2)Zookeeper虽然在配置文件中并没有指定Master和Slave,但是ZK工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内布的选举机制临时产生的。

3)以一个简单的例子说明选举过程

假设现在有五台服务器组成的ZK集群,它们的id从1-5,同时它们都是最新启动的,即没有历史数据,而且每台机器存放的数据量也是一样的。假设这些服务器依序启动,会发生什么?如何选举?

五台机器如下图所示:

ZK选举.png

一开始,第一台机器Server1启动,会自动投自己一票,但是因为此时节点数量未过半,所以节点1处于Looking状态。后面Server2启动,也会投自己,然后Server1会投给2,因为id最大,但是因为未过半所以还是处于Looking状态。后面类似,后面来的,myid大的,就投票给它。

但是注意,只要Leader选出来了,就是既定事实,不能变了。

所以,当每个机器新加入集群的时候,首先会投票给自己,如果票投给自己选不出来Leader,那么会把它这一票投给id号大的。一旦某个机器得到的选票过半,它就是leader,后面再加入机器,也不能是Leader,因为Leader已经定了。(注意,ZK启动的时候知道有多少台服务器,因为你已经写了数据到ZK的配置文件里了

Zookeeper节点类型

一共分为两大类,四种。

持久节点(Persistent):客户端和服务端断开连接后,创建的节点不删除。

持久类节点分为两种:

  • 持久化目录节点:客户端与ZK断开连接后,该节点仍然存在
  • 持久化顺序编号目录节点:客户端与ZK断开连接后,该节点依旧存在,只是ZK会对该节点名称进行书序编号。

说明:创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护。而有顺序号的节点有一个用处:顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序

临时节点(Ephemeral):客户端和服务端断开连接后,创建的节点会被自己删除。

临时节点也分为两类:

  • 临时目录节点:客户端与ZK断开连接后,该节点被删除
  • 临时顺序编号目录节点:客户端与ZK断开连接后,该节点被删除,只是ZK给该节点名称进行顺序编号。

为什么有的节点要在断开连接后删除?——有必要,有一些服务器记录的是其他服务器是否在线的数据,所以如果节点断开连接后,删除记录,那么查询的时候查不到数据,说明用户已经下线。

四种类型的节点如下图所示:

节点类型.png

Zookeeper监听器原理(详细参考Raft算法)

ZK监听器经常会被用到,因为其用到了观察者模式。

监听器会按照以下步骤工作

1)创建main()线程

2)在main线程中创建zookeeper客户端对象(主要用于访问server服务器),这时就会创建两个线程,一个负责正常业务通讯,即网络连接通信(connect),一个负责监听(listener)。

3)通过connect线程将注册的监听事件发送给zookeeper

4)在zookeeper注册监听器列表中将注册的监听事件添加到列表中

5)zookeeper监听到有数据或者路径变化,就会回调main()线程,将这个消息发送给listener线程,告诉客户端现在有事情发生,要处理。

6)listener线程内部调用process()方法

如下图所示:

常见监听方式.png

常见监听方式

1)监听节点数据的变化:get path [watch]

2)监听子节点增减的变化:ls path [watch]

分布式锁是什么?

对比下redis和zk两种分布式锁的优劣?