Zookeeper客户端
Zookeeper客户端提供了基本的操作,比如,创建会话、创建节点、读取节点、更新数据、删除节点和检查节点是否存在等。但对于开发人员来说,Zookeeper提供的基本操纵还是有一些不足之处,比如Session超时之后没有实现重连机制、异常处理繁琐、Watcher是一次性等等。但是好在社区提供了两款十分强大的ZK客户端:ZKClient和Curator。
- ZkClient是一个开源客户端,在Zookeeper原生API接口的基础上进行了包装,更便于开发人员使用。内部实现了Session超时重连,Watcher反复注册等功能。像dubbo等框架对其也进行了集成使用。
- Curator是Netflix公司开源的一套Zookeeper客户端框架,和ZkClient一样,解决了非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等。目前已经成为Apache的顶级项目。另外还提供了一套易用性和可读性更强的Fluent风格的客户端API框架。除此之外,Curator中还提供了Zookeeper各种应用场景(Recipe,如共享锁服务、Master选举机制和分布式计算器等)的抽象封装。
1、集群管理
所谓集群管理无外乎两点是否有机器退出和加入、选举master。应用集群中,我们常常需要让每一个机器知道集群中哪些机器是活着的,并且在集群机器因为宕机,网络断链等原因能够不在人工介入的情况下迅速通知到每一个机器。
Zookeeper同样很容易实现这个功能,比如我在Zookeeper服务器端有一个znode叫/GroupMembers,那么集群中每一个机器启动的时候都去这个节点下创建一个EPHEMERAL类型的节点,比如server1创建/GroupMembers/client1(可以使用IP,保证不重复),server2创建/GroupMembers/client2,然后SERVER1和SERVER2都watch /GroupMembers,那么也就是这个父节点下数据或者子节点变化都会通知对该节点进行watch的客户端。因为EPHEMERAL类型节点有一个很重要的特性,就是客户端和服务器端连接断掉或者session过期就会使节点消失,那么在某一个机器挂掉或者断链的时候,其对应的节点就会消失,然后集群中所有对/GroupMembers进行watch的客户端都会收到通知,然后取得最新列表即可。
另外有一个应用场景就是集群选master,一旦master挂掉能够马上能从slave中选出一个master,实现步骤和前者一样,只是机器在启动的时候在APP1SERVERS创建的节点类型变为EPHEMERAL_SEQUENTIAL类型,这样每个节点会自动被编号。我们默认规定编号最小的为master,所以当我们对/APP1SERVERS节点做监控的时候,得到服务器列表,只要所有集群机器逻辑认为最小编号节点为master,那么master就被选出,而这个master宕机的时候,相应的znode会消失,然后新的服务器列表就被推送到客户端,然后每个节点逻辑认为最小编号节点为master,这样就做到动态master选举。
如果"主节点-A"挂了,这时候他所注册的节点将被自动删除,ZooKeeper会自动感知节点的变化,然后再次发出选举,这时候"主节点-B"将在选举中获胜,替代"主节点-A"成为主节点。如果主节点恢复了,他会再次向ZooKeeper注册一个节点,这时候他注册的节点将会是"master-00003",ZooKeeper会感知节点的变化再次发动选举,这时候"主节点-B"在选举中会再次获胜继续担任"主节点","主节点-A"会担任备用节点。
2、分布式锁
在我们日常的开发中,如果是单个进程中对共享资源的访问,我们只需要用synchronized或者lock就能实现互斥操作。但是对于跨进程、跨主机、跨网络的共享资源似乎就无能为力了。
实现思路:
- 1、首先zookeeper中我们可以创建一个/distributed_lock持久化节点
- 2、然后再在/distributed_lock节点下创建自己的临时顺序节点,比如:/distributed_lock/task_00000000008
- 3、获取所有的/distributed_lock下的所有子节点,并排序
- 4、判读自己创建的节点是否最小值(第一位)
- 5、如果是,则获取得到锁,执行自己的业务逻辑,最后删除这个临时节点。
- 6、如果不是最小值,则需要监听自己创建节点前一位节点的数据变化,并阻塞。
- 7、当前一位节点被删除时,我们需要通过递归来判断自己创建的节点是否在是最小的,如果是则执行5);如果不是则执行6)(就是递归循环的判断)
3、配置中心
集中式的配置管理在应用集群中是非常常见的,一般商业公司内部都会实现一套集中的配置管理中心,应对不同的应用集群对于共享各自配置的需求,并且在配置变更时能够通知到集群中的每一个机器。将全局配置项全部放入到Zookeeper上,保存在Zookeeper某个目录节点中,然后相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序都会收到通知,然后从Zookeeper中获取新的配置信息更新到应用系统中,可以结合Netflix Archaius使用更容易实现配置中心。
4、服务注册与发现
利用Zookeeper的临时节点特性,所有的服务提供者在持久化父节点/services/service1下创建临时节点,znode数据包含服务提供者的IP、端口、请求地址、接口名、服务根路径、服务组等信息。新的服务节点加入时向该父节点下注册服务提供者信息,服务下线时与Zookeeper失去心跳连接,Zookeeper自动将该服务节点删除。服务调用者获取/services/service1下所有的服务提供者列表信息,根据负载均衡策略和服务治理策略选取一个服务调用者发起调用。
5、负载均衡
首先我们需要简单的理解分布式和集群,通俗点说:分布式就是将一个系统拆分到多个独立运行的应用中(有可能在同一台主机也有可能在不同的主机上),集群就是将单个独立的应用复制多分放在不同的主机上来减轻服务器的压力。而Zookeeper不仅仅可以作为分布式集群的服务注册调度中心(例如dubbo),也可以实现集群的负载均衡。
- 1、首先我们要理解,如果是一个集群,那么他就会有多台主机。所以,它在Zookeeper中信息的存在应该是如下所示:
- 2、如上的结构,当服务调用方调用服务时,就可以根据特定的均衡负载算法来实现对服务的调用(调用前需要监听/services/serviceXXX节点,以更新列表数据),即可实现轮询、随机、加权轮询、最小活跃等负载均衡策略。
6、分布式队列
在日常使用中,特别是像生产者消费者模式中,经常会使用BlockingQueue来充当缓冲区的角色。但是在分布式系统中这种方式就不能使用BlockingQueue来实现了,但是Zookeeper可以实现。
- 1、首先利用Zookeeper中临时顺序节点的特点
- 2、当生产者创建节点生产时,需要判断父节点下临时顺序子节点的个数,如果达到了上限,则阻塞等待;如果没有达到,就创建节点。
- 3、当消费者获取节点时,如果父节点中不存在临时顺序子节点,则阻塞等待;如果有子节点,则获取执行自己的业务,执行完毕后删除该节点即可。
- 4、获取时获取最小值,保证FIFO特性。