控制台下利用Zookeeper模拟分布式系统协同

前言

我们知道包括HBase,Kafka在内的许多分布式系统底层都采用zookeeper来实现分布式任务协作。使用Zookeeper开发分布式系统,可以让我们不用过多地纠结于分布式协同的一些极端概念,允许我们把更多的精力放在应用本身的逻辑上。当然,哪怕你不直接参与分布式系统的开发,了解zookeeper是怎样帮助我们构建一个分布式系统的,也可以让你在使用类似的一些工具上更加得心应手,触类旁通。

准备工作&基础知识

进入正题之前,不妨让我们先来看看分布式系统的核心意义在哪里。个人的理解,就是把任务并行化,通过把一个大的任务,划分成许多小的任务,分配给不同的处理单元(可能是线程,进程或者是机器),让这些处理单元同时处理这些任务来加快任务执行的速度。而通过分布式系统来实现任务并行化,和多线程&多进程并行有什么区别的?我认为至少包括以下几点:
1. 数据同步。不同于多线程和多进程可以利用共享内存来进行协同做工,分布式系统的各个机器节点之间只能通过网络传输或者共享文件来实现消息通信。消息延迟,时钟偏移等等问题,如何在不可靠的通信基础上构建可靠的协同机制,是分布式系统首先要考虑的。
2. 崩溃检测。多线程和多进程因为共享一台操作系统,健壮的操作系统可以保证线程&进程之间的崩溃可以很及时地被检测并做出处理。但在网络环境中,不同机器之间如果发生崩溃,相互之间可能完全没法知晓。甚至由于通信延迟,处理器性能问题等原因,如何判断一台机器是延时还是崩溃,也是崩溃检测需要处理的。当然完成崩溃检测之后还要对崩溃机器未处理完的任务进行接手,如何快速接盘,如何保证事务安全这也是需要考虑的。
3. 元数据管理。我们把应用业务相关的数据称为业务数据,比如数据库表,任务日志等等;把分布式系统保证自身稳定运行的数据称为协同数据或者叫元数据,比如当前系统主从节点信息,任务队列信息等等。如何保证元数据在系统中的一致性可用性,也是需要考虑的。
在理出上面这些分布式计算中普遍会遇到的难点之后,我们就可以来看看通过zookeeper构建的是怎样处理这些问题的。

数据树结构

zookeeper采用主-从架构,使用共享存储模型来实现应用间的协作和同步,采用类似于文件系统的层级树状结构进行管理。类似于:
这里写图片描述
图中的每个数据节点跟分布式系统中的节点一一对应。比如,/master节点即主节点,该节点下面保存者主节点的信息;/workers节点对应从节点,其下每个节点worker-n代表一个可用从节点。等等。这些数据即是上文所说的元数据,有了他们一个完整的分布式系统才可以运行起来。

znode的不同类型

可以知道,机器节点/master和/workers对应的计算机是可能随时崩溃的(或者因为延时被误认为崩溃),当一台机器崩溃之后,如何保证其在数据树中的位置相应被回收?zookeeper提供了临时节点供我们使用,当我们创建该临时节点的客户端崩溃或关闭连接时,这个节点就会被删除。所以,当机器崩溃断开连接后,它所对应的znode会被zookeeper删除。
与机器节点相对的是任务节点,当一台机器崩溃时,它所负责的任务并不能抛弃,所以就有了永久节点。永久节点,只有通过显示调用delete方法才能删除。
同时,zookeeper还支持为节点动态添加一个自增整数作为标识,用以指示不同节点间的创建顺序。

通知

节点信息保存在数据树中之后,各个节点如何访问数据?
最常见的方法是轮询
这里写图片描述
而它带来的问题也是显而易见的,过于频繁的读取会耗费太多资源。zookeeper采用基于通知的机制来使用数据。客户端向zookeeper注册需要接收通知的znode。

版本

因为zookeeper的分布式架构,可能存在多台主节点机器之间互相的进度不一致。比如有S1和S2两台主节点可供客户端选择,客户端会根据之前链接的主节点数据版本来判断应该链接哪台主节点,只接受版本比旧节点新的主节点作为下一个连接对象。

过程模拟

上文已经粗略把zookeeper架构的核心概念介绍了一遍,下面我们便可以利用上面的概念,通过zookeeper控制台终端,模拟一遍分布式系统是怎么借助zookeeper的协同来工作的。、

第一步,创建三个重要的一级znode,而创建的任务在实际业务中通常由主节点完成,这里模拟单主节点系统,所以省略掉主节点在数据树中的位置:
- /workers :保存可用从节点列表的信息
- /tasks :保存任务列表信息
- /assign:保存任务分配列表信息

create /workers ""
create /tasks ""
create /assign ""

/**主节点还要监控从节点信息和任务列表信息。所以在这里通过ls /目录位置 true 的语法创建监控点,当目录发生变化时,主节点会收到对应的通知**/
ls /workers true
ls /tasks true

第二步,注册从节点机器

/**添加-e参数表示创建的是一个临时节点,当创建此znode的从节点机器崩溃后,zookeeper会负责删除该znode**/
create -e /workers/worker1 ""

第三步,创建从节点任务分配节点

/**当需要给该节点分配任务时,可以往此节点添加具体的任务节点**/
create -e /assign/worker1 ""
/**从节点还要持续监控它的任务分配节点,当有新任务时及时处理**/
ls /assign/worker1 true

第四步,客户端创建任务

/**客户端创建一个新的任务到任务队列,并监控它的变化**/
create /tasks/task-1 "cmd"
ls /task/task-1 true

第五步,主节点收到新任务通知,给从节点分配任务

/**主节点先确认有新任务,并且存在可用的从节点来处理任务**/
ls /tasks
[task-1]
ls /workers
[worker1]

/**主节点为从节点的任务分配节点创建新任务**/
create /assign/worker1/tasks-1 ""

第六步,从节点接收到分配任务,处理任务,并完成任务

 /**从节点确认有新任务**/
 ls /assign/worker1
 [task-1]

 /**从节点处理任务**/

/**从节点标志任务完成**/ 
ls /tasks/task-1/status "done"

第七步,客户端收到任务变更通知,查询/tasks/task-1/status节点的内容为“done”,表示任务确实完成。
结束。

结语

上面的例子虽然很简陋,但是基本上把利用zookeeper来构建分布式系统的常用方式抽象地描述了一遍,希望对各位有帮助~
The End.

你可能感兴趣的:(分布式)