2.1 master-worker架构的znode tree模型

2016-04-12 23:17:17 5,872 0

单从语法的角度讲解这四种模式,读者不好理解其实际用途,因此通过在典型的master-workers分布式架构来讲解,在实际中,如何使用这四种znode来实现这种分布式架构。

在传统的master-worker架构中,服务的组成一般如下所示,

Image.png

其中master也是一个worker,是众多worker中推选出来的一个leader。master负责监控workers的状态、接受任务(tasks),并将任务分配(assign)给worker。所以,在这里展示的master-worker架构涉及到了四个概念:master、worker、task、assign。

在zookeeper中,集群的架构是通过数据模型目录结构中的znode tree来描述的。所以我们需要创建一个合适的目录结构,选择正确的znode模式,来表述这种架构,将master、worker、task、assign都转换为zookeeper中的znode。以下展示一个已经建立好的描述上述描述master-worker架构的znode  tree:

Image.png


其中圆圈和空心矩形表示的是持久节点,其他表示临时节点,矩形框中的内容是临时序列节点的data。


从图中可以看出,/master节点是临时节点;/workers、/tasks、/assign这种固定的目录一般是持久节点,而他们的子节点都是临时序列节点。

下面详细解释为什么要使用这样的目录结构和znode类型来描述master-worker架构。

1、master为什么是临时节点

在master-worker架构中,master只有一个,且是由众多的worker中选举出来的。如果master是持久znode,那么即使master宕机了,在znode tree中,/master节点依然存在。由于worker是根据/master是否存在判断leader是否宕机的,如果是持久节点的话,就算leader宕机了worker也无法判断。如果主节点是临时节点,宕机后,/master znode就会自动删除,此时worker发现/master不存在,就会重新选举出leader,因此/master必须是临时节点。

2、/workers、/tasks、/assign为什么是持久节点

这三个节点其实是为了znode tree的目录结构更加清晰而创建的,因为在实际中,我们可能会有很多个worker,客户端也会提交很多个task,我们将这些worker、task以及任务分配的状态放置与固定的path下,便于查看和管理。因为path下还必须要存放其他的znode,因为临时节点是没有子node的,所以对于这三个目录我们只能使用持久node。

3、/workers、/tasks的子节点为什么是临时节点

对于workers,如果某个worker宕机了,其对应的znode也应该自动删除,否则leader检测到这个worker对应的znode还存在,会认为这个worker还没有宕机。

4、/assign的子znode空心矩形为什么是持久节点

因为这个节点表示的是给分配给某个worker的任务,所有分配给这个worker的task都在这个目录下,所以针对每个worker,我们在assign目录下,设置一个对应的持久目录,然后将分配给这个worker的任务设置为其子node,这样我们就能很容易的统计出,当前worker已经分配了那些task。就算这个worker宕机,也不删除这个node,因为重启之后,我们还是要创建这个目录。

master-worker架构的znode-tree实现


上面的介绍中,我们已经知道master-worker架构的znode tree应该是什么样子的了,我们需要创建对应的目录结构,并且每个znode选择正确的模式。不过,仅仅创建这样的一个znode tree,还不行,我们在之前提到:

1、master要监控workers的状态,因为其master要知道worker是否宕机,如果宕机了,则不能将任务分配给它,同时如果有新的worker存在时,master也要能检测到,可以将task分配给新的worker。

2、workers要监控master的状态,因为如果master如果宕机了,就不能接受和分配任务了,此时应该在workers中重新选举出一个leader。

所以我们在实现znode tree的时候,还要注意设置相应的监控关系。

master应该监控的目录包括:/workers、/tasks、/assign,当设置过监控之后,worker宕机或者新增worker、新的task或者task执行完成,某个任务assign给那个worker,master就都可以知道。

每个worker都应该监控master的状态,如果宕机,则进行新的选举。

下面通过zkCli.sh来实现master-worker架构,在实际开发中,我们都是通过Java API来实现的。在这里我们通过伪分布式的zookeeper集群,来演示这个案例。

所谓Zookeeper的伪分布式搭建,就是在同一台机器上的不同端口,启动多个zookeeper Server实例,并通过多个配置文件来实现Server之间的通信。


新建以下目录和文件:

[root@www zookeeper-3.4.5-cdh5.4.7]# tree $ZOOKEEPER_HOME/pseudo_conf/
/usr/local/zookeeper-3.4.5-cdh5.4.7/pseudo_conf/
├── zk1
│   ├── data
│   │   └── myid
│   └── zk1.cfg
├── zk2
│   ├── data
│   │   └── myid
│   └── zk2.cfg
└── zk3
    ├── data
    │   └── myid
    └── zk3.cfg

创建脚本

mkdir $ZOOKEEPER_HOME/pseudo_conf
mkdir $ZOOKEEPER_HOME/pseudo_conf/zk1
mkdir $ZOOKEEPER_HOME/pseudo_conf/zk2
mkdir $ZOOKEEPER_HOME/pseudo_conf/zk3
mkdir $ZOOKEEPER_HOME/pseudo_conf/zk1/data
mkdir $ZOOKEEPER_HOME/pseudo_conf/zk2/data
mkdir $ZOOKEEPER_HOME/pseudo_conf/zk3/data
touch $ZOOKEEPER_HOME/pseudo_conf/zk1/data/myid
touch $ZOOKEEPER_HOME/pseudo_conf/zk2/data/myid
touch $ZOOKEEPER_HOME/pseudo_conf/zk3/data/myid
echo 1 > $ZOOKEEPER_HOME/pseudo_conf/zk1/data/myid
echo 2 > $ZOOKEEPER_HOME/pseudo_conf/zk2/data/myid
echo 3 > $ZOOKEEPER_HOME/pseudo_conf/zk3/data/myid
touch $ZOOKEEPER_HOME/pseudo_conf/zk1/zk1.cfg
touch $ZOOKEEPER_HOME/pseudo_conf/zk2/zk2.cfg
touch $ZOOKEEPER_HOME/pseudo_conf/zk3/zk3.cfg

zk1.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2181
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445

zk2.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2182
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445

zk3.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2183
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445

启动zookeeper服务:

启动zk1

cd $ZOOKEEPER_HOME/pseudo_conf/zk1

#第一个参数值可以使start/stop  第二个参数指的是配置文件的配置

$ZOOKEEPER_HOME/bin/zkServer.sh start ./zk1.cfg

启动zk2

cd $ZOOKEEPER_HOME/pseudo_conf/zk2

$ZOOKEEPER_HOME/bin/zkServer.sh start ./zk2.cfg

启动zk3

cd $ZOOKEEPER_HOME/pseudo_conf/zk3

$ZOOKEEPER_HOME/bin/zkServer.sh start ./zk3.cfg

启动以后,使用zkCli连接服务:

${ZOOKEEPER_HOME}/bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

登录成功之后,执行

#创建主节点
create -e /master "master1.example.com:2223"
#监控临时节点使用stat命令
stat /master true
create /workers ""
create /tasks ""
create /assign ""
#监控workers目录
ls /workers true
#监控tasks目录
ls /tasks true
创建worker
create -e /workers/worker1.example.com "worker1.example.com:2224"
create /assign/worker1.example.com ""
#监控持久节点使用ls命令
ls /assign/worker1.example.com true

create -s /tasks/task- "cmd"
create /assign/worker1.example.com/task-0000000000 ""