zookeeper 是一个典型的发布/订阅模式的分布式数据管理和协调框架,开发人员可以使用它来进行分布式数据的发布和订阅。另外一方面,通过对 zookeeper 中丰富的数据节点类型进行交叉使用,配合 Watcher 事件通知机制,可以非常方便的构建一系列分布式应用中会涉及的核心功能,如数据发布/订阅,负载均衡,命名服务,分布式协调/通知,集群管理,Master 选举,分布式锁和分布式队列等。1.典型的应用场景zookeeper 是一个高可用的分布式数据管理和协调框架。基于对 zab 算法的实现,该框架能够很好的保证分布式环境中数据的一致性。也是基于这样的特性,使得 zookeeper 成为了分布式一致性问题的利器。1.数据发布/订阅数据的发布/订阅系统,即所谓的配置中心,顾名思义就是发布者将数据发布到 zookeeper 的一个或者一系列的节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和数据的动态更新。发布/订阅系统一般有2种模式,分别是推(Push)模式和拉(Pull)模式。在推模式中,服务器主动将数据更新发送给所有订阅的客户端;而拉模式则是由客户端主动发起请求来获取最新的数据,通常客户端采用定时进行轮询拉去的方式。zookeeper 采用了推拉结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变化,那么服务端就会向相应的客户端发送 Watcher 事件通知,客户端接收到这个消息通知之后,需要主动到服务端获取最新的数据。如果将配置信息放到 zookeeper 上进行集中管理,那么通常情况下,应用在启动的时候都会主动到 zookeeper 服务端上进行一次配置信息的获取,同时,在指定节点上注册一个 Watcher 监听,这样一来,但凡配置信息发生改变,服务端都会实时通知到所有订阅的客户端,从而达到实时获取最新配置信息的目的。平常管理配置的方式:本地配置文件和内存变量中。zookeeper 如何管理配置的:1.配置存储 : 我们将需要初始化的配置存储到 zookeeper 上去。一般情况,我们可以在 zookeeper 上选取一个数据节点用于配置的存储。#DBCPdbcp.driverClassName=com.mysql.jdbc.Driverdbcp.dbJDBCUrl=jdbc:mysql://1.1.1.1:3306/taokeeperdbcp.username=usernamedbcp.password=password2.配置获取 : 机器启动的时候,从这个节点获取信息,同时在该节点上注册一个数据变更的 Watcher 监听。3.配置更新 : zookeeper 可以将数据更新发送到各个客户端。2.负载均衡一种动态 DNS 服务:当应用的机器规模在一定范围内,并且域名的变更不是特别频繁,本地 HOST 绑定是非常高效且简单的做法。然后一旦机器规模变大后,就不方便了。现在基于 zookeeper 实现的动态 DNS 方案(DDNS)。1.域名配置:创建一个节点来配置域名。 /DDNS/app1/server.app1.company1.com#单个IP:PORT192.168.0.1:8080#多个IP:PORT192.168.0.1:8080,192.168.0.2:80802.域名解析在传统的 dns 解析中,我们都不需要关心域名的解析过程,所有这些工作都交给了操作系统的域名和ip地址映射机制(本地HOST绑定)或者是专门的域名解析服务器。因此,在这点上,DDNS 方案和传统的域名解析有很大区别 --- 在 DDNS 中,域名的解析过程都是由每一个应用自己负责的。通常应用都会首先从域名节点中获取一份 ip 地址和端口的配置,进行自行解析。同时,每个应用还会在域名节点上注册一个数据变更的 Watcher 监听,以便及时收到域名变更的通知。3.域名变更在运行过程中,难免碰上域名对应的ip地址或是端口变更,这个时候需要进行域名变更操作。在 DDNS 中,我们只需要对指定的域名节点进行更新操作,zookeeper 就会向订阅的客户端发送这个事件通知,应用在接收到这个事件通知后,就会再次进行域名配置的获取。通过zookeeper 来实现动态 dns 服务,一方面,可以避免域名数量无限增长带来的集中式维护成本,另一方面,在域名变更的情况下,也能够避免逐台更新本地 HOST 而带来的繁琐工作。3.命名服务在分布式系统中,被命名的实体通常可以是集群中的机器,提供的服务地址或远程对象等 --- 这些我们都可以统称它们为名字(Name),其中较为常见的就是一些分布式服务框架(如 RPC, RMI)中的服务地址列表,通过使用名字服务,客户端能够根据指定名字来获取资源的实体,服务地址和提供者的信息等。zookeeper 提供的命名服务功能与 JNDI 技术有相似的地方,都能够帮助应用系统通过一个资源引用的方式来实现对资源的定位于使用。另外,广义上命名服务的资源定位都不是真正意义的实体资源 --- 在分布式环境中,上层应用仅仅需要一个全局唯一的名字,类似于数据库中的唯一主键。UUID 是通用唯一标识码,包含32位字符和4个短信的字符串。缺点:1.长度过长2.含义不明使用zookeeper生成唯一 ID 的基本步骤:1.所有的客户端都会根据自己的任务类型,在指定类型的任务下面通过调用 create() 接口来创建一个顺序节点,例如创建 'job-' 节点。2.节点创建完毕后,create() 接口会返回一个完整的节点名,例如 'job-0000000003'3.客户端拿到这个返回值后,拼接上 type 类型,例如 'type2-job-0000000003',这个就可以作为全局id了在 zookeeper 中,每一个数据节点都能够维护一份子节点的顺序序列,当客户端对其创建一个顺序子节点的时候 zookeeper 会自动以后缀的形式在其子节点上添加一个序号,在这个场景中就利用了 zookeeper 这个特性。4.分布式协调/通知分布式协调/通知服务是分布式系统中不可缺少的一个环节,是将不同的分布式组件有机结合起来的关键所在。对于一个在多台机器上部署运行的应用而言,通常需要一个协调者(Coordinator)来控制整个系统的运行流程,例如分布式事务的处理,机器间的互相协调等。同时,引入这样的协调者,便于将分布式协调的职责从应用中分离出来,从而可以减少系统之间的耦合性,而且能够显著提高系统的可扩展性。zookeeper 中特有的 Watcher 注册和异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与通知,从而实现对数据变更的实时处理。基于 zookeeper 实现分布式协调与通知功能,通常的做法是不同的客户端都对 zookeeper 上同一个数据节点进行 Watcher 注册,监听数据节点的变化(包括数据节点本身及其子节点),如果数据节点发生变化,那么所有订阅的客户端都能够接收到相应的 Watcher 通知,并作出相应的处理。一种通用的分布式系统机器间通信方式:1.心跳检测机器间的心跳检测是指在分布式环境中,不同机器之间需要检测到彼此是否在正常运行。在传统的开发中,我们通常是通过主机之间是否可以ping通来判断,更复杂一点的话,则会通过机器之间建立长连接,通过tcp固有的心跳检测机制来实现上层机器的心跳检测。基于 zookeeper 的临时节点特性,可以让不同的机器都在 zookeeper 的一个指定节点下创建临时子节点,不同的机器之间可以根据这个临时节点来判断对应的客户端机器是否存活。通过这种方式,检测系统和别检测系统之间并不需要直接相关联,而是通过 zookeeper 上的某个节点进行关联,大大减少耦合。2.工作进度汇报在一个常见的任务分发系统中,通常任务被分发到不同的机器上执行后,需要实时的将自己的任务执行进度汇报给分发系统。这个时候就可以通过 zookeeper 来实现。在 zookeeper 上选择一个节点,每个任务客户端都在这个节点下面创建临时子节点,这样便可以实现2个功能:1.通常判断临时节点是否存在来确定任务机器是否存活2.各个机器会实时的将自己的任务执行进度写到这个临时节点上去,以便中心系统能够实时的获取任务的执行进度。3.系统调度一个分布式系统由控制台和一些客户端系统两部分组成,控制台的职责就是需要将一些指令信息发送给所有的客户端,以控制它们进行相应的业务逻辑。后台管理人员在控制台上做一些操作,实际上就是修改了 zookeeper 上的某些节点的数据,而 zookeeper 进一步把这些数据变更以事件通知的形式发送给了对应的订阅客户端。5.集群管理所谓集群管理,包括集群监控与集群控制两大块,前者侧重对进群运行时状态的收集,后者则是对集群进行操作与控制。经常会有类似如下的需求:1.希望知道当前集群中有多少台机器在工作2.对集群中每台机器运行时状态的收集3.对集群中机器进行上下线的操作在传统的基于 Agent 的分布式集群管理体系中,都是通过在集群中的每台机器上部署一个Agent,由这个 agent 负责主动向指定的一个监控中心系统(监控中心系统负责将所有数据进行集中处理,形成一系列报表,并负责实时报警)汇报自己所在机器的状态。在集群规模适中的场景下比较合适。缺点:1.大规模升级困难2.统一的 agent 无法满足多样性的需求对于机器的cpu使用率,负载,内存使用率,网络吞吐以及磁盘容量,是可以监控。但业务监控比较不合适。3.编程语言的多样化zookeeper 具有以下两个特性:1.客户端如果对 zookeeper 的一个数据节点注册 Watcher 监听,那么当该数据节点的内容或是其子节点列表发生变化时,zookeeper 服务器就会向订阅的客户端发送变更通知。2.对在 zookeeper 上创建的临时节点,一旦客户端与服务器之间的会话失效,那么该临时节点也就被自动删除了.分布式日志收集系统:分布式日志收集系统的核心工作就是收集分布在不同机器上的系统日志。在一个典型的日志系统的架构设计中,整个日志系统会把所有需要收集的日志机器(日志源机器)分为多个组别,每个组别对应一个收集器,这个收集器其实就是一个后台机器(收集器机器),用于收集日志。对于大型的分布式日志系统,通常需要解决如下问题:1.变化的日志源机器2.变化的收集器机器无论是日志源机器还是收集器机器的变更,最终都归结为一点:如何快速,合理,动态的为每个收集器分配对应的日志源机器。1.注册收集器机器使用 zookeeper 来进行日志系统收集器的注册,典型的做法是在 zookeeper 上创建一个节点作为收集器的根节点,例如 /logs/collector,每个收集器机器在启动的时候,都会在收集器节点下创建自己的节点。例如 /logs/collector/[Hostname]。2.任务分发待所有收集器机器都创建好自己对应的节点后,系统根据收集器节点下面子节点的个数,将所有日志源机器分成对应的若干组,然后将分组后的机器列表分别写到这些收集器机器创建的子节点(例如 /logs/collector/host1)上去。这样一来,每个收集器机器都能够从自己对应的收集器节点上获取日志源机器列表,进而开始进行日志收集工作。3.状态汇报在完成收集器机器的注册以及任务分发后,我们还要考虑到这些机器随时都有可能挂掉的可能。因此,针对这个问题,我们需要有一个收集器的状态汇报机制:每个收集器机器在创建完自己的专属节点后,还需要在对应的子节点上创建一个状态子节点,例如 /logs/collector/host1/status,每个收集器机器都需要定期向该节点写入自己的状态信息。我们把这看做是一种心跳检测机制,通常收集器机器都会在这个节点中写入日志收集进度信息。日志系统工具该状态子节点最后更新时间来判断对应的收集器机器是否存活。4.动态分配如果收集器机器挂掉或者是扩容了,就需要动态的进行任务收集分配。在运行过程中,日志系统始终关注着 /logs/collector 这个节点下所有的子节点的变更,一旦检测到有收集器机器停止汇报或者是有新的收集器机器加入,就要开始进行任务的重新分配。无论是针对收集器机器停止汇报还是新机器加入的情况,日志系统都需要将之前分配给该收集器的所有的任务进行转移。为了解决这个问题,通常有2种做法:1.全局动态分配这是一种简单粗暴的方式,在出现收集器机器挂掉或是新机器加入的时候,日志系统需要根据新的收集器机器列表,立即对所有的日之源机器重新进行一次分组,然后将其分配给剩下的收集器机器。2.局部动态分配全局动态分配存在一个问题:一个或部分收集器机器的变更,就会导致全局动态任务的分配,影响面比较大,因此风险也就比较大。局部动态分配,每个收集器机器在汇报自己日志收集状态的同事,也会把自己的负载汇报上去。根据负载进行分配。5.注意事项1.节点类型2.日志系统节点监听在线云主机管理:在传统的实现方案中,监控系统通过某种手段(比如检测主机的指定端口)来对每台机器进行定时检测,或者每台机器自己定时向监控系统汇报'我还活着'。但是这种方式需要每一个业务系统的开发人员自己来处理网络通信,协议设计,调度和容灾等诸多繁琐的问题。需求点如下:1.快速统计出一共多少台服务器2.快速获取机器上/下线的情况3.实时监控集群中每台主机的运行状态1.机器上/下线通常在新增机器的时候,需要首先将指定的 Agent 部署到这台机器上。agent 部署启动后,会首先向 zookeeper 的指定节点进行注册,具体的做法就是在机器列表节点下面创建一个临时子节点,例如 /XAE/machine/[Hostname]。当 agent 在 zookeeper 上创建完这个子节点后,对 /XAE/machine 节点关注的监控中心就会收到 '子节点变更' 事件,即上线通知,于是就可以对这个新加入的机器开启相应的后台管理逻辑。另一方面,监控中心同样可以获取到机器下线的通知,这样就可以实现对机器上/下线的检测,同时能够很容易的获取到在线的机器列表。2.机器监控在运行的过程中,agent 会定时将主机的运行状态信息写入 zookeeper 上的主机节点,监控中心通过订阅这些节点的数据变更通知来间接的获取主机的运行信息。6.Master 选举分布式最核心的特性就是能够将具有独立计算能力的系统单元部署在不同的机器上,构成一个完整的分布式系统。在分布式系统中,Master 往往用来协调集群中的其他系统单元,具有对分布式系统状态变更的决定权。如,在一些读写分离的应用场景中,客户端写往Master写;另外一些场景,Master通常负责一些复杂的逻辑,并将处理结果同步给集群中其他系统单元。Master 选举过程:在所有的机器中选举出一台机器作为 Master。通常情况下,我们可以选择关系型数据库中的主键特性来实现:集群中的所有机器都向数据库中插入一条相同主键id的记录,数据库会帮助我们自动进行主键冲突检查。所有进行插入操作的客户端机器中,只有一台成功 --- 那么插入成功的就是Master。但是这台机器挂了,关系型数据库没法通知我们。利用 zookeeper 的强一致性,能够很好的保证在分布式高并发情况下节点的创建一定能够保证全局唯一性,即 zookeeper 将会保证客户端无法重复创建一个已经存在的数据节点。也就是说,如果同时有很多客户端请求创建同一个数据节点,那么最终一定只有一个客户端能够请求成功。利用这个特性,就能很容易的在分布式环境中进行Master选举了。在这个系统中,首先会在 zookeeper 上创建一个日期节点,例如 '2013-09-20'.客户端集群每天都会定时往 zookeeper 上创建一个临时节点,例如 /master_election/2013-09-20/binding。在这个过程中,只有一个客户端能够成功的创建这个节点,那么这个客户端所在的机器就成为了Master。同时,其他没有在zookeeper 上成功创建节点的客户端,都会在节点 /master_election/2013-09-20 上注册一个子节点变更的 Watcher,用于监控当前的Master机器是否存活,一旦发现当前的 Master 挂了,那么其他的客户端将会重新进行 Master 选举。如果我们仅仅只是想实现 Master 选举的话,那么其实只需要有一个能够保证数据唯一性的组件即可。7.分布式锁1.排他锁:排它锁(Execlusive Locks,简称X锁),又称为写锁或独占锁,是一种基本的锁类型。如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能再对这个数据对象进行任何类型的操作 --- 直到 T1 释放了排它锁。排它锁的核心是如何保证当前有且仅有一个事务获得锁,并且锁被释放之后,所有正在等待锁的事务都能够被通知到。定义锁:通过 zookeeper 上的数据节点来表示一个锁,例如 /exclusive_lock/lock 节点就可以被定义为一个锁。获取锁:在需要获取排他锁时,所有的客户端都会试图通过调用 create() 接口,在 /exclusive_lock 节点下创建临时子节点 /exclusive_lock/lock。zookeeper 会保证在所有的客户端中,最终只有一个客户端能够创建成功,那么就可以认为该客户端获取了锁。同时,所有没有获取锁的客户端就需要到 /exclusive_lock 节点上注册一个子节点变更通知的 Watcher 监听,以便实时听到 lock 节点的变更情况。释放锁:/exclusive_lock/lock 是一个临时节点,因此在以下2种情况,都有可能释放锁:1.当前获取锁的客户端机器发生宕机,那么zookeeper 上的这个临时节点就会被删除。2.正常执行完业务逻辑后,客户端就会主动将自己创建的临时节点删除无论在什么情况下移除了 lock 锁,zookeeper 都会通知到所有在 /exclusive_lock 节点上注册了子节点变更 Watcher 监听的客户端。这些客户端在接收到通知后,再次重新发起分布式锁获取,即重复'获取锁'过程。2.共享锁:共享锁(Shared Locks,简称S锁),又称为读锁,同样是一种基本的锁类型。如果事务T1对数据对象O1加上了共享锁,那么当前事务只能对O1进行读取操作,其他事务也只能对这个数据对象加共享锁 --- 直到该对象上的所有共享锁都被释放。共享锁和排它锁的区别在于,加上排它锁后,数据对象只对一个事务可见,而加上共享锁后,数据对所有的事务可见。定义锁:通过 zookeeper 上的数据节点来表示一个锁,是一个类似于 '/share_lock/[Hostname]-请求类型-序号' 的临时顺序节点,例如 /share_lock/192.168.0.1-R-0000000001,那么这个节点就代表了一个共享锁。获取锁:在需要获取共享锁的时候,所有客户端都会到 /share_lock 这个节点下面创建一个临时顺序节点,如果当前是读请求,那么就创建 /share_lock/192.168.0.1-R-0000000001;如果是写请求,/share_lock/192.168.0.1-W-0000000001判断读写顺序:根据共享锁的定义,不同的事务都可以同时对一个数据对象进行读取操作,而更新操作必须在当前没有任何事务进行读写操作的情况下进行。基于这个原则,我们来看看如何通过 zookeeper 的节点来确定分布式读写顺序,大概4个步骤:1.创建完节点,获取 /share_lock 节点下面的所有子节点,并对该节点注册子节点变更的 Watcher 监听2.确定自己的节点序号在所有子节点中的顺序。3.对于读请求:如果没有比自己序号小的子节点,或是所有比自己序号小的子节点都是读请求,那么表明自己已经成功获取了共享锁,同时开始执行读取逻辑。如果比自己序号小的子节点中有些请求,那么就需要进入等待;对于写请求:如果自己不是序号最小的子节点,那么就需要进入等待。释放锁:   同排它锁一样。羊群效应:zookeeper 发送了子节点变更 Watcher 通知所有机器,然后这个通知除了给 192.168.0.2 这台机器产生实际影响,对余下的其他所有机器都没有任何作用。短时间内发送大量的事件通知 --- 这就是所谓的羊群效应。上面这个 zookeeper 分布式共享锁实现中出现羊群效应的根源在于,没有找准客户端真正的关注点。分布式锁竞争的过程,核心的逻辑在于:判断自己是否是所有子节点序号中最小的。于是,很容易联想到,每个节点对应的客户端只需要关注比自己序号小的那个相关节点的变更情况就可以了 --- 而不需要关注全局的子列表变更情况。改进后的分布式锁实现:这里的主要改动在于:每个锁竞争者,只需要关注 /share_lock 节点下序号比自己小的那个节点是否存在即可,具体实现如下:1.客户端调用 create() 方法创建一个类似于 '/share_lock/[Hostname]-请求类型-序号'的临时顺序节点2.客户端调用 getChildren() 接口来获取所有已经创建的子节点列表,注意,这里不需要任何 Watcher3.如果无法获取共享锁,那么就调用 exist() 来对对比自己小的那个节点注册 Watcher。注意,这里'比自己小的节点'只是一个笼统的说法,具体对于读请求和写请求不一样。读请求:向比自己序号小的最后一个写请求节点注册 Watcher 监听写请求:向比自己序号小的最后一个节点注册 Watcher 监听4.等待 Watcher 通知,继续进入步骤2注意:如同在多线程并发编程中,我们会尽量去缩小锁的范围 --- 对于分布式锁实现的改进也是同样的思路。8.分布式队列     分布式队列,简单来说分为2类:一种是常规的先入先出队列,另外一种则是要等队列元素聚集之后才同意安排执行的 Barrier 模型。1.FIFO:先入先出使用 zookeeper 实现 FIFO 队列,和上面提到的共享锁的实现非常类似。FIFO 队列就类似于一个全写的共享锁模型,大体思路:所有客户端都会到 /queue_fifo 这个节点下面创建一个临时顺序节点,例如 /queue_fifo/192.168.0.1-0000000001。创建完节点后,根据如下4个步骤来确定执行顺序:1.通过调用 getChildren()接口来获取 /queue_fifo 节点下面的所有子节点,即获取队列中所有的元素。2.确定自己的节点序号在 所有子节点中的顺序3.如果自己不是最小的子节点,那么就需要进入等待,同时向比自己序号小的最后一个节点注册 Wather 监听4.接收到 Watcher 通知后,重复步骤12.Barrier:分布式屏障Barrier 在分布式系统中,特指系统之间的一个协调条件,规定了一个队列的元素必须都集聚后才能统一进行安排,否则一直等待。这往往出现在那些大规模分布式并行计算的应用场景上:最终的合并计算需要基于很多并行计算的子结果来进行。这些队列其实是 FIFO 队列的基础上进行了增强,大致设计思路如下:开始时,/queue_barieer节点是一个已经存在的默认节点,并且将其节点的数据内容赋值为一个数字n来代表 Barrier 值,例如 n=10 代表只有 /queue_barrier 节点下的子节点个数达到 10 后,才会打开 Barrier。之后,所有的客户端都会到 /queue_barrier 节点下创建一个临时节点。例如 /queue_barrier/192.168.0.1 创建完节点后,根据5个步骤来确定执行顺序:1.通过调用 getData() 接口获取 /queue_barrier 节点的数据内容:102.通过调用 getChildren() 接口获取 /queue_barrier 节点下的所有子节点,即获取队列中的所有元素,同时注册对子节点列表变更的 Watcher 监听3.统计子节点个数4.如果子节点个数还不足10,那么需要进入等待5.接收到 Watcher 通知后,重复步骤2
2.Zookeeper 在大型分布式系统中的应用1.HadoopHadoop 是 Apache 开源的一个大型分布式计算框架,其定义了一种能够开发和运行处理海量数据的软件规范。Hadoop的核心是 HDFS 和 MapReduce分别提供了对海量数据的存储和计算能力。自 0.23.0 版本开始,Hadoop 又引入了新一代的 MapReduce 框架 YARN。在 Hadoop 中 zookeeper 主要用于实现 HA(High Availability),这部分逻辑主要集中在 Hadoop Common 的 HA 模块中。YARN 介绍:YARN 是 Hadoop 为了提高节点 Master(JT)的扩展性,同时为了支持多计算模型和提供资源的细粒度调度而引入的全新一代分布式调度框架。Fencing(隔离):在分布式环境中,经常会出现诸如单机'假死'的情况。所谓的假死是指机器由于网络闪断或是其自身由于负载过高(常见的有GC占用时间过长或CPU 的负载过高等)而导致无法正常的对外进行及时响应。在上述主备切换的过程中,我们假设RM集群由 RM1 和 RM2 两台机器组成,且 RM1 为 Active,RM2 为 Standby。某一时刻,RM1 发生了假死,此时 zookeeper 认为 RM1 挂了,根据主备切换逻辑,RM2 被设置为了 Active。但是随后,RM1 恢复了正常,其依然认为自己还处于Active 状态,这就是我们说的分布式 '脑裂'现象,即存在多个处于 Active 状态的 RM。YARN 中引入了 Fencing 机制,接着 zookeeper 数据节点的 ACL 权限控制机制来实现不同 RM 之间的隔离。具体做法,在上文的 '主备切换'部分中讲到,多个 RM 之间通过竞争创建锁节点来实现主备状态的确定。创建的根节点必须携带 zookeeper 的 ACL 信息,目的是为了独占该根节点,以防止其他 RM 对该节点进行更新。RM1 出现假死后,zookeeper 就会将其创建的锁节点移除,此时 RM2 就会创建相应的节点,并且切换为 Active 状态。RM1 恢复之后,会试图去更新 zookeeper 的相关数据,但是此时发现其没有权限更新 zookeeper 的相关节点数据,也就是说,RM1 发现 zookeeper 上的相关节点不是自己创建的,于是就自动切换为 Standby 状态,这样就避免了脑裂现象出现。2.HbaseHbase,全称 Hadoop Database,是 Google Bigtable 的开源实现,是一个基于 Hadoop 文件系统设计的面向海量数据的高可靠性,高性能,面向列,可伸缩的分布式存储系统,利用 HBase 技术可以在廉价的 pc 服务器上搭建起大规模结构化的存储集群。与大部分分布式NoSQL数据库不同的是,HBase 针对数据写入具有强一致性的特性,甚至包括索引列也能实现强一致性。HBase 在实现上严格遵守了 GoogleBigtable 论文的设计思想。Bigtable 使用了 Chubby 来负责分布式状态的协调。Chubby 是 Google 实现的一种基于 Paxos 算法的分布式锁服务,而HBase 则采用了开源的 zookeeper 服务来完成整个系统的分布式协调工作。3.Kafkakafka 是 LinkedIn 开源的分布式消息系统,主要由 Scala 语言开发。kafka 主要用于实现低延迟的发送和收集大量的事件和日志数据 --- 这些数据通常都是活跃的数据。所谓活跃的数据,在互联网大型的web网站应用中非常常见,通常是指网站的 pv数和用户访问记录等。这些数据通常以日志的形式记录下来,然后由一个专门的系统来进行日志的收集与统计。kafka 是一个吞吐极高的分布式消息系统,其整体设计的典型的发布与订阅模式系统。在kafka 集群中,没有 '中心主节点' 的概念,集群中所有的服务器都是对等的,因此,可以在不做任何配置修改的情况下实现服务器的添加与删除,同样,消息的生产者与消费者也能够做到随意的重启和机器的上下线。术语介绍:消息生产者,即 Producer,是消息产生的源头,负责生成消息并发送到 kafka 服务器上。消息消费者,即 Consumer,是消息的使用方,负责消费 kafka 服务器上的消息主题,即 Topic,由用户定义并配置在 kafka 服务端,用于建立生产者和消费者之间的订阅关系:生产者发送消息到指定的 Topic下,消费者从这个 Topic下消费消息。消息分区,即 Partition,一个 topic 下面会分为许多个分区,例如 'kafka-test'这个 topic 可以分为10个分区,分别由2台服务器提供,那么通常可以配置为让每台服务器提供5个分区,假设服务器id分别为0和1,则所有的分区为 0-0,0-1,0-2,0-3,0-4 和 1-0,1-1,1-2,1-3,1-4。消息分区机制和分区数量与消费者的负载均衡机制有很大的关系。Broker,即kafka的服务器,用于存储消息,在消息中间件中通常被称为 Broker。消费者分组,即 Group,用于归组同类消费者。在 kafka 中,多个消费者可以共同消费一个 topic 下的消息,每个消费者消费其中部分消息,这些消费者就组成了一个分组,拥有同一个分组名称,通常也被称为消费者集群。Offset,消息存储在 kafka 的 Broker 上,消费者拉取消息数据的过程中需要知道消息在文件中的偏移量,这个偏移量就是所谓的 Offset。Broker 注册:kafka 是一个分布式的消息系统,这也体现在 broker,producer和 cunsumer 的分布式部署上。虽然 broker是分布式部署并且互相之间是独立运行的,但还是需要一个注册系统能够将整个集群中的broker服务器都管理起来。在kafka的设计中,选择使用了zookeeper来进行所有的broker 管理。在 zookeeper 上会有一个专门用来进行 broker 服务器列表记录的节点,其节点路径为 /brokers/ids。每个 broker服务器启动时,都会到 zookeeper 上进行注册,即到 broker 节点下创建属于自己的节点,其节点路径为 /broker/ids/[0...N]。从上面的节点路径中,我们可以看出,在 kafka 中,我们使用一个全局唯一的数字来指代每一个 broker 服务器,我们称其为 'broker id',不同的 broker 必须使用不同的 broker id 进行注册,例如 /broker/id/1 和 /broker/id/2 分别代表了两个 broker 服务器。创建完 broker 节点后,每个 broker 就会将自己的 ip 和端口等信息写入到该节点中去。请注意,broker 创建的节点是一个临时节点,也就是说,一旦这个 broker 服务器宕机或者是下线后,那么对应的 broker 节点也被删除了。因此我们可以通过zookeeper上 broker 节点的变化情况来动态表征 broker 服务器的可用性。Topic 注册:在 kafka 中,会将同一个 topic 的消息分成多个分区并将其分布到多个 broker 上,而这些分区信息以及与 broker 对应关系也都是 zookeeper 维护的,由专门的节点来记录,其节点路径为 /brokers/topics。kafka 中的每一个 topic,都会以 /brokers/topics/[topic] 的形式记录在这个节点下,例如,/brokers/topics/login 和 /brokers/topics/search 等。broker 服务器启动后,会到对应的 topic 节点下注册自己的 broker id,并写入针对该 topic 的分区总数。例如,/brokers/topics/login/3 -> 2 这个节点表明broker id 为 3 的一个 broker 服务器,针对 'login' 这个 topic 信息,提供了2个分区进行消息存储。同样,这个分区数节点也是一个临时的节点。生产者负载均衡:kafka 是分布式部署broker服务器的,会对同一个topic的消息进行分区并将其分布到不同的 broker 服务器上。因此,生产者需要将消息合理的发送到这些分布式的broker上 --- 这就面临一个问题:如何进行生产者的负载均衡。对于生产者的负载均衡,kafka 支持传统的四层负载均衡,同时也支持使用 zookeeper 方式来实现负载均衡。四层负载均衡:四层负载均衡设计比较简单,一般就是根据生产者的ip地址和端口来为其确定一定相关联的 broker。通常一个生产者只会对应单个 broker,然后该生产者生产的所有消息都发送给这个 broker。优点:逻辑简单,不需要引入第三方系统,同时每个生产者也不需要同其他系统建立额外的tcp链接,只需要和broker维护单个tcp即可。缺点:事实上该方案无法做到真正的负载均衡。因为实际运行过程中,每个生产者生成的消息量,以及每个 broker的消息存储量都是不一样的。会导致 broker 接收到的消息总数非常不均衡。另一方面,生产者也无法实时感知 broker 的新增与删除,因此,这种负载均衡方式无法做到动态的负载均衡。使用 zookeeper 进行负载均衡:在kafka中,客户端使用了基于zookeeper的负载均衡策略来解决生产者的负载均衡问题。每当一个 broker 启动时,首先会完成broker注册过程,并注册一些诸如'有哪些订阅的 topic' 的元数据信息。生产者就能够通过这个节点的变化来动态的感知到 broker服务器列表的变更。在实现上,kafka 的生产者会对zookeeper上的'broker 的新增与减少','topic的新增与减少'和 'broker与 topic关系的变化'等事件注册 Watcher 监听,这样就可以实现一种动态的负载均衡策略了。此外,这种模式下,还能够允许开发者控制生产者根据一定的规则(例如根据消费者的消费行为)来进行数据分区,而不仅仅是随机算法而已 --- kafka 将这种特定的分区策略称为 '语义分区'。消费者负载均衡:kafka 有消费者分组的概念,每个消费者分组中都有包含了若干个消费者,每一条消息都只会发送给分组中的每一个消费者,不同的消费者分组消费自己特定topic下面的消息,互不干扰,也不需要互相进行协调。因此消费者负载均衡也可以看做是同一个消费者分组内部的消息消费策略。消息分区与消费者的关系:对于每个消费者分组,kafka都会为其分配一个全局唯一的 Group ID,同时消费者分组内部的所有消费者都共享该 ID.同时,kafka 也会为每个消费者分配一个 Consumer ID,通常采用 'Hostname:UUID'的形式来表示。在 kafka 的设计中,规定了每个消息分区有且只能同时有一个消费者进行消息的消费,因此,需要 zookeeper 上记录下消息分区与消费者之间的对应关系。每一个消费者一旦确定了对一个消息分区的消费权限,那么需要将其 Consumer ID 写入到对应消息分区的临时节点上,例如 /consumers/[group_id]/owners/[topic]/[broker_id-partition_id],其中 '[broker_id-partition_id]' 就是一个消息分区的标志,节点内容就是消费该分区上消费者的 Consumer ID。消息消费进度 Offset 记录:在消费者对指定消息分区进行消息消费的过程中,需要定时的将分区的消费进度,即 offset 记录到 zookeeper 上,以便在该消费者进行重启或者是其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息的消费。offset 在 zookeeper 上的记录由一个专门的节点负责,其节点路径为 /consumers/[group_id]/offset/[topic]/[broker_id-partition_id],其节点内容就是 offset 值。消费者注册:消费者服务器在初始化启动时加入消费者分组的过程:1.注册到消费者分组每个消费者服务器在启动的时候,都会到 zookeeper 的指定节点下创建一个属于自己的消费者节点,例如 /consumers/[group_id]/ids/[consumer_id]。完成节点创建后,消费者就会将自己订阅的 topic 信息写入到该节点。该节点也是临时节点。2.对消费者分组中消费者的变化注册监听每个消费者都需要关注消费者分组中消费者服务器的变化情况,即对 /consumers/[group_id]/ids 节点注册子节点变化的 Watcher 监听。一旦发现消费者新增或者减少,就会触发消费者的负载均衡。3.对 broker 服务器的变化注册监听消费者需要对 /broker/ids/[0...N] 中的节点进行监听的注册,如果发现 broker 服务器列表发生变化,那么就根据具体的情况来决定是否需要进行消费者的负载均衡。4.进行消费者负载均衡所谓消费者负载均衡,是指为了能够让同一个 topic 下不同分区的消息尽量均衡的被多个消费者消费而进行的一个消费者与消息分区匹配的过程。通常,对于一个消费者分组,如果组内的消费者服务器发生变更或broker服务器发生变更,会触发消费者负载均衡。
1.基于 MySQL Binlog 的增量订阅和消费组件Canal 基于 mysql 数据库 binlog 实现的增量订阅和消费组件。Canal 的工作原理相对比较简单,其核心思想就是模拟 mysql slave交互协议,将自己伪装成mysql的 slave 机器,然后不断的向 master 服务器发送 dump 请求。master 收到 dump 请求后,就会开始推送相应的 binary log 给 slave(也就是 Canal)。Canal 收到 binary log,解析出相应的binary log 对象后进行二次消费。2.分布式数据库同步系统:OtterOtter 分布式数据库同步系统,主要用于异地双A 机房的数据库同步,致力于解决长距离机房的数据库同步及双A机房架构下的数据一致性问题。分布式SEDA模型调度:在Otter中将整个数据同步流程抽象为类似于 ETL 的处理模型,具体为4个步骤:1.select : 数据接入2.extract : 数据提取3.transform : 数据转换4.load : 数据载入zookeeper 的 Observer 功能,从 3.3.0 版本开始,zookeeper 新增了Observer 模式,该角色只提供了只读服务,且不参与事务的请求投票,主要用来提升整个zookeeper 集群对非事务请求的处理能力。3.实时计算引擎 : JStormStorm 是 Twitter 开源的一个高容错的分布式实时计算系统。

6.从Paxos到Zookeeper分布式一致性原理与实践---Zookeeper 的典型应用场景相关推荐

  1. 《从Paxos到zookeeper分布式一致性原理与实践》笔记

    <从Paxos到zookeeper分布式一致性原理与实践>笔记 文章目录 <从Paxos到zookeeper分布式一致性原理与实践>笔记 一.概念 二.一致性协调 2.1 2P ...

  2. 《从Paxos到zookeeper分布式一致性原理与实践》

    <从Paxos到zookeeper分布式一致性原理与实践> 一.概念 ACID: Automaticy.consistency.isolation. Durability CAP: con ...

  3. [201502][从 Paxos 到 ZooKeeper][分布式一致性原理与实践][倪超][著]

    [201502][从 Paxos 到 ZooKeeper][分布式一致性原理与实践][倪超][著] http://zookeeper.apache.org 第 1 章 分布式架构 1.1 从集中式到分 ...

  4. 《从Paxos到Zookeeper 分布式一致性原理与实践》

    第1章 分布式架构 1.1 从集中式到分布式 1.1.1 集中式的特点 集中式的特点:部署结构简单(因为基于底层性能卓越的大型主机,不需考虑对服务多个节点的部署,也就不用考虑多个节点之间分布式协调问题 ...

  5. 《从Paxos到ZooKeeper 分布式一致性原理与实践》读书笔记

    一.分布式架构 1.分布式特点 分布性 对等性.分布式系统中的所有计算机节点都是对等的 并发性.多个节点并发的操作一些共享的资源 缺乏全局时钟.节点之间通过消息传递进行通信和协调,因为缺乏全局时钟,很 ...

  6. 《从paxos到zookeeper分布式一致性原理与实践》读书笔记--第二章一致性协议--二阶段提交

    在分布式系统中,每一台机器节点虽然能够知道自己在进行事务操作过程中的结果是成功还是失败但无法直接获取其他分布式系欸但的操作结果.因此,当一个事务需要跨越多个分布式节点的时候为了保持事务的ACID特性, ...

  7. 从Paxos到Zookeeper:分布式一致性原理与实践

    网站 更多书籍点击进入>> CiCi岛 下载 电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍 电子书下载(皮皮云盘-点击"普通下载" ...

  8. Zookeeper分布式一致性原理(四):Zookeeper简介

    zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现数据发布/订阅.负载均衡.命名服务.分布式协调/通知.集群管理.master选举.分布式锁和分布式队列等.Zook ...

  9. Zookeeper分布式一致性原理(八):Zookeeper典型应用场景

    1. 简介 Zookeeper是一个高可用的分布式数据管理和协调框架,并且能够很好的保证分布式环境中数据的一致性.在越来越多的分布式系统(Hadoop.HBase.Kafka)中,Zookeeper都 ...

  10. Zookeeper分布式一致性原理(二):一致性协议

    为了解决分布式一致性问题,在长期的研究过程中,提出了一大批经典的一致性协议和算法,其中最著名的就是2PC和3PC以及Paxos算法了. 1. 2PC和3PC 在分布式系统中,每个节点都明确知道自己事务 ...

最新文章

  1. 【YOLOV4】(7) 特征提取网络代码复现(CSPDarknet53+SPP+PANet+Head),附Tensorflow完整代码
  2. js获取浏览器高和宽的基本信息:屏幕信息
  3. python编程语法-Python学习笔记(Ⅰ)——Python程序结构与基础语法
  4. 爬虫实现csdn文章一键(批量)更换阅读类型(全部可见、粉丝可见、vip可见)
  5. rust(72)-match匹配
  6. Eclipse将引用了第三方jar包的Java项目打包成jar文件
  7. python形参中的:*args和**kwargs区别
  8. css实现风车转动,纯CSS实现的风车转动效果特效演示
  9. java自定义对象集合排序
  10. 音视频传输协议之 RTMP
  11. 【历史上的今天】10 月 14 日:iPhone 十年之变;英国计算机协会成立;第一个 C++ 编译器诞生
  12. 如何计算每个月有多少天
  13. 怎样合理有效的与人争论(讨论)问题?
  14. 商品期货CTA策略系列文章 -- CTA策略的起源
  15. restfulApi相关
  16. 经典Ghost XP
  17. JAVA7所有版本下载地址 JRE jre jdk JDK
  18. 使用linux命令直接截取ip地址
  19. 【单片机笔记】K型热电偶单运放放大,单片机ADC采集电路
  20. 复旦大学科学计算机系王欢,复旦大学计算机科学技术学院举行2019级研究生新生入学教育大会...

热门文章

  1. Dnsmasq 安装配置
  2. [转载]windows 7 IIS 7.5 ASP.Net 文件上传大小限制
  3. enum枚举类型 的用法
  4. Hadoop MapReduce链式实践--ChainReducer
  5. 利用js排序html表格
  6. LeetCode题解——Reverse Integer
  7. sizeof,真正终结版GCC与VC
  8. 基于公司云平台的素材归档系统(一)
  9. asp.net MVC4, Ninject auto-mating
  10. Ajax的简单应用之2