前言
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置共享、命名服务、分布式同步、服务注册等。
上一篇博客中我们了解到Zookeeper可以用来实现分布式同步,主要是利用了顺序临时节点和watcher
的机制来实现的,所以今天再来讲一下Zookeeper在其他场景上的应用。
服务注册
dubbo是阿里的RPC微服务框架的具体实现,dubbo中的服务注册就是基于Zookeeper的。那么什么是服务注册呢?为了支持高并发,我们需要将服务部署成集群,当客服端来调用服务的时候,会在集群列表中找到对应的服务节点。
但是这个列表是静态的(在配置文件中写死的),如果服务的提供者发生了变化,例如有些机器down了,或者又新增了服务节点的实例,客户端根本不知道,可能还在傻乎乎地尝试那些已经坏掉的实例呢!
看来这个配置文件的确不方便,需要有一个更灵活的方式来告知客服端有哪些服务节点可以使用。要解决的问题有,如何知道哪些机器down了,以及服务要实现动态的注册,不能是写死的。刚好Zookeeper上的心跳检测以及提供创建节点的方法刚好可以解决上述的问题。
先来看一下服务的提供者如何在Zookeeper中注册服务。假设这里有4个服务提供者,提供一个orderService的方法,首先Zookeeper上创建一个orderService的Znode,然后四个服务提供者在这个节点下创建对应的临时节点。
/orderService 表达了一个服务的概念, 下面的每个节点表示了一个服务的实例。 例如/orderService/node2
表示的order service 的第二个实例, 每个节点上可以记录下该实例的url , 这样就可以查询了。
客户端就到Zookeeper这里来查询,只需要给出名称orderService,注册中心找到该节点下的所有可用节点,然后根据均衡算法给出一个可以使用的节点中的url。
注册中心还可以和各个服务实例直接建立Session, 让各个服务实例定期地发送心跳,如果过了特定时间收不到心跳,就认为这个服务实例挂掉了,Session 过期, 把它从树形结构中删除。
配置共享
集中式的配置管理在应用集群中是非常常见的,一般商业公司内部都会实现一套集中的配置管理中心,应对不同的应用集群对于共享各自配置的需求,并且在配置变更时能够通知到集群中的每一个机器。简单来说就是集群中的配置要修改的时候,不用一个个去改,而是通过Zookeeper的Watcher机制来实现。
假设一个集群有三个服务节点,server1,server2,server3,先在Zookeeper上创建一个/config的Znode节点,Znode上的值可以是配置文件的初始值。然后每一个server去获取/config节点上的数据。
Zookeeper有exists,getData,getChildren读操作。Zookeeper客户端在请求读操作的时候,可以选择是否设置Watch。我们可以理解成是注册在特定Znode上的触发器。当这个Znode发生改变,也就是调用了create,delete,setData方法的时候,将会触发Znode上注册的对应事件,请求Watch的客户端会接收到异步通知。
那么让这三个server在getData的时候,设定watch为true,这样只要这个Znode的数据发生改变,就会触发process方法,我们就可以在process方法中做相应的配置修改操作了。具体交互过程如下:
1.客户端调用getData方法,watch参数是true。服务端接到请求,返回节点数据,并且在对应的哈希表里插入被Watch的Znode路径,以及Watcher列表。
2.当被Watch的Znode已删除,服务端会查找哈希表,找到该Znode对应的所有Watcher,异步通知客户端,并且删除哈希表中对应的Key-Value。
命名服务
在我们熟悉的关系型数据库中,各个表都需要一个主键来唯一标识某条数据记录,这个主键就是 这样的唯一ID。
在过去的单库表型系统中,通常可以使用数据库字段自带的auto_increatement属性来自动为每条数据库记录生成一个唯一的ID,数据库会保证生成的这个ID在全局唯一。但是随着数据数据规模增大,分库分表随之出现,而auto_increatement属性仅能针对单表中的记录自动生成ID,因此在这种情况下,我们必须寻求一种能够在分布式环境下生成全局唯一的ID的方法。
说起全局唯一ID,大家都会联想到UUID。但是UUID因为长度过长,需要花费很多的空间,而且含义不明。
而我们通过Zookeeper节点创建的API接口可以创建一个顺序节点,并且API返回值中会返回这个节点的完整名字。利用这个特性,我们就可以借助Zookeeper来生成全局唯一的ID了。