本文是大数据学习总结系列第二篇之ZooKeeper,上一篇是hadoop
Hadoop知识点整理
本文是根据《从Paxos到Zookeeper 分布式一致性原理与实践》的知识点进行整理总结。
集中式特点:不用考虑网络分区,宕机问题,协作问题。但是昂贵。
分布式:由多台机器通过网络通信组成,到了的节点机器,分布式,故障发生频率大。
故障原因:网络问题,多台机器网络通信容易超时,中间有可能断掉造成分区。
网络分区:俗称脑裂。
网络的三态问题:要么连接成功,要么失败,要么超时。
所以分布式主要是网络方面和机器方面的问题,最大问题是网络问题。
例如数据库的事务
原子性:要么成功,要么失败;
一致性:如果出现异常数据,还是原来的那份
隔离性:各个会话之间是相互独立的
持久性:就是提交后的数据永久保存在磁盘上,不丢失。
一致性:多台机器拥有相同副本
可用性:在适合的时间响应客户端
分区容错性:不能出现网络分区
分布式主要的是网络,所以我们优先处理分布式的网络分为,然后在一致性和可用性之间权衡。这时提出了BASE就是对CAP的一致性和可用性的权衡结果。
BASE 基本可用,最终一致性
最终一致性:就是你提交一台机器,其他机器最终会把你提交的那台机器给同步到自己上。
主的控制机器就叫协调者,副本机器叫参与者
两个阶段,提交事务和执行事务。
提交事务
1). 询问
2).执行初始化(执行提交)
执行事务
2PC的故障情况
单台机器
1. 协调者故障,那么有个备用协调者接管,并且查询参与者当前执行到什么地步,然后接着执行下去。
2. 参与者故障,那么协调者会等待它重启,然后再执行下去。
这两种情况,都只会阻塞,并不会不一致性。
同时故障:
协调者和参与者同时故障
例如:有机器1,2,3,4。其中4是协调者,1,2,3是参与者
4给1,2发完提交事务后故障了,正好3这个时候也故障了,注意这是3是没有提交事务数据的。现在备用协调者启动了,去询问参与者,用于3死掉了,一直不知道它处于什么状态(接受了提交事务,还是反馈了能执行还是不能执行3个状态)。
面对这种情况,让1,2回归停止事务,3恢复以后,不管是什么状态,直接停止事务,回滚,这样子就保证了一致性。
这是2PC的漏洞,当同时故障了,就全部回滚,效率低下,代价大
2PC 当时只考虑如果单机故障的情况,并没有考虑协调者和参与者同时故障的情况。3PC就是对2PC漏洞的补充协议。它把2PC中的提交事务请求一分为二,添加了一个状态(准备阶段)。做到就算两个同时故障也不阻塞,并且保证一致性。
事务询问阶段(can阶段)
事务准备阶段 (pre)(包括执行提交)
执行事务阶段 (do commit)(将状态更改)
下面例子分析:
1. 4是协调者 ,1,2,3 是 参与者,当新闻的节点,协调者4和参与者3同时挂掉了。这时候备用的协调者启动了,询问了1和2的状态,都在can阶段,回滚代价下,直接回滚。当3重新启动了发现自己是can阶段,回滚代价下,执行回滚,停止事务。这样子就摆在了3个节点数据一致性。3PC对应2PC就是减少回滚代价。
当3个参与者都进入到per准备阶段,说明它们都接受到提交询问,并且都表决过(意思是都领到了数据),这时协调者4和参与者3突然死掉了。备用协调起来后,询问其他参与者状态,一看都到pre阶段了,说明都领到了数据包括死掉的3,因为他表决过才进入到准备阶段,所以他让大家都提交了。当3重启后,看了日志,发现自己已经到准备阶段时死掉了,可以执行提交,这样保证了数据一致性。
有个叫paxos小岛,他们每项 决定都得通过提议然后半数才能生效,每个决定的提议都有一个唯一的全局编号,这个编号只能自增长,不能后退。
何为通过:就是提议的id好要大于议员手记录的最大的id
第一阶段:提议者发起提议给每个议员,然后等议员反馈同意或不同意。
第二阶段:如果半数以上同意了,则执行事务,否则不执行。
如果半数以上同意了,这个议题就通过,然后提议者就命令剩下的议员同步自己的数据,并修改手上的最大id好。
问题:在分布式中并发是常见的,例如现在有提议者p1,p2
提议者同时提出一个提议,这个时候他们手上的id就有可能是一样,p1的id是3,p2的id也是3。当p1提议给议员(假设议员手上的id是2),现在议员先同意了p1,p2来访问这个议员,议员告诉他已经同意了议题id是3,p2的id是3不同意。然后p2回去加大自己的id重新请求,议员这时同意了他。p1收到半数同意准备去通知他们来更新id同步数据,可是发现议员们的id比自己的大了,然后p1有加大id。这种极端情况,导致死锁了。
这种解决办法就是提议者只有一个,也就是paxos里面说的总统。
zookeeper是为了解决分布式一致性问题的工程应用。
zookeeper并没有直接用paxos协议,而是在paxos协议的基础上,提出了符合自己符合实际应用场景的高可用的一致性协议ZAB原子广播协议。
zookeeper分布式一致性的特点:
顺序一致性:客户端访问zookeeper的一个节点,发起事务,是排着队到leader那让他发起提议,一个一个来;
单一视图:任何节点上的数据都是一样的,所以客户端访问任意节点都看到是相同的数据。
可靠性:给了一个客户端反馈,同意他的请求,那么就是真的同意了。
实时性:zookeeper保证在一定时间内,比如5秒之后你可以访问到最新数据。这是最终一致性导致的。
简单的数据模型:就是文件夹的树形结构
可以构建集群:
顺序访问:客户端提出了一个事务请求,会获得一个唯一的id编号,用于操作的先后顺序;
高性能:这里指的是读取数据
zookeeper有几个角色:leader、follower、observer;其中observer一般不配置,它也不参与投票,observer可以在不影响写性能的情况下提升集群的读性能;
zookeeper中节点有实体机器节点,还有znode数据节点。znode数据节点指的是目录文件夹。数据节点有永久数据节点和临时节点。
zookeeper有watcher监听机制,例如一个临时数据节点,如果客户session中断了,临时节点就删除了,这时watcher就监听到了。这点就是hadoop的HA实现机制,zkfc实现了zookeeper的watcher机制来自动切换。
zookeeper的数据节点就是一个文件夹目录,它有自己的权限机制ACL。
实际zookeeper删除、设置。创建目录,这些就是执行权限。
Looking/election:系统刚启动时或者Leader崩溃后正处于选举状态;
Following:Follwoer节点所处的状态,Follower与Leader处于数据同步阶段;
Leading:Leader所处状态,当前集群中有一个Leader为主进程。
崩溃恢复
快速选举
原子广播
选举
发现
同步
广播
客户端提交一个请求到leader然后leader发起提议floower来投票,这个过程都是原子广播
ZooKeeper启动时所有节点初始状态为Looking,这时集群会初始选举出一个Leader节点,选举出的Leader节点切换为Leading状态;
当节点发现集群中已经选举出Leader则该节点会切换到Following 状态,然后和Leader节点保持同步;
当Following节点与Leader失去联系时Follower节点则会切换到Looking状态,开始新一轮选举;
在ZooKeeper的整个生命周期中每个节点都会在Looking、Following、Leading状态间不断转换。
选举出Leader节点后zab进入原子广播阶段,这是Leader为和自己同步的每个节点Follower只能和一个Leader保持同步Leader节点与Follow节点使用心跳检测来感知对方的存在;
当Leader节点在超时时间内收到来自Follower的心跳检测,那Follower节点会一直与该节点保持连接;若超时时间内Leader没有接收到来自过半Follower节点的心跳检测或TCP连接断开,那Leader会结束当前的领导,切换到Looking状态,所有Follower节点也会放弃该Leader节点切换到Looking状态,所有Follower节点也会放弃该Leader节点切换到Looking状态,然后开始新一轮选举;
第一阶段:准备leader选举
成为leader的条件:
选epoch最大的;
epoch相等,选zxid最大的
epoch的zxid都相等,选择server id最大的(就是配置zoo.cfg中的myid)。
节点在选举开始读默认投票给自己,当接收其他节点的选票是,会根据上面的条件更改自己的选票并重新发送选票给其他节点,但一个节点的得到票超过半数,该节点会设置自己的状态leading,其他节点会设置自己的状态为following。
什么是epoch,什么是zxid?
首先ZooKeeper一个事务包含两部分,一个数数据,一个是id;id是全局唯一的id,数据就是具体操作数据,并且是lastid加1;
ZooKeeper每个请求都是顺序执行的,强顺序性的;
epoch是leader标识,zxid是事务标识。
epoch是指:年代,一个领导挂了,另一个领导上任,现在就是新领导的时代了,当产生新领导,事务编号就从0开始。
zxid是总称:前32位是leader编号(epoch),后32位是这个leader下事务编号。
第二阶段:发现阶段
发现阶段主要是发现最大的epoch和最大的事务编号;
之前说了快速产生准备leader,然后其他节点就是fllower,然后发现阶段就是fllower向leader报告,自己的epoch和事务编号,然后leader排序,选择最大的epoch和最大的事务编号。然后通知fllower去更改它的epoch。
第三阶段:同步阶段
leader利用上一个阶段知道最大事务编号,然后通知其他fllower去leader这同步数据。事务编号有可能不一样,所以要同步。保持数据最终一致性。
第四阶段:原子广播阶段
这时候leader真正对外提供服务,接受客户端的请求,生成一个数据,半数以上同意,然后就提交事务。剩下的其他节点直接去leader那同步数据。
它启动起来,发现他的时代已经过时了,就删除了事务,发现有心的leader,自己就变成fllower,然后就去同步数据。
在选举上,会选举拥有最新提议历史(lastZxid最大)的节点作为leader,这样子就省去了发现最新提议的步骤。这是局域拥有最新提议的节点也有最新提交记录的前提。
paxos没有给出leader选举协议,只给出一致性协议。
ZooKeeper 目录有几个特点,有临时目录,永久目录,顺序目录,强一致性(顺序访问)和watcher机制。
利用这些特点,我们可以实现:
发布订阅,例如一些配置信息;
负载均衡,例如kafka生产,消费均衡;
master选举,例如hbase利用它hmaster选举;
主备切换,例如hdfs的HA利用它进行切换。
例如:我们的数据库配置信息文件就可以放到ZooKeeper上。
利用ZooKeeper的watcher机制实现配置变更,程序在运行中就可以获取到最新的配置信息,不需要起停。
hdfs的HA,它的主备切换用的是ZooKeeper来做Active standby之间切换的。
大致步骤:
1). 多个nodemanager同时向ZooKeeper注册一个数据节点lock。因为ZooKeeper是强一致性的,所以只能有一个注册成功,注册成功的那个就是active
2). 没有注册成功的否成了standby,然后在lock目录上注册监听事件watcher。
注意:注册的lock节点目录是临时节点,如果active挂了,这个目录也就没了,并且这个lock目录是有权限控制的ACL,防止active假死后重新连接出现脑裂。
3). 主备切换:当active挂掉以后,会话结束,临时目录自动删除。其他standby监听到临时目录删除了,各个standby重新同时进行创建带权限的临时目录。成功的改为active,没有成功的还是standby。
4). 如果挂掉的active启动后,发现没有权限范围lock临时目录,自动更改成standby状态。
这是ZooKeeper主备切换应用,利用临时目录,ACL,watcher机制实现。
利用ZooKeeper master选举其实很简单,和主备切换一样。
利用强一致性同时创建同一个目录,最后只能一个成功。
成功那个节点会返回成功状态,其他节点返回异常,成功的那个就成为master,其他节点就改成slave。
hmaster监控regionserver是否挂掉。
首先,rs(regionserver简称)在ZooKeeper注册一个临时目录rs/[hostname]目录,然后hmaster注册watcher监控rs目录下面变化就可以发现rs服务器是否挂掉。
元数据存储(订阅发布):每个region存储信息位置和状态,都放在ZooKeeper上存储,以便大家都能订阅目前region所处的状态,比如region是在合并还是在切割,有多少个region分别在哪个regionserver上。所以客户端访问先访问ZooKeeper得到位置信息去读取数据,不经过hmaster。
kafka在ZooKeeper注册的信息
首先,kafka会把broker创建到ZooKeeper临时目录上。
/broker/ids/[1-n]表示broker还活着。然后topic信息创建到ZooKeeper临时目录。/brokers/topics/[topicname]/paritiong信息。如果有消费者,消费者也会在ZooKeeper创建自己消费信息的offset信息。等临时目录。
kafka注册broker和topic信息使为了生产消费时负载均衡,这就利用到ZooKeeper负载均衡。消费生产者监控到broker和topic,topic和partition之间的数量,进行重新排序。
ZooKeeper是主从架构,分为leader,follower,observer。
leader:处理事务请求,保证事务一致性;
follower:处理非事务请求,并转发客户端事务请求到leader,并参与选举投票;
observer:处理客户的非事务请求,不参与选举投票,只是为了分担数据做动态扩展,可有可无。
注意:非事务就是不改变集群状态,比如读取数据,读取目录。读取就是非事务请求。事务请求就是要改变集群转台,比如创建目录,改变了集群原本状态。
ZooKeeper的数据模型是树形结构,类似于操作系统的文件目录结构,但有点不同。
ZooKeeper的文件夹目录是可以存数据,并且他没有文件概念,比如txt等没有这个概念,所以它的目录直接叫做数据节点znode。一个“/”就代表一个znode数据节点。所以跟目录也是一个znode并且可以存数据。
znode分为永久数据节点、临时数据节点、组合数据节点;组合数据节点又分为永久顺序节点、临时顺序节点。
重点了解:永久和临时区别,顺序是什么。
永久和临时是和会话有关系的,永久是会话结束后依然存在的,临时是和会话的生命周期绑定在一起。
顺序就是每个父znode下面的子znode都是有一个唯一的编号顺序的。注意是父目录下的子目录:你可以在这父目录下车间顺序节点保证唯一。创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名,这个数子字后缀的范围是整型的最大值。
ZooKeeper的znode也是有自己的元数据信息,并且他可以保存数据,znode元数据也就是状态信息:
首先说说悲观锁和乐观锁:
悲观锁:就是独占,我锁定资源只有当我释放资源了别人才可用(包括了不让别人读取);
乐观锁:就是大家可以用资源,当你写入更新的时候去判断之前数据状态是否已经被更改,如果更改就是有操作过了,那么就回滚。
ZooKeeper的数据节点采用了悲观锁的思想,用一个版本号做检验状态,每次要写入数据、更改数据都带上版本号做验证,如果是-1就是用最新版本号,不做验证。
ZooKeeper没有利用平时我们所接触的权限控制模型,它利用了更先进的ACL权限控制列表。ACL包含权限模式、控制对象、控制权限三部分。
ZooKeeper模式就是我们经常用的就是digest。username:password。
ZooKeeper数据节点还有一个特性就是watcher——事件监听。
ZooKeeper客户端包含了我们的编程,还有用zkCli.sh启动进行命令操作,连上那台机器follower那台就是客户端。
具体客户端操作:
创建znode、ls列出目录、get获取数据、set更新数据、delete删除znode(删除的时候只能一个个删除)
其中参数列表如下:
注意:创建ZooKeeper会话的时候需要注册一个美人watcher事件监听。
watcher 的注册过程:
客户端向ZooKeeper服务注册一个watcher,并且将watcher存储在客户端。
ZKWatcherManager进行管理,当zk的服务端触发Watcher事件后,通知客户端,客户端从ZKWatcherManager中拿出处理逻辑代码执行。
处理逻辑代码也就是:process(WatchedEvent event),回调process的时候,watchedEvent包含了三部分信息:通知状态,事件类型,节点路径。重点看前两者
通知状态就是tcp连接情况,事件类型就是连接上以后znode改变情况。
客户端连接需要三个过程:
初始化,也就是准备环境;
创建会话,也就是发送连接;
响应,也就是等待反馈。
要分清客户端的网络线程是clientcnxn来维护连接。服务器端也有网络线程叫做servercnxn。他们互相通信的最小单元就是packet包,pacjet封装了ip端口等连接信息外,还有请求类型,还有watcher信息。
ZooKeeper通信协议如下:
请求:包含请求头和请求体
首先选举leader时候存在的集中服务器状态(注意:选举期间所有节点都处于looking状态)
这个就是为什么ZooKeeper集群是单数的原因
Follower可以参与选举,发起的选举数据格式是:(myid,zxid),他们先给自己投一票,然后发送给其他节点机器,其他的节点机器接收到这个选项,进行pk投票;
pk下来然后把比自己打的发送给其他节点,就是属于投了一票,
每个节点都统计别人投自己票数,如果超过一半投票,就给其他机器发送暂停投票,然后宣布自己成为leader改变状态成leading(zab里面状态),其他follower状态就是(follower),
如果服务器是运行期间leader挂掉,一开始所有的follower改状态为looking,然后进行投票。类似上面的投票机制。主要是pk机制,半数以上同意。
在ZooKeeper中客户端成功连接服务器端就会产生一个会话。
会话有几个状态:连接成功,连接超时重试,关闭连接。
当去创建一个会话的时候,服务端会生成一个sessionid,timeout,isclose并保存在服务端的zkdatabase中,sessionid是全局唯一的来表示唯一的一个会话。如果发起一个事务就会生成自增zxid。zxid来顺序执行事务。服务器对于会话恢分桶管理,根据预计下次超时时间相同的会话分桶在一块。
相同的超时时间的会话分在一个桶里管理,也就是分区
超时判断:如果没有执行这些命令,客户端会自己主动去发送心跳,告诉服务端会话还有效,服务端不断去激活会话。心跳时间:time/3。如果会话超时,服务端标记为已经关闭,进行清理,包括临时的数据节点。重新连接的要求是在超时之内,如果客户端连接上服务端其中一台会话还是有效的。
zk是树结构,并且保存的数据在内存中,zk并且会记录操作日志、内存数据,并且定时snapshot到硬盘上进行数据快照。当集群启动的时候,进行数据初始化。
首先读取磁盘上快照到内存中,然后找最大zxid,加载日志到内存中,对比快照中的zxid和zxid。
如果zxid较大,把内存中的数据进行日志操作,改变zxid成为最大zxid。
数据同步就是follower去leader上同步数据,因为leader一个提议只需要n/2+1,所以还有一些机器没收到(就是没有投票给leader的follower),这些没收到的机器发起一个请求去同步数据
同步数据分两种:一种是差异同步,另一种是全量同步。
大数据学习总结系列的下篇文章是Hive
更多关于hadoop,spark和机器学习文章请关注本文公众号: