Zookeeper简单总结
简介
- zookeeper是一个分布式协调服务
- 分布式应用程序可以基于它实现同步服务,配置维护以及命名维护等
- zookeeper可以保证数据在zookeeper集群之间的数据的事务性一致
- zookeeper中的组件角色
- leader 领导者,负责进行肉票的发起以及决议,更新系统状态
- learner 学习者 ,包括follower 跟随者 以及 observer 观察者
- follower 跟随者:用于接收客户端的请求 并向客户端返回结果 在选择主节点的时候参与投票
- observer 观察者:可以接收少部分的客户端连接,将写请求转发给leader,不参与投票,主要是用来 同步leader的状态,目的是为了扩展系统,提高读取速度
- client 客户端:请求发起方
命令行操作
- ls /
- 查看指定节点下的信息
- create /test/ data
- 创建节点
- get / test
- 获取节点上保存的数据
- set /tets datass
- 修改节点的内容
- rmr /test
- 删除节点
节点的介绍
zookeeper的数据模型
- 层次化的目录结构,命名符合常规文件系统规范
- 每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识
- 节点Znode可以包含数据和子节点,但是EPHEMERAL临时类型的节点不能有子节点
- Znode中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据就需要带上版本
- 客户端应用可以在节点上设置监视器
- 节点不支持部分读写,而是一次性完整读写
zookeeper的节点
- Znode有两种类型,临时节点(ephemeral)和永久节点(persistent)
- Znode的类型在创建时确定并且之后不能再修改
- 临时znode的客户端会话结束时,zookeeper会将该临时znode删除,临时znode不可以有子节点
- 永久znode不依赖于客户端会话,只有当客户端明确要删除该znode时才会被删除
- Znode有四种形式的目录节点,PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、EPHEMERAL_SEQUENTIAL
实际应用
zookeeper实现分布式进程监控
- 假设要监控多台服务器上的A程序运行状态,当发现有服务器上的A程序下线的时候,给管理员发短信,并且尝试重启A程序。
- 主要利用zk的临时节点和watcher监视器的特性
- 大致实现的思路
- 首先在A程序启动的时候在zookeeper的/monitor节点下创建一个临时节点,临时节点的名称可以用这个服务器的主机名或者ip信息,只要A程序一直正常运行,这个临时节点就会一直存在。
- 给zk的/monitor节点注册一个watcher监视器,监视monitor节点下面的所有子节点的变化情况,当有子节点变化的时候,获取到具体是哪一个子节点发生了变化,就知道是哪台机器上的A程序有问题了。
- 可以给管理员发短信,打电话,发邮件之类的,并且还可以实现对那一台服务器上的A程序进行重启。
zookeeper实现分布式共享锁
- 首先假设有两个线程,两个线程要同时到mysql中更新一条数据,对数据库中的数据进行累加更新。由于在分布式环境下,这两个线程可能存在于不同的机器上的不同jvm进程中,所以这两个线程的关系就是垮主机跨进程,使用java中的synchronized锁是搞不定的。
- 在这我们主要利用了zookeeper的临时有序节点的特性和watcher监视器。
- 我们认为最小的节点具备执行权,也就是获取到了锁。
- 大致思路如下:
- 当这两个线程去mysql更新数据之前,先到zookeeper的/locks(永久节点)下面注册一个临时有序节点,这样每个线程都注册了一个临时节点,两个临时节点肯定是有序的。
- 线程1:/locks/000000001 线程2:/locks/000000002
- 当每个线程注册完节点之后,需要尝试获取锁,这个时候,哪个节点最小,哪个线程就获取到锁,这个时候,线程2注册的节点最小,所以线程2 就获取到锁,执行更新数据库的代码,更新完成之后,删除自己注册的临时节点
- 同时线程1会判断自己不是最小的,所以就会监控比自己小1的那个节点,当发现那个节点消失的话,也就意味着它的节点就是最小的节点,获取锁,执行更新数据库的代码…
遇到过的问题
- kafka集群无法正常工作,提示连不上zk集群
- 分析产生的原因:zk集群的某一个节点磁盘故障导致进程假死
- 恢复过程:
- 先把线上zk集群的一个正常节点转化为单节点运行,恢复kafka集群服务
- 重新部署一个新的zk集群
- 把老zk集群的数据恢复到新zk集群中,kafka集群切换新的zk集群