zk的原理和数据结构,在前面已经简单介绍过了,接下来看看如何利用zk的特性实现一些神奇的功能
命名服务
分布式数据库自增id的唯一性
利用znode SEQUENTIAL
不同的客户端对同一个zk集群调用create方法,创建SEQUENTIAL节点(对于其父节点唯一)
配置管理
在web运行过程中,动态的修改一些配置信息,让其立即生效,而不需要重启项目
同一个web应用运行在不同的机器上,要保证对配置信息的修改能够对所有机器都可见
将配置信息保存在某个节点内,一旦配置信息发生变化,会通知客户端(推模式)
也可以客户端每次加载配置信息时,读取最新的数据(拉模式)
仔细思考下,其实和存放在数据库中效果类似,但是zk集群能够保证服务的稳定性,而如果使用数据库必然使用分布式数据库,此时一样需要zk来协调
RPC服务的注册与发现
比如业界知名的dubbo 对于service的注册和发现都是基于zk实现的
服务提供方:在名为serviceName的父节点下创建ip+port子节点(同一个serviceName的节点下有多个以ip+port为名字的节点)
服务消费方:根据serviceName去zk查询可提供服务的ip和port
执行rpc调用(tcp方式)
Master选举
以分布式数据库为例子,所有的数据库服务器在同一个zk父节点下创建同名的临时节点,举个例子 /master/election/master 存储当前机器的ip和提供数据库服务的port
这时候只有一个服务器能够创建成功,这个创建成功的服务器就成为了Master,而其他创建失败的服务器需要在父节点/master/election上注册一个子节点变更的watcher
一旦发现master挂了,就重新选举master
or
每个客户端在 /master/election/下注册临时有序节点 /client1,/client2 etc
并且在父节点注册watcher
默认选取client序号最小的客户端作为master,加入该客户端宕机,那么对应的节点将被删除,此时父节点下序号最小的节点对应的客户端当选master
分布式锁
假设现在有两个不同客户端的线程都要处理某个共享资源,如何保证资源能够被预期地被处理?
这时候需要分布式锁,加锁的过程就是在zk指定节点下创建子节点比如/locks/lock
创建成功的线程表示获取锁成功,而失败的客户端会对这个父节点进行监听
释放锁的时候分为两种情况,第一种情况,机器宕机,此时临时节点被删除;第二种情况,获取锁的线程执行完业务逻辑主动删除该节点
接下来其他想要获取锁的线程会得到通知,并再次进行竞争
分布式队列
分布式环境,如何保证消息的有序消费,如何保证消息不会重复消费?
自己yy的一个方案
利用zk实现的FIFO队列,在特定的目录下创建SEQUENTIAL节点,出队列的时候通过getChild()返回当前队列中所有的元素,
找到最小序号的节点,如果该节点下有子节点(表示该任务已经被消费),那么再去找次小的节点,假设该节点下无子节点,那么在该节点下创建子节点(表示当前任务已被消费)
这样可以保证任务被有序消费,且不会被重复消费 Ps 但是此时的场景仅仅是有序,并非任务1消费过后 再去消费任务2