实现统一配置
实现思路
- 比如我们现在有三个系统A、B、C,他们有三份配置,分别是ASystem.yml、BSystem.yml、CSystem.yml,然后,这三份配置又非常类似,很多的配置项几乎都一样。
- 此时,如果我们要改变其中一份配置项的信息,很可能其他两份都要改。并且,改变了配置项的信息很可能就要重启系统。于是,我们希望把ASystem.yml、BSystem.yml、CSystem.yml相同的配置项抽取出来成一份公用的配置common.yml,并且即便common.yml改了,也不需要系统A、B、C重启。
实现方法
我们可以将common.yml这份配置放在ZooKeeper的Znode节点中,系统A、B、C监听着这个Znode节点有无变更,如果变更了,及时响应。
实现步骤
配置管理中心实现:
- 导入zkClient对应的jar。
- 实现工具类方法,完成从数据库加载配置、将配置文件保存到数据库、配置文件同步到zookeeper。
/** * 配置文件同步到zookeeper */ public void syncConfigToZk(){ ZkClient zk = new ZkClient("localhost:2181"); if(!zk.exists("/zkConfig")){ zk.createPersistent("/zkConfig",true); } zk.writeData("/zkConfig", config); zk.close(); }
- 具体的代码是实现,将上面的1、2进行代码实现。运行就可以实现同步配置信息到zookeeper了,
客户端实现:
- 监听zookeeper中zkConfig对应的zoNode节点。
private Config config; public Config getConfig() { ZkClient zk = new ZkClient("localhost:2181"); config = (Config)zk.readData("/zkConfig"); System.out.println("加载到配置:"+config.toString()); //监听配置文件修改 zk.subscribeDataChanges("/zkConfig", new IZkDataListener(){ @Override public void handleDataChange(String arg0, Object arg1) throws Exception { config = (Config) arg1; System.out.println("监听到配置文件被修改:"+config.toString()); } @Override public void handleDataDeleted(String arg0) throws Exception { config = null; System.out.println("监听到配置文件被删除"); } }); return config; }
统一命名服务
命名服务功能主要是根据指定名字来获取资源或服务的地址、提供者信息,利用zookeeper我们可以创建唯一标识路径,这个路径可以作为一个名字,指定集群中的集群,提供的服务的地址或者一个远程对象。这个路径就好比是一个仓库,这个仓库的地址是唯一的,这些仓库里面存了一些东西,当我们来到这个仓库,我们就能取到仓库里的东西。
比如说,现在我有一个域名www.liancan.com,而这个域名下有多台机器:
192.168.0.91
192.168.0.93
192.168.0.94
192.168.0.95
通过访问 www.liancan.com 就可以访问到我的机器,而不是通过 IP 去访问,如下图所示:
分布式锁
实现分布式锁有两种,一种是保持独占,一种是控制时序。
- 第一种方式
- 我们将zookeeper上的节点看成一把锁,通过createznode的方式来实现,所有客户端都去创建/distribute_lock节点,最终成功创建的那个客户端就拥有了这把锁。用完删掉自己创建的节点就释放锁。
- 缺点:
- 注意:不适用于客户端数量很大的情况,当一个客户端拥有第一把锁之后,所有的客户端都要去监听节点,节点的释放也会通知所有的客户端,这样会出现羊群效应。
- 第二种方式
- 假设/distribute_lock已经预先存在,所有的客户端都在它下面创建临时顺序编号目录节点,编号最小的获取锁。
- 没有获取到锁的客户端就监听编号比自己小的前一个节点,因为节点是有顺序的,很容易找到自己创建的前一个节点。
- 当监听到前一个节点删除节点,即释放锁,该客户端就会获得锁。
- 这样避免所有的客户端只需要监听一个节点和节点删除需要通知所有客户端的情况。
- 实现思路:
- 客户端 A 拿到 /distribute_lock 节点下的所有子节点,经过比较,发现自己(id_001),是所有子节点最小的。所以得到锁。
- 客户端 B 拿到 /distribute_lock 节点下的所有子节点,经过比较,发现自己(id_002),不是所有子节点最小的。所以监听比自己小的节点 id_001 的状态。
- 客户端 C 拿到 /distribute_lock 节点下的所有子节点,经过比较,发现自己(id_003),不是所有子节点最小的。所以监听比自己小的节点 id_002 的状态。
- 等到客户端 A 执行完操作以后,将自己创建的节点 id_001 删除。通过监听,客户端 B 发现 id_001 节点已经删除了,发现自己已经是最小的节点了,于是顺利拿到锁。
集群管理
在分布式环境中,掌握集群中每个节点的状态,zookeeper做集群管理可以实现检测是否有机器加入或退出,还可以用来选举集群的master。
只要客户端 A 挂了,那/GroupMember/A这个节点就会删除,通过监听 GroupMember 下的子节点,客户端 B 和客户端 C 就能够感知到客户端 A 已经挂了(新增也是同理)