Zookeeper:一个主-从模式例子的实现

Zookeeper主-从模式的模型中包括三个角色:

  • 主节点:负责监视新的从节点和任务,分配任务给可用的从节点
  • 从节点:通过系统注册自己,以确保主节点看到它们可以执行任务,然后开始监视新任务
  • 客户端:创建新任务并等待系统的响应

1 主节点角色

因为只有一个进程会成为主节点,所以一个进程成为Zookeeper的主节点后必须锁定管理权。为此,进程需要创建一个临时znode,名为/master:

[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create -e /master "master1.example.com:2223"
Created /master
[zk: localhost:2181(CONNECTED) 2] ls /
[zookeeper, master]
[zk: localhost:2181(CONNECTED) 3] get /master
master1.example.com:2223
cZxid = 0xc
ctime = Tue Sep 24 23:22:18 CST 2019
mZxid = 0xc
mtime = Tue Sep 24 23:22:18 CST 2019
pZxid = 0xc
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x100000e04220000
dataLength = 24
numChildren = 0

首先创建一个临时znode/master。我们在znode中添加了主机信息,以便Zookeeper外部的其它进程需要与它通信。添加主机信息并不是必须的,但这样做仅仅是为了说明我们可以在需要时添加数据。为了设置znode为临时性的,需要添加-e标志。(一个临时节点会在会话结束过期或关闭时自动删除)

现在来看看使用两个进程来获得主节点角色的情况,尽管在任何时刻最多只能有一个活动的主节点,其它进程将成为备份主节点。假如其它进程不知道已经有一个主节点被选举出来并尝试创建一个/master节点。来看看会发生什么:

[zk: localhost:2181(CONNECTED) 4] create -e /master "master2.example.com:2223"
Node already exists: /master

Zookeeper报告一个/master节点已经存在。这样,第二个进程就知道已经存在一个主节点。然而,一个活动的主节点可能会崩溃,备份主节点需要接替活动主节点的角色。为了检测到这些,需要在/master节点上设置一个监视点,操作如下:

[zk: localhost:2181(CONNECTED) 5] stat /master true
cZxid = 0xc
ctime = Tue Sep 24 23:22:18 CST 2019
mZxid = 0xc
mtime = Tue Sep 24 23:22:18 CST 2019
pZxid = 0xc
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x100000e04220000
dataLength = 24
numChildren = 0

stat命令可以得到一个znode节点的属性,并允许在已经存在的znode节点上设置监视点。通过在路径后面设置参数true来添加监视点。当活动的主节点崩溃时,可以观察到以下情况:

[zk: localhost:2181(CONNECTED) 6]
WATCHER:
WatchedEvent stat:SyncConnected type:NodeDeleted path:/master

在输出的最后为NodeDeleted事件。这个事件指出活动主节点的会话已经关闭或过期。同时注意,/master节点已经不存在了。现在备份主节点通过再次创建/master节点来成为活动主节点。

[zk: localhost:2181(CONNECTED) 1] create -e /master "master2.example.com:2223"
Created /master

因为备份主节点成功创建了/master节点,所以现在客户端开始成为活动主节点。

2 从节点、任务和分配

先创建三个父znode: /workers、/tasks 和 /assign:

[zk: localhost:2181(CONNECTED) 2] create /workers ""
Created /workers
[zk: localhost:2181(CONNECTED) 3] create /tasks ""
Created /tasks
[zk: localhost:2181(CONNECTED) 4] create /assign ""
Created /assign

这三个新的znode为持久性节点,且不包含任何数据。本例中,通过使用这些znode可以知道哪个从节点当前有效,还可以知道当前有任务需要分配,并向从节点分配任务。

在真实的应用中,这些znode可能由主进程在分配任务前创建,也可能由一个引导程序创建,不管这些节点是如何创建的,一旦这些节点存在了,主节点就需要监视/workers和/tasks的子节点的变化情况:

[zk: localhost:2181(CONNECTED) 8] ls /workers true
[]
[zk: localhost:2181(CONNECTED) 9] ls /tasks true
[]

请注意,在主节点上调用stat命令前,使用可选的true参数调用ls命令。通过true这个参数,可以设置对应znode的子节点变化的监视点。

3 从节点角色

从节点首先要通知主节点,告知从节点可以执行任务。从节点通过在/workers子节点下创建临时性的znode来进行通知,并在子节点中使用主机名来标识自己:

[zk: localhost:2181(CONNECTED) 11] create -e /workers/worker2.example.com "worker1.example.com:2224"

注意,输出中,Zookeeper确认znode已经创建。之前节点已经监视了/workers的子节点变化情况。一旦从节点在/workers下创建了一个znode,主节点就会观察到以下通知信息:

WATCHER::Created /workers/worker2.example.com


WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/workers

下一步,从节点需要创建一个父znode/assing/worker1.example.com来接收任务分配,并通过第二个参数为true的ls命令来监视这个节点的变化,以便等待新的任务。

[zk: localhost:2181(CONNECTED) 12] create /assign/worker1.example.com ""
Created /assign/worker1.example.com
[zk: localhost:2181(CONNECTED) 13] ls /assign/worker1.example.com true
[]

从节点现在已经准备就绪,可以接收任务分配。之后,可通过讨论客户端角色来看一下任务分配的问题。

4 客户端角色

客户端向系统中添加任务。在本示例中具体任务是什么并不重要,假设客户端请求主从系统来运行cmd命令。为了向系统添加一个任务,客户端执行以下操作:

[zk: localhost:2181(CONNECTED) 0] create -s /tasks/task- "cmd"
Created /tasks/task-0000000000

需要按照任务添加的顺序来添加znode,其本质上为一队列。客户端现在必须等待任务执行完毕。执行任务的从节点将任务执行完毕后,会创建一个znode来表示任务状态。客户端通过查看任务状态的znode是否创建来确定任务是否执行完毕,因此客户端需要监视状态znode的创建事件:

[zk: localhost:2181(CONNECTED) 1] ls /tasks/task-0000000000 true
[]

执行任务的从节点会在/tasks/task-0000000000节点下创建状态znode节点,所以我们需要用ls命令来监视/tasks/task-000000000的子节点。一旦创建任务的znode,主节点会观察到以下事件:

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/tasks

主节点之后会检查这个新的任务获取可用的从节点列表,之后分配这个任务给worker2.example.com:

ls /tasks
[task-0000000000]
[zk: localhost:2181(CONNECTED) 16]  ls /workers
[worker2.example.com]
[zk: localhost:2181(CONNECTED) 17] create /assign/worker1.example.com/task-00000000 ""

从节点接收到新任务分配的通知:

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/assign/worker1.example.com
Created /assign/worker1.example.com/task-00000000

从节点之后便开始检查新任务,并确认该任务是否分配给自己:

[zk: localhost:2181(CONNECTED) 18]  ls /assign/worker1.example.com
[task-00000000]

一旦从节点完成任务的执行,它就会在/tasks中添加一个状态znode:

[zk: localhost:2181(CONNECTED) 19] create /tasks/task-0000000000/status "done"
Created /tasks/task-0000000000/status

之后,客户端接收到通知,并检查执行结果:

[zk: localhost:2181(CONNECTED) 2] get /tasks/task-0000000000
cmd
cZxid = 0x17
ctime = Wed Sep 25 22:03:54 CST 2019
mZxid = 0x17
mtime = Wed Sep 25 22:03:54 CST 2019
pZxid = 0x19
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 1
[zk: localhost:2181(CONNECTED) 3] get /tasks/task-0000000000/status
done
cZxid = 0x19
ctime = Wed Sep 25 22:28:06 CST 2019
mZxid = 0x19
mtime = Wed Sep 25 22:28:06 CST 2019
pZxid = 0x19
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 4] 

客户端检查状态znode的信息,并确认任务的执行结果。本例中,我们看到任务成功执行,其状态为"done"。当然任务也可能非常复杂,甚至涉及另一个分布式系统。最终不管是什么样的任务,执行任务的机制与通过Zookeeper来传递结果,本质上都是一样的。

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值