写在开头:
本章是zookeeper学习归纳,着重于复习盘点zookeeper的大部分知识点。
文章内容输出来源:拉勾教育大数据高薪训练营。
1.什么是zookeeper?
Zookeeper 是⼀个分布式协调服务的开源框架。 主要⽤来解决分布式集群中应⽤系统的⼀致性问题,例如怎样避免同时操作同⼀数据造成脏读的问题。分布式系统中数据存在⼀致性的问题。
2.Zookeeper的数据模型
我们需要记忆的知识点:
- Zookeeper有一个根节点 /
- 每一个节点叫做znode
- 每个znode节点都可以有自己的子节点
- Zookeeper的所有操作,都是基于节点路径来操作的
- 多个znode节点共同形成一个znode树(整个Zookeeper存储的目录结构)
- 每个Znode节点都可以存储数据,但是不超过1M
- znode的节点路径是唯一的,基于这个特性,可以做集群的统一命名服务,用路径来标识一台服务器
- znode是维系于内存中的,即znode节点的数据也是存在内存中,目的是供用户快速查询。
- 不能利用Zookeeper存储海量数据,一是Zookeeper的使用场景是做分布式协调服务,二是基于内存存储,多台zk节点存储的是同一数据。
- Zookeeper也提供了持久化机制,持久化的目录:zoo.cfg中的dataDir来决定
- Zookeeper会为每个事务分配一个全局递增事务id
- cZxid:创建节点的事务id
- mZxid:修改节点的事务id
- pZxid:此节点的子节点最新的事务id
Zookeeper 节点类型可以分为三⼤类:
- 持久性节点(Persistent):是Zookeeper中最常⻅的⼀种节点类型,所谓持久节点,就是指节点被创建后会⼀直存在服务器,直到删除操作主动清除。
- 临时性节点(Ephemeral):就是会被⾃动清理掉的节点,它的⽣命周期和客户端会话绑在⼀起,客户端会话结束,节点会被删除掉。与持久性节点不同的是,临时节点不能创建⼦节点。
- 顺序性节点(Sequential):将会在节点后添加自增的标识。
ZNode 的状态信息
#使⽤bin/zkCli.sh 连接到zk集群
[zk: localhost:2181(CONNECTED) 2] get /zookeeper
cZxid = 0x0
ctime = Wed Dec 31 19:00:00 EST 1969
mZxid = 0x0
mtime = Wed Dec 31 19:00:00 EST 1969
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
整个 ZNode 节点内容包括两部分:
节点数据内容和节点状态信息。
这个节点的数据内容是空,其他的属于状态信息。那么这些状态信息都有什么含义呢?
- cZxid 就是 Create ZXID,表示节点被创建时的事务ID。
- ctime 就是 Create Time,表示节点创建时间。
- mZxid 就是 Modified ZXID,表示节点最后⼀次被修改时的事务ID。
- mtime 就是 Modified Time,表示节点最后⼀次被修改的时间。
- pZxid 表示该节点的⼦节点列表最后⼀次被修改时的事务 ID。只有⼦节点列表变更才会更新 pZxid,⼦节点内容变更不会更新。
- cversion 表示⼦节点的版本号。
- dataVersion 表示内容版本号。
- aclVersion 标识acl版本
- ephemeralOwner 表示创建该临时节点时的会话 sessionID,如果是持久性节点那么值为0
- dataLength 表示数据⻓度。
- numChildren 表示直系⼦节点数。
从上⾯的输出信息中,我们可以看到,第⼀⾏是节点/zk-permanent 的数据内容,其他⼏⾏则是创建该 节点的事务ID(cZxid)、最后⼀次更新该节点的事务ID(mZxid)和最后⼀次更新该节点的时间(mtime)等属性信息
Zookeeper选举机制
zk主机竞选Leader的PK原则:
a.先比较Zxid,谁大谁当Leader,因为Zxid越大,事务越新。
b.如果Zxid比较不出来,就要比较选举id,谁大谁当leader。
注:如果已经选出leader,那么剩下的节点自动变为follower,最基本的原则是要满足过半性。
称为Leader的主机能做什么?
1.原子广播:确保所有的节点数据一致。即客户端节点无论从哪一台zk服务器读数据,数据都是一致的。
2.如果客户端发起的是事务请求,follower会将事务请求转交给leader,然后leader做原子广播确保数据一致性。
ZAB⼀致性协议
1.分布式数据⼀致性问题
在分布式系统中引⼊数据复制机制后,多台数据节点之间由于⽹络等原因很容易产⽣数据不⼀致的情况:
当客户端Client1将系统中的⼀个值K1由V1更新为V2,但是客户端Client2读取的是⼀个还没有同步更新的副本,K1的值依然是V1,这就导致了数据的不⼀致性。其中,常⻅的就是主从数据库之间的复制延时问题。
2.什么是zab?
ZAB 协议是为分布式协调服务 Zookeeper 专⻔设计的⼀种⽀持崩溃恢复和原⼦⼴播协议。
ZK怎么处理集群中的数据?所有客户端写⼊数据都是写⼊Leader中,然后,由 Leader 复制到Follower中。ZAB会将服务器数据的状态变更以事务Proposal的形式⼴播到所有的副本进程上,ZAB协议能够保证了事务操作的⼀个全局的变更序号(ZXID)。
⼴播消息:
ZAB 协议的消息⼴播过程类似于 ⼆阶段提交过程。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成⼀个事务 Proposal(提议),将其发送给所有 Follwer ,如果收到超过半数反馈ACK,则执⾏ Commit 操作(先提交⾃⼰,再发送 Commit 给所有Follwer)。
1. 发送Proposal到Follower
2. Leader接收Follower的ACK
3. 超过半数ACK则Commit
不能正常反馈Follower恢复正常后会进⼊数据同步阶段最终与Leader保持⼀致.
细节:
Leader接收到Client请求之后,会将这个请求封装成⼀个事务,并给这个事务分配⼀个全局递增的唯⼀ ID,称为事务ID(ZXID),ZAB 协议要求保证事务的顺序,因此必须将每⼀个事务按照 ZXID进⾏先后排序然后处理。
ZK集群为了保证任何事务操作能够有序的顺序执⾏,只能是 Leader 服务器接受写请求,即使是Follower 服务器接受到客户端的请求,也会转发到 Leader 服务器进⾏处理。
zk提供的应该是最终⼀致性的标准。zk所有节点接收写请求之后可以在⼀定时间内保证所有节点都能看 到该条数据.
崩溃恢复问题:
Leader宕机后,ZK集群⽆法正常⼯作,ZAB协议提供了⼀个⾼效且可靠的leader选举算法。
Leader宕机后,被选举的新Leader需要解决的问题
- ZAB 协议确保那些已经在 Leader 提交的事务最终会被所有服务器提交。
- ZAB 协议确保丢弃那些只在 Leader 提出/复制,但没有提交的事务。
基于上⾯的⽬的,ZAB协议设计了⼀个选举算法:能够确保已经被Leader提交的事务被集群接受,丢弃还没有提交的事务。
这个选举算法的关键点:保证选举出的新Leader拥有集群中所有节点最⼤编号(ZXID)的事务!!
分布式锁
以下是一个正常的下单流程:
如果Redis ⾥⾯的某个商品库存为 1;此时两个⽤户同时下单,其中⼀个下单请求执⾏到第 3 步,更新 数据库的库存为 0,但是第 4 步还没有执⾏。⽽另外⼀个⽤户下单执⾏到了第 2 步,发现库存还是 1,就继续执⾏第 3 步。但是商品库存已经为0,所以如果数据库没有限制就会出现超卖的问题。
分布式环境中可能出现读取到脏数据的情况,那么怎么解决呢?
假设有两个下单请求同时到来,分别由两个机器执⾏,那么这两个请求是可以同时执⾏了,依然存在超卖的问题,因为如图所示系统是运⾏在两个不同的 JVM ⾥⾯,不同的机器上,增加的锁只对⾃⼰当前 JVM ⾥⾯的线程有效,对于其他 JVM 的线程是⽆效的。所以现在已经不是线程安全问题。需要保证两台机器加的锁是同⼀个锁,此时分布式锁就能解决该问题。分布式锁的作⽤:在整个系统提供⼀个全局、唯⼀的锁,在分布式系统中每个系统在进⾏相关操作的时候需要获取到该锁,才能执⾏相应操作。
写在结尾:
以上的文章大致归纳了zookeeper的基础知识,后续还会服务器动态上下线监听代码的实现和用zk实现一个分布式锁的流程。下一篇将记录Hadoop HA的搭建过程。