ZooKeeper的典型应用场景之分布式协调/通知。
博文中的内容来源《从Paxos到Zookeeper 分布式一致性原理与实践》这一本书,感激不尽。
分布式协调/通知服务是分布式系统中不可缺少的一个环节,是将不同的分布式组件有机结合起来的关键所在。对于一个在多台机器上部署运行的应用而言,通常需要一个协调者(Coordinator)来控制整个系统的运行流程,例如分布式事务的处理、机器间的互相协调等。同时,引入这样一个协调者,便于将分布式协调的职责从应用中分离出来,从而可以大大减少系统之间的耦合性,而且能够显著提高系统的可扩展性。
ZooKeeper中特有的Watcher注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与通知,从而实现对数据变更的实时处理。基于ZooKeeper实现分布式协调与通知功能,从而实现对数据变更的实时处理。基于ZooKeeper实现分布式协调与通知功能,通常的做法是不同的客户端都对ZooKeeper上同一个数据节点进行Watcher注册,监听数据节点的变化(包括数据节点本身及其子节点),如果数据节点发生变化,那么所有订阅的客户端都能够接收到相应的Watcher通知,并做出相应的处理。
MySQL数据复制总线:Mysql_Replicator
MySQL数据复制总线(以下简称“复制总线”)是一个实时数据复制框架,用于在不同的MySQL数据库实例之间进行异步数据复制和数据变化通知。整个系统是一个由MySQL数据库集群、消息队列系统、任务管理监控平台以及ZooKeeper集群等组件共同构成的一个包含数据生产者、复制管道和数据消费者等部分的数据总线系统,下图所示该系统的整体结构图。
在该系统中,ZooKeeper主要负责进行一系列的分布式协调工作,在具体的实现上,根据功能将数据复制组件划分为三个核心子模块:Core、Server和Monitor,每个模块分别为一个单独的进程,通过ZooKeeper进行数据交换。
- Core实现了数据复制的核心逻辑,其将数据复制封装成管道,并抽显出生产者和消费者两个概念,其中生产者通常是MySQL数据库的Binlog日志。
- Server负责启动和停止复制任务。
- Monitor负责监控任务的运行状态,如果在数据复制期间发生异常或出现故障会进行告警。
三个子模块之间的关系如下图所示。
每个模块作为独立的进程运行在服务器,运行时的数据和配置信息均保存在ZooKeeper上,Web控制台通过ZooKeeper上的数据获取到后台进程的数据,同时发布控制信息。
任务注册
Core进程在启动的时候,首先会向/mysql_replicator/tasks节点(以下简称“任务列表节点”)注册任务。例如,对于一个“复制热门商品”的任务,Task所在机器在启动的时候,会首先在任务列表节点上创建一个子节点,例如/mysql_replicator/tasks/copy_hot_item(以下简称“任务节点”),如下图所示。如果在注册过程中发现该子节点已经存在,说明已经有其他Task机器注册了该任务,因为自己不需要再创建该节点了。
任务热备份
为了应对复制任务故障或者复制任务所在主机故障,复制组件采用“热备份”的容灾方式,即将同一个复制任务部署在不同的主机上,我们称这样的机器为“任务机器”,主、备任务机器通过ZooKeeper互相检测运行健康状况。
为了实现上述热备方案,无论在第一步中是否创建了任务节点,每台任务机器都需要在/mysql_replicator/task/copy_hot_item/instances节点上将自己的主机名注册上去。注意,这里注册的节点类型很特殊,是一个临时的顺序节点。在注册完这个子节点后,通常一个完整的节点名如下:/mysql_replicator/task/copy_hot_item/instances/[Hostname]-1,其中最后的序列号是临时顺序节点的精华所在。
在完成该子节点的创建后,每台任务机器都可以获取到自己创建的节点的完成节点名以及所有子节点的列表,然后通过对比判断自己是否是所有子节点中序号最小的。如果自己是序号最小的子节点,那么就将自己的运行状态设置为RUNNING,其余的任务机器则将自己设置为STANDBY——我们将这样的热备份策略称为“小序号优先”测路。
热备切换
完成运行状态的标识后,任务的客户端机器就能够正常工作了,其中标记为RUNNING的客户端机器进行正常的数据复制,而标记为STANDBY的客户端机器则进入待命状态。这里所谓待命状态,就是说一旦标记为RUNNING的机器出现故障停止了任务执行,那么就需要在所有标记为STANDBY的客户端机器中再次按照“小序号优先”策略来选出RUNNING机器来执行,具体的做法就是标记为STANDBY的机器都需要在/mysql_replicator/task/copy_hot_item/instances节点上注册一个“子节点列表变更”的Watcher监听,用来订阅所有任务执行机器的变化情况—— 一旦RUNNING机器宕机与ZooKeeper断开链接后,对应的节点就会消失,于是其他机器也就接收到了这个变更通知,从而开始新一轮的RUNNING选举。
记录执行状态
既然使用了热备份,那么RUNNING任务机器就需要将运行时的上下文状态保留给STANDBY任务机器。在这个场景中,最主要的上下文状态就是数据复制过程中的一些进度信息,例如Binlog日志的消费位点,因此需要将这些信息保存到ZooKeeper上以便共享。在Mysql_Replicator的设计中,选择了/mysql_replicator/task/copy_hot_item/lastCommit作为Binlog日志消费位点的存储节点,RUNNING任务机器会定时向这个节点写入当前的Binlog日志消费位点。
控制台协调
在上文中我们主要讲解了Core组件是如何进行分布式任务协调的,接下来我们再看看Server是如何来管理Core组件的。在Mysql_Replicator中,Server主要的工作就是进行任务的控制,通过ZooKeeper来对不同的任务进行控制与协调。Server会将每个复制任务对用生产者的元数据,即库名、表名、用户名与密码等数据库信息以及消费者的相关信息以配置的形式写入任务节点/mysql_replicator/tasks/copy_hot_item中去,以便该任务的所有任务机器都能够共享该复制任务的配置。
冷备切换
到目前为止我们已经基本了解了Mysql_Replicator的工作原理,现在再回头看上面提到的热备份。在该热备份方案中,针对一个任务,都会至少分配两台任务机器来进行热备份,但是在一定规模的大型互联网公司中,往往有许多MySQL实例需要进行数据复制,每个数据库实例都会对应一个复制任务,如果每个任务都进行双机热备份的话,那么显然需要消耗太多的机器。
因此,我们同时设计了一种冷备份的方案,他和热备份方案最大的不同点在于,对所有任务进行分组,如下图所示。
和热备份中比较大的区别在于,Core进程被配置了所属Group(组)。举个例子来说,假如一个Core进程被标记了group1,那么在Core进程启动后,会到对应的ZooKeeper group1节点下面获取所有的Task列表,假如找到了任务“cop_hot_item”之后,就会遍历这个Task列表的instances节点,但凡还没有子节点的,则会创建一个临时的顺序节点:/mysql_replicator/task/copy_hot_item/instances/[Hostname]-1——当然,在这个过程中,其他Core进程则会自动将自己创建的子节点删除,然后继续遍历下一个Task节点——我们将这样的过程称为“冷备份扫描”。就这样,所有Core进程在一个扫描周期内不断的对相应的Group下面的Task进行冷备份扫描。整个过程可以通过如下图所示的流程图来表示。
冷热备份对比
从上面的讲解中,我们基本对热备份和冷备份两种运行方式都有了一定的了解,现在再来对比下这两种运行方式。在热备份方案中,针对一个任务使用了两台机器进行热备份,借助ZooKeeper的Watcher通知机制和临时顺序节点的特性,能够非常实时的进行互相协调,但缺陷就是机器资源消耗特别大。而在冷备份方案中采用了扫描机制,虽然降低了任务协调的实时性,但是节省了机器资源。
一种通用的分布式系统机器间通信方式
在绝大部分的分布式系统中,系统机器间的通信无外乎心跳检测、工作进度汇报和系统调度这三种类型。接下来,我们将围绕这三种类型的机器通信来讲解如何基于ZooKeeper去实现一种分布式系统间的通信方式。
心跳检测
机器间的心跳机制是指在分布式环境中,不同机器之间需要检测到彼此是否在正常运行,例如A机器需要知道B机器是否正常运行。在传统的开发中,我们通常是通过主机之间是否可以相互PING通来判断,更复杂一点的话,则会通过在机器之间建立长连接,通过TCP连接固有的心跳检测机制来实现上层机器的心跳检测,这些确实都有一些非常常见的心跳检测方法。
下面来看看如何使用ZooKeeper来实现分布式机器间的心跳检测。基于ZooKeeper的临时节点特性,可以让不同的机器都在ZooKeeper的一个指定节点下创建临时子节点,不同的机器之间可以根据这个临时节点来判断对应的客户端机器是否存活。通过这种方式,检测系统和被检测系统之间并不需要直接相关联,而是通过ZooKeeper上的某个节点进行关联,大大减少了系统耦合。
工作进度会报
在一个常见的任务分发系统中,通常任务被分发到不同的机器上执行后,需要实时的将自己的任务执行进度汇报给分发系统。这个时候就可以通过ZooKeeper来实现。在ZooKeeper上选择一个节点,每个任务客户端都在这个节点下面创建临时子节点,这样便可以实现两个功能:
- 通过判断临时节点是否存在来确定任务机器是否存活;
- 各个任务机器会实时的将自己的任务进度写到这个临时节点上去,以便中心系统能够实时的获取到任务的执行进度。
系统调度
使用ZooKeeper,能够实现另一种系统调度模式:一个分布式系统由控制台和一些客户端系统两部分组成,控制台的职责就是需要将一些指令信息发送给所有的客户端,以控制他们进行相应的业务逻辑。后天管理人员在控制台上做的一些操作,实际上就是修改了ZooKeeper上某些节点的数据,而ZooKeeper进一步把这些数据变更以事件通知的形式发送给了对应的订阅客户端。
总之,使用ZooKeeper来实现分布式系统机器间的通信,不仅能省去大量底层网络通信和协议设计上重复的工作,更为重要的一点是大大降低了系统之间的耦合,能够非常方便的实现异构系统之间的灵活通信。
更多推荐
所有评论(0)