ZooKeeper内部原理
- 查看日志命令
java -cp zookeeper-3.4.8.jar:lib/log4j-1.2.16.jar:lib/slf4j-log4j12-1.6.1.jar:lib/slf4j-api-1.6.1.jar org.apache.zookeeper.server.LogFormatter tmp/zookeeper/version-2/log.1
请求、事务和标识符
- 请求:zk服务器会在本地处理只读请求,对于增删改请求会转发给leader处理
- 事务:leader执行相应的请求,并形成状态的更新。一个事务为一个单位,所有的变更处理需要以原子方式执行。
- 标识符:leader产生一个事务,并给该事务分配一个标识符,称为zk服务会话id(Zxid),通过zxid对事务进行标识,就可以按照leader所指定的顺序在各个服务中按序执行。
- zxid为一个long型(64位)整数:分为两部分:时间戳(epoch)部分和计数器(counter)部分.
- 时间戳的概念代表了管理权随时间的变化情况,时间戳的值在每次新leader选举发生的时候便会增加。
leader选举
当一个服务器进入Looking状态,就会向集群中每个服务器发送一个通知消息,该消息中包括服务器的投票(vote)消息,该信息主要由标识符(sid)和最近执行的事务zxid信息组成。 当一个服务器收到一个投票信息,该服务器将会根据以下规则修改自己的投票信息:
- 1.将接收的voteId和voteZxid作为一个标识符,并获取接收方当前的投票中的zxid,用myZxid和mySid表示接收方服务器自己的值。
- 2.如果(voteZxid > myZxid)或者(voteZxid = myZxid且voteId>mySid),保留当前的投票信息。
- 3.否则,修改自己的投票信息,将voteZxid赋值给myZxid,将voteId赋值给mysid。
选举过程中出现脑裂问题,最简单有效的方式,是通过延时,即让old leader在选举过程中,多停顿一会儿。这样新的leader,再被选举出来后,会通知所有从机然后更新zxid,这样就就可以解决脑裂问题了。
Zab:状态更新的广播协议
Zab:zookeeper原子广播协议。假设我们有一个活动的leader服务器,并拥有仲裁数量的追随者支持该leader的管理权,通过该协议提交一个事务非常简单,类似于一个两阶段提交:
- 1.leader向所有追随者发送一个personal消息p;
- 2.当一个追随者接受消息p后,会响应leader一个ACK消息,通知leader其已经接受该personal;
- 3.当收到仲裁数量的服务器发送的确认消息后,leader就会发送消息通知追随者进行提交(commit)操作。
Zab保障了以下几个重要属性:
- 如果leader按顺序广播了事务T和事务T',那么每个服务器在提交T'事务前保证事务T已经提交完成。
- 如果某个服务器按照事务T、事务T'的顺序提交事务,所有其他服务器也必然会在提交事务T'前提交事务T。
Zab协议需要提供的保障:
一个被选举的leader确保在提交完所有之前的时间戳内需要提交的事务,之后才开始广播新的事务。为保证这个需求,leader在被选举出来后,并不会直接处于活动状态,直到确保仲裁数量的服务器认可这个leader新的时间戳值。
在任何时间点,都不会出现两个被被选举的leader。 在leader选举中,我们选择zxid最大的服务器作为leader
观察者
- 引入观察者的一个主要原因是提高读请求的可扩展性
- 采用观察者的另外一个原因是进行垮多个数据中心的部署
快照
快照是zk数据树的拷贝副本,每一个服务器会经常以序列化整个数据树的方式来提取快照,并将这个提取的快照保存到文件中。