zookeeper分布式锁原理:https://my.oschina.net/u/3492343/blog/2992492 zookeeper的树形结构 zookeeper节点特性 1.同级节点唯一性 2.临时节点和持久化节点 3.有序节点和无序节点 4.临时节点下不能存在子节点 集群搭建server.id = ip:port:port 在zoo.cfg里面加入以下 server.1=192.168.182.128:2888:3888 192.168.182.128:2888是完成数据同步的节点 192.168.182.128:3888是选举leader的节点 自己练习的话关闭防火墙service iptables stop,生产就开放相关端口, 在data目录下创建myid(id一定要和上面id对应的ip对应) vim /tmp/zookeeper/myid 里面加入:1或2或3 zoo.cfg里面的参数 1.tickTime=2000 心跳时间 2.initLimit=10 初始化同步数据的时候10个心跳时间 3.syncLimit=5 心跳检测的最大延迟 4.dataDir = /x 同步数据存储的位置 5.clientPort=2181 客户端和服务端连接的端口 [zk: localhost:2181(CONNECTED) 1] get /mic mic cZxid = 0x100000002 ctime = Tue Dec 03 21:08:23 CST 2019 mZxid = 0x100000002 mtime = Tue Dec 03 21:08:23 CST 2019 pZxid = 0x100000002 //子节点变更以后才会产生pzxid的影响 cversion = 0 //类似乐观锁,当前节点的子节点版本号 dataVersion = 0 //当前数据内容的版本号 aclVersion = 0 //当前节点ACL变更的版本号 ephemeralOwner = 0x0 //绑定当前会话的信息 dataLength = 3 //当前数据长度 numChildren = 0 //子节点数量 通过版本号来控制并发情况下的数据修改 ACL (access control list) 权限控制 CREATE/READ/WRITE/DELETE/ADMIN 五种权限 watch机制 zookeeper的应用场景 分布式协调服务 配置中心(aoolication.properties,数据库配置,常量配置等),这个配置中心统一维护配置 负载均衡(知道机器的状态,选举master) 分布式锁 zookeeper主要是解决分布式环境下的服务协调问题而产生的,如果我们要去实现一个zookeeper这样的中间件,需要做什么? 1.防止单点故障 如果要防止zookeeper这个中间件的单点故障,那就势 必要做集群。而且这个集群如果要满足高性能要求的话, 还得是一个高性能高可用的集群。高性能意味着这个集 群能够分担客户端的请求流量,高可用意味着集群中的 某一个节点宕机以后,不影响整个集群的数据和继续提 供服务的可能性 结论:这个中间件需要考虑到集群,还需要分摊客户端的请求流量 2.如果要满足这样的一个高 性能集群,我们最直观的想法应该是,每个节点都能接 收到请求,并且每个节点的数据都必须要保持一致。要 实现各个节点的数据一致性,就势必要一个leader节点 负责协调和数据同步操作。这个我想大家都知道,如果 在这样一个集群中没有leader节点,每个节点都可以接收所有请求,那么这个集群的数据同步的复杂度是非常 大 结论:所以这个集群中设计到数据同步以及会存在leader节点 3.如何在这些节点中选举出leader节点,以及leader挂了以后,如何恢复? 结论:zookeeper用了基于paxos理论所衍生出来的ZAB协议 4. leader 节点如何和其他节点保证数据一致性,并且要求 是强一致的。在分布式系统中,每一个机器节点虽然都 能够明确知道自己进行的事务操作过程是成功和失败, 但是却无法直接获取其他分布式节点的操作结果。所以 当一个事务操作涉及到跨节点的时候,就需要用到分布 式事务,分布式事务的数据一致性协议有 2PC 协议和 3PC协议。 关于2PC提交(Two Phase Commitment Protocol)当一个事务操作需要跨越多个分布式节点的时候,为了保持事务处理的ACID 特性,就需要引入一个“协调者”(TM)来统一调度所有分 布式节点的执行逻辑,这些被调度的分布式节点的执行逻辑,这些被调度的分布式节点被称为AP。 TM负责调度AP的行为,并最终决定这些AP是否要把事 务真正进行提交;因为整个事务是分为两个阶段提交,所 以叫2pc 阶段一:提交事务请求(投票) zookeeper的集群在zookeeper中,客户端会随机连接到zookeeper集群中的一个节点,如果是读请求,就直接从当前节点中读取数据,如果是写请求,那么请求会被转发给leader提交事务,然后leader会广播事务,只要有超过半数节点写入成功,那么写请求就会被提交(类2PC事务) 所有的事务请求必须由一个全局唯一的服务器来协调处理,这个服务器就是Leader服务器,其他的服务器就是follower。leader服务器把客户端的事务请求转化成一个事务(Proposal)提议,并把这个Proposal分发给集群中的所有follower服务器。之后leader服务器需要等待所有follower服务器的反馈,一旦超过半数的follower服务器进行了正确的反馈,那么leader就会再次向所有的follower服务器发送Commit消息,要求各个follower节点对前面的一个Proposal进行提交 集群角色Leader 角色Leader服务器是整个zookeeper集群的核心,主要的工作 任务有两项 1. 事物请求的唯一调度和处理者,保证集群事物处理的顺 序性 2. 集群内部各服务器的调度者 Follower 角色Follower角色的主要职责是 1. 处理客户端非事物请求、转发事物请求给leader服务器 2. 参与事物请求 Proposal 的投票(需要半数以上服务器 通过才能通知leader commit数据; Leader发起的提案, 要求Follower投票) 3. 参与Leader选举的投票 Observer 角色Observer 是 zookeeper3.3 开始引入的一个全新的服务器 角色,从字面来理解,该角色充当了观察者的角色。 观察zookeeper集群中的最新状态变化并将这些状态变化 同步到 observer 服务器上。Observer 的工作原理与 follower 角色基本一致,而它和 follower 角色唯一的不同 在于 observer 不参与任何形式的投票,包括事物请求 Proposal的投票和leader选举的投票。简单来说,observer 服务器只提供非事物请求服务,通常在于不影响集群事物 处理能力的前提下提升集群非事物处理的能力 集群组成通常zookeeper是由2n 1台server组成,每个server都 知道彼此的存在。对于2n 1台server,只要有n 1台(大 多数)server可用,整个系统保持可用。我们已经了解到, 一个zookeeper集群如果要对外提供可用的服务,那么集 群中必须要有过半的机器正常工作并且彼此之间能够正常 通信,基于这个特性,如果向搭建一个能够允许 F 台机器 down 掉的集群,那么就要部署 2*F 1 台服务器构成的 zookeeper 集群。因此 3 台机器构成的 zookeeper 集群, 能够在挂掉一台机器后依然正常工作。一个 5 台机器集群 的服务,能够对 2 台机器怪调的情况下进行容灾。如果一 ZAB协议ZAB(Zookeeper Atomic Broadcast) 协议是为分布式协 调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子 广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现 分布式数据一致性,基于该协议,ZooKeeper 实现了一种 主备模式的系统架构来保持集群中各个副本之间的数据一 致性。 zab协议介绍 ZAB协议包含两种基本模式,分别是 1.崩溃恢复 2.原子广播 当整个集群在启动时,或者当leader节点出现网络中断、崩溃等情况时,ZAB协议就会进入恢复模式并选举产生新的leader,当leader服务器选举出来后,并集群中有过半的机器和该leader节点完成数据同步后(同步指的是数据同步,用来保证集群中过半的机器能够和leader服务器的数据状态保持一致),ZAB协议就会退出恢复模式 当集群中已经有过半的follower节点完成了和leader状态同步以后,那么整个集群就进入了消息广播模式。这个时候。在leader节点正常工作时,启动 一台新的服务器加入到集群,那这个服务器会直接进入数据恢复模式,和leader节点进行数据同步。同步完成后即可正常对外提供非事务请求的处理 消息广播的实现原理如果大家了解分布式事务的2pc和3pc协议的话(不了解 也没关系,我们后面会讲),消息广播的过程实际上是一个 简化版本的二阶段提交过程 1. leader 接收到消息请求后,将消息赋予一个全局唯一的 64位自增id,叫:zxid,通过zxid的大小比较既可以实 现因果有序这个特征 2. leader为每个follower准备了一个FIFO队列(通过TCP 协议来实现,以实现了全局有序这一个特点)将带有zxid 3. 当follower接收到proposal,先把proposal写到磁盘, 写入成功以后再向leader回复一个ack 4. 当leader接收到合法数量(超过半数节点)的ACK后, leader就会向这些follower发送commit命令,同时会 在本地执行该消息 5. 当 follower 收到消息的 commit命令以后,会提交该消 息 leader 的投票过程,不需要 Observer 的 ack,也就是 Observer不需要参与投票过程,但是Observer必须要同 步 Leader 的数据从而在处理请求的时候保证数据的一致 性 崩溃恢复(数据恢复)ZAB 协议的这个基于原子广播协议的消息广播过程,在正 常情况下是没有任何问题的,但是一旦 Leader 节点崩溃, 或者由于网络问题导致 Leader 服务器失去了过半的 1. 已经被处理的消息不能丢失 当 leader 收到合法数量 follower 的 ACKs 后,就向 各个 follower 广播 COMMIT 命令,同时也会在本地 执行 COMMIT 并向连接的客户端返回「成功」。但是如 果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。 leader 对事务消息发起 commit 操作,但是该消息在 follower1 上执行了,但是 follower2 还没有收到 commit, 就已经挂了,而实际上客户端已经收到该事务消息处理成功的回执了。所以在zab协议下需要保证所有机器都要执 行这个事务消息 2. 被丢弃的消息不能再次出现 1. 如果 leader 选举算法能够保证新选举出来的 Leader 服 务器拥有集群中所有机器最高编号(ZXID最大)的事务 Proposal,那么就可以保证这个新选举出来的Leader一 定具有已经提交的提案。因为所有提案被 COMMIT 之 前必须有超过半数的 follower ACK,即必须有超过半数 节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保 存了所有被 COMMIT 消息的 proposal 状态 另外一个,zxid是64位,高32位是epoch编号,每经过 一次 Leader 选举产生一个新的 leader,新的 leader 会将 epoch 号 1,低 32 位是消息计数器,每接收到一条消息 这个值 1,新 leader选举后这个值重置为0.这样设计的好 处在于老的leader挂了以后重启,它不会被选举为leader, 因此此时它的 zxid 肯定小于当前新的 leader。当老的 leader 作为 follower 接入新的 leader 后,新的 leader 会 让它将所有的拥有旧的 epoch 号的未被 COMMIT 的 proposal 清除 关于 ZXID epoch :可以理解为当前集群所处的年代或者周期,每个 leader 就像皇帝,都有自己的年号,所以每次改朝换代, leader 变更之后,都会在前一个年代的基础上加 1 。这样 就算旧的 leader 崩 溃 恢 复 之 后 ,也 没 有 人 听 他 的 了 ,因 为 follower 只听从当前年代的 leader 的命令。 * 1. 启动一个zookeeper集群。 2. 在/tmp/zookeeper/VERSION-2 路径下会看到一个 currentEpoch文件。文件中显示的是当前的epoch 3. 把 leader 节点停机,这个时候在看 currentEpoch 会有 变化。 随着每次选举新的leader,epoch都会发生变化 leader 选举Leader选举会分两个过程 服务器启动时的 leader 选举每个节点启动的时候状态都是 LOOKING,处于观望状态, 接下来就开始进行选主流程 运行过程中的 leader 选举当集群中的 leader 服务器出现宕机或者不可用的情况时, 那么整个集群将无法对外提供服务,而是进入新一轮的 Leader 选举,服务器运行期间的 Leader 选举和启动时期 的Leader选举基本过程是一致的。 事件机制watcher特性:当数据发生变化的时候,zookeeper会产生一个watcher事件,并且会发送到客户端。但是客户端只会收到一次通知。如果后续这个节点再次发生变化,那么之前设置watcher的客户端不会再次收到消息。(watcher是一次性的操作)。可以通过循环监听去达到永久监听效果 如何注册事件机制通过这三个操作来绑定事件:getData\Exists\getChildren 如何触发事件?凡是事务类型的操作,都会触发监听事件。create /delete /setDat watcher 事件类型None (-1), 客户端链接状态发生变化的时候,会收到 none 的事件 |
|