探讨其功能需要围绕的一个主线:它可以在分布式系统中协作多个任务
一个协作任务指一个包含多进程的任务。这个任务可以是为了协作或者是为了管理竞争。协作意味着多个进程需要同时处理某些事情,一些进程采取某些行动使得其它进程可以继续工作
分布式系统中进程通信通常两种选择:直接通过网络进行信息交换,或读写某些共享存储。
zookeeper使用共享存储模型(是借鉴了这个模型)来实现应用间的协作和同步原语。对于共享存储本身,又需要在进程和存储间进行网络通信
网络通信的一些真实问题:
1. 消息延迟
2. 处理器的性能
3. 处理器时钟偏移
采用仲裁方式的复制集群中,由于具备高可用的镜像复写功能,如果客户端需要等待每个服务器完成数据的螺钉后在继续,则延时的问题会变得比较突出,要知道,延时,在大流量的访问中,是不可接收的,但不代表能消灭延时。此时,在ZK的设计思路中,为了规避这个问题,则衍生了法定人数的思想,即我们只需要保证我们的集群中,由若干算法模式下实现的人数能完成对应的信息落地之后,则认为客户端可以继续下一波的操作,而不是等到所有集群完全落实才继续下去。例如,我们由5个zk服务器,而法定人数为3人,则我们只需要确保其中的3台服务器保存了对应的数据,客户端就可以继续,而其他两个服务器在正常的状态下,最终也是能获取到数据,并保存下来
1. 一个main()
2. main()线程创建zookeeper客户端,这时会创建两个线程,1个负责网络连接通信(connect),一个负责监听(listener)
3. 通过connect线程将注册的监听事件发送给Zookeeper
4. 在zookeeper的注册监听列表中,将注册的监听事件添加到列表中
5. zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程
6. listener线程内部调用process()方法
主节点负责负责跟踪从节点状态和任务的有效性,并分配任务到从节点
1.主节点崩溃: 如果主节点发送错误并失效,系统将无法分配新的任务或重新分配已失败的任务
2. 从节点崩溃:如果从节点崩溃,已分配的任务将无法完成
3. 通信故障: 如果主节点和从节点之间无法进行信息交换,从节点将无法得知新任务分配给它(一致性问题)
zk 服务端启动
bin/zkServer.sh start-foreground
启动一个客户端
bin/zkCli.sh
查看服务端日志
过程
1. 客户端启动程序来建立会话,客户端尝试连接到zookeepr服务端
2. 服务端初始化会话完成,建立log file,发送一个SyncConnected事件给客户端
3. 客户端应用需要实现Watcher对象来处理这个事件
zkNode的创建,删除
退出客户端
服务端log
主节点: 负责监视新的从节点和任务,分配任务给可用的从节点
从节点:通过系统注册自己,以确保主节点可以看到自己能执行任务了,然后开始监视新任务
客户端: 创建新任务并等待系统的响应
../bin/zkServer.sh start ../conf/z1.cfg
../bin/zkServer.sh stop ../conf/z1.cfg
之后启动zk2, 达到仲裁人数,zk2称为leader, z1是个follower
客户端连接
bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182
多次停止客户端在重新,观察连接的变化
bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
可以观察到连接127.0.0.1:2183 失败,最终可以连接的日志
主节点创建临时性的zNode,从节点可以看到;当主节点删除时,从节点也能注意到
主节点监控/workers 和 /tasks的自节点的变化情况
从节点通知主节点,自己可以执行任务
create -e /workers/worker1 "worker1"
主节点收到该消息
从节点创建接收任务的zNode, 并监控,以等待任务的分配
create -e /assign/worker1 ""
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 6] create -s /tasks/task- "cmd"
Created /tasks/task-0000000000
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 7] ls /tasks/task-0000000000 true
[]
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 8]
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/tasks
随后会检查这个新任务,获取可用的从节点列表,之后分配这个给worker1
[zk: 127.0.0.1:2182(CONNECTED) 9] ls /tasks
[task-0000000000]
[zk: 127.0.0.1:2182(CONNECTED) 10] ls /workers
[worker1]
[zk: 127.0.0.1:2182(CONNECTED) 11] create /assign/worker1/task-0000000000 ""
Created /assign/worker1/task-0000000000
[zk: 127.0.0.1:2182(CONNECTED) 12]
[zk: 127.0.0.1:2181(CONNECTED) 8] ls /assign/worker1 true
[]
[zk: 127.0.0.1:2181(CONNECTED) 9]
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/assign/worker1
接着从节点开始执行这个任务
[zk: 127.0.0.1:2181(CONNECTED) 9] create /tasks/task-0000000000/status "done"
Created /tasks/task-0000000000/status
[zk: 127.0.0.1:2181(CONNECTED) 10]
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/tasks/task-0000000000
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 8] get /tasks/task-0000000000
cmd
cZxid = 0x10000003a
ctime = Thu Apr 04 21:31:44 CST 2019
mZxid = 0x10000003a
mtime = Thu Apr 04 21:31:44 CST 2019
pZxid = 0x100000040
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 9] get /tasks/task-0000000000/status
done
cZxid = 0x100000040
ctime = Thu Apr 04 21:51:23 CST 2019
mZxid = 0x100000040
mtime = Thu Apr 04 21:51:23 CST 2019
pZxid = 0x100000040
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTED) 10]