zookeeper
概述
- zookeeper是一个开源的分布式的, 为分布式服务提供协调服务的Apache项目。
- zookeeper = 文件系统 + 通知机制
工作机制
是一个基于观察者模式设计的分布式服务管理框架,每个注册到zookeeper的服务都是一个观察者,zookeeper负责管理每个观察者都比较关心的数据, 一旦这些数据发生变化,就会及时通知到各个观察者作出相应的反映。
特点
- zookeeper集群有一个leader和多个flower。
- 集群中只要有半数以上的节点存活,zookeeper就能工作。
- 全局数据一致,每个节点都保存一份副本,客户端连接哪个节点都可以。
- 每个结点发送过来的多个更新请求都会按照顺序执行。
- 数据更新的原子性,一次数据请求,要么成功,要么失败。
- 实时性,在一定时间范围内,能够及时读取到最新数据,因为zookeeper存储的数据非常小。
数据结构
zookeeper的数据结构可以看成一个树,每个节点成为ZNode,每个ZNode默认能够存储1M的数据,每个ZNode可以通过其路径唯一标识。
应用场景
- 统一命名服务,类似于eureka
- 统一配置管理,类似于配置中心
- 统一集群管理,检测每个注册的服务健康状态
- 服务器动态上下线,能够实时检测到注册进来的服务是否健康,如果一个服务挂了,可以及时切换到其他服务。
- 负载均衡,记录每个服务的访问数,让访问数最少的来处理请求。
开机时leader选取机制(重点)
- 半数机制,半数以上的节点存活,集群可用,所以集群选择奇数个节点安装
- 每个节点都会先选自己作为leader,比如有5台,需要三票才能作为leader,所以第一台服务器会选第二台作为leader,2票还是不够,依次选第三台,过半了,第三台就会作为leader。
节点类型
默认是持久类型, 监听一次,不管是子节点改变还是节点值改变,都只会通知一次,如果多次通知,必须多次watch
- 持久:客户端与服务端断开连接后,创建的节点会保存
- 持久化节点
- 顺序持久化节点:zookeeper给该节点一个顺序编号,由父节点维护,可以编排事件的执行顺序
- 短暂:客户端与服务端断开连接后,创建的节点会删除,也可以有顺序编号
监听器原理(重点)
- 启动客户端,会创建两个线程,一个connect线程和一个listener线程
- 通过connect线程将注册的监听事件发送给zookeeper
- 在zookeeper注册监听器列表中添加注册的监听事件
- zookeeper监听到有数据变化或者路径变化,就会将这个消息发给lister线程
- lister线程内部调用了process() 方法
常见的监听事件:
- 数据监听事件
- 子节点变化事件
写数据流程
集群中每个server可以读和写,每个server写之后,如果不是leader,都会将写的数据发给leader,leader负责将消息复制分发到每个flower。如果leader接收分发到server大部分成功了, 就会认为写成功了。
安装(docker-compose)
单机版
创建目录zookeeper,同时创建子目录data,config,log
- docker-compose.yml
version: '3'
services:
zookeeper:
image: zookeeper
restart: always
container_name: zookeeper
volumes:
- ./config:/conf
- ./data:/data
- ./logs:/datalog
ports:
- "2181:2181"
- 在config目录下创建zoo.cfg
dataDir=/data
dataLogDir=/datalog
tickTime=2000
initLimit=5
syncLimit=2
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
admin.enableServer=true
server.1=localhost:2888:3888;2181
4lw.commands.whitelist=*
- 启动
docker-compose up -d
三个节点的集群
- docker-compose.yml
version: '3.1'
services:
zoo1:
image: zookeeper
restart: always
container_name: zoo1
ports:
- 2181:2181
volumes:
- /usr/local/docker/zookeeper/zoo1/data:/data
- /usr/local/docker/zookeeper/zoo1/datalog:/datalog
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
zoo2:
image: zookeeper
restart: always
container_name: zoo2
ports:
- 2182:2181
volumes:
- /usr/local/docker/zookeeper/zoo2/data:/data
- /usr/local/docker/zookeeper/zoo2/datalog:/datalog
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
zoo3:
image: zookeeper
restart: always
container_name: zoo3
ports: