Zookeeper工作原理

news2024/11/24 23:30:09

一 Zookeeper是什么

  ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户,主要为了解决分布式架构下数据一致性问题,典型的应用场景有分布式配置中心、分布式注册中心、分布式锁、分布式队列、集群选举、分布式屏障、发布/订阅等场景。简单说zookeeper=文件系统+通知机制。

1,Zk的文件系统

每个子目录项如 NameService 都被称作为znode,和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

  1. 持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除该节点,他将永远存在。
  2. 持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是zookeeper给该节点名称进行顺序编号。
  3. 临时目录节点:客户端与zookeeper断开连接后,该节点被删除。
  4. 临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是zookeeper给该节点名称进行顺序编号。

在这里插入图片描述

2,zk的通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。监听事件如下:

1、None:连接建立事件
2、NodeCreated:节点创建
3、NodeDeleted:节点删除
4、NodeDataChanged:节点数据变化
5、NodeChildrenChanged:子节点列表变化
6、DataWatchRemoved:节点监听被移除
7、ChildWatchRemoved:子节点监听被移除

3,zk的角色

  • 领导者(leader),负责进行投票的发起和决议,更新系统状态
  • 学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票
  • Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度。zoo.cfg中添加peerType=Observer,这表示这个server以observer角色运行,即不参与投票。再在所有 server的配置文件中,修改server.X配置项,在那些observer的节点上加上:observer后缀。例如,server.1对应的server要作为observer:Server.1=IP:2181:3181:observer
    这样配置后,ZooKeeper集群中的所有服务器节点都知道哪些节点扮演的是observer角色。
  • 客户端(client),请求发起方
    在这里插入图片描述

Leader 服务器会和每一个 Follower/Observer 服务器都建立 TCP 连接,同时为每个Follower/Observer 都创建一个叫做 LearnerHandler 的实体。LearnerHandler 主要负责 Leader 和Follower/Observer 之间的网络通讯,包括数据同步,请求转发和 proposal 提议的投票等。Leader 服务器保存了所有 Follower/Observer 的 LearnerHandler 。

4,CAP理论

zookeeper:满足数据的最终一致性,但是在leader选举过程中不可用。
Eureka:在任何时间都可用,但是可能有数据不一致的情况.

  • C是一致性,Consistency,就是各个节点保存的数据都是最新的。
  • A是Availability, 可用性,每次请求都可以获得响应,但是没法保证是最新的响应。
  • P是分区容错性(Partition tolerance),就是每个节点可能都存在于不同的子网络,也就是不同的分区,不同分区之间的通信总是有可能发生故障的,或者总是有可能存在一些节点挂了的情况。

可以认为P总是成立的,C和A是无法同时做到。所以一般对于数据一致性要求特别高的业务,例如支付,交易相关的业务,就是会优先保证一致性C和分区容错性P,就是保证数据一致性,例如让所有子节点都收到更新后才算提交成功,就像MySQL主从同步中的全同步模式一样。普通的业务是优先保证可用性A和分区容错性P,比如在MySQL主从同步时,默认就是异步的方式,我们执行一条更新SQL,只需要主节点更新成功就行就对事务进行提交,不需要等待从节点更新数据成功,主节点会异步把SQL发送给从节点。

二 zk的工作流程

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后 ,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid) 来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
每个Server在工作过程中有三种状态:

  1. LOOKING:当前Server不知道leader是谁,正在搜寻
  2. LEADING:当前Server即为选举出来的leader
  3. FOLLOWING:leader已经选举出来,当前Server与之同步

1,zk的选主流程

   当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的 Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。

1)basic paxos流程:

  1. 选举线程由当前Server发起,其主要功能是对投票结果进行统计,并推选出Leader
  2. 选举线程首先向所有的server发次一次询问(包括自己)
  3. 选举线程收到回复后,验证是否是自己发起的询问(验证zxid),然后获取对方的id(myId),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(zxid和myid),并将这些信息存储到当次选举的投票记录中。
  4. 收到所有的server回复后,就计算出zxid最大的server,并将这个Server相关的信息设置成下次要投票成leader的server。
  5. 线程将当前最大zxid的server设置成推荐leader时,如果获得n/2+1的server同意,则zxid最大的server称为leader,然后将根据获胜的server相关的信息来设置自己的状态,否则继续当前流程,直到leader选出。

   通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1。
   每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。选主的具体流程图如下所示:
在这里插入图片描述

2)fast paxos流程
是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和 zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。其流程图如下所示:
在这里插入图片描述
如果还不明白可以参考:
https://blog.csdn.net/qq_35128600/article/details/104798113

2,zk的同步流程

选完leader以后,zk就进入状态同步过程。

  1. leader等待server连接;
  2. Follower连接leader,将最大的zxid发送给leader;
  3. Leader根据follower的zxid确定同步点;
  4. 完成同步后通知follower 已经成为uptodate状态;
  5. Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。

流程图如下所示:
在这里插入图片描述

3,zk的工作流程

ZooKeeper集群中的每个server都能为客户端提供读、写服务。对于客户端的读请求,server会直接从它本地的内存数据库中取出数据返回给客户端,这个过程不涉及其它任何操作,也不会联系leader。对于客户端的写请求,因为写操作会修改znode的数据、状态,所以必须要在ZooKeeper集群中进行协调。处理过程如下:
在这里插入图片描述
如图所示:

  1. 收到写请求的那个server,首先将写请求发送给leader。
  2. leader收到来自follower(或observer)的写请求后,首先计算这次写操作之后的状态,然后将这个写请求转换成带有各种状态的事务(如版本号、zxid等等)。
  3. leader将这个事务以提议的方式广播出去(即发送proposal)。
  4. 所有follower收到proposal后,对这个提议进行投票,投票完成后返回ack给leader。follower的投票只有两种方式:(1)确认这次提议表示同意;(2)丢弃这次提议表示不同意。
  5. leader收集投票结果,只要投票数量达到了大多数的要求(例如,5个节点的集群,3个或3个以上的节点才算大多数),这次提议就通过。
  6. 提议通过后,leader向所有server发送一个提交通知。
  7. 所有节点将这次事务写入事务日志,并进行提交。
  8. 提交后,收到写请求的那个server向客户端返回成功信息。

上面只是简单的介绍了下zk的写流程,实际过程中,leader和foller还有好多其他的功能,具体如下。

1.Leader的工作流程

Leader的主要功能是:恢复数据和维持与foller的心跳,并接收foller的请求消息类型。leader接收的消息类型主要有

  • PING消息:指的是foller的心跳信息。
  • REQUEST消息:foller发送的提议信息,包括写请求和同步数据请求
  • ACK消息:foller对于提议信息的恢复,超过半数的foller同意,则该commit该提议。
  • REVALIDATE消息:是用来延长session的有效时间。

Leader的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。

2.foller的工作流程

Follower主要有四个功能:

  1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息)
  2. 接收Leader消息并进行处理;
  3. 接收Client的请求,如果为写请求,发送给Leader进行投票;
  4. 返回Client结果。

Follower的消息循环处理如下几种来自Leader的消息:

  • PING消息: 心跳消息;
  • PROPOSAL消息:Leader发起的提案,要求Follower投票;
  • COMMIT消息:服务器端最新一次提案的信息;
  • UPTODATE消息:表明同步完成;
  • REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;
  • SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

Follower的工作流程简图如下所示,在实际实现中,Follower是通过5个线程来实现功能的
在这里插入图片描述

三 zk的常见应用场景

1,zk的命名服务

  命名服务是指通过指定的名字来获取资源或者服务的地址,提供者的信息。利用Zookeeper很容易创建一个全局的路径,而这个路径就可以作为一个名字,它可以指向集群中的集群,提供的服务的地址,远程对象等。简单来说使用Zookeeper做命名服务就是用路径作为名字,路径上的数据就是其名字指向的实体。
  例如:Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表。在Dubbo实现中:

  • 服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布。
  • 服务消费者启动的时候,订阅/dubbo/{serviceName}/providers目录下的提供者URL地址, 并向/dubbo/{serviceName} /consumers目录下写入自己的URL地址。

2,zk的配置管理

程序总是需要配置的,如果程序分散部署在多台机器上,要逐个改变配置就变得困难。现在把这些配置全部放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中就好
在这里插入图片描述

3,zk的注册中心

所谓集群管理无在乎两点:是否有机器退出和加入、选举master。

  1. 对于第一点,所有机器约定在父目录GroupMembers下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船了。新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount又有了
  2. 对于第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为master就好。

在这里插入图片描述

4,zk的分布式锁

有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

  1. 对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。
  2. 对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便。

在这里插入图片描述

5,zk的队列管理

两种类型的队列:

  1. 同步队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。
  2. 队列按照 FIFO 方式进行入队和出队操作。和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。

四 zk的常见问题

1,zk的节点信息

通过stat命令来查看主要信息,其中信息有:

1、cZxid:创建znode的事务id(Zxid的值)。
2、mZxid:最后修改znode的事务id。
3、pZxid:最后添加或删除子节点的事务id(子节点列表发生变化才会发生改变)。
4、ctime:znode创建时间。
5、mtime:znode最近修改时间。
6、dataVersion:znode的当前数据版本。
7、cversion:znode的子节点结果集版本(一个节点的子节点增加、删除都会影响这个版本)。
8、aclVersion:表示对此znode的acl版本。
9、ephemeralOwner:znode是临时znode时,表示znode所有者的sessionid,如果znode不是临时节点,则该字段设置为零。
10、dataLength:znode数据字段的长度。

2,zookeeper创建节点

1、创建持久节点:create /节点名称
2、创建持久顺序节点:create -s /节点名称
3、创建临时节点:create -e /节点名称
4、创建临时顺序节点:create -e -s /节点名称
5、监听节点:get -w /节点名称

3,zookeeper的权限控制

zookeeper有ACL( Access Control List )权限控制,可以控制节点的读写操作,保证数据的安全性。
ACL(Access Control List),分别由权限模式,授权对象和权限信息组成
1)权限模式:

  1. 范围验证:zookeeper可以通过对一个ip或者一段ip进行授权。
  2. 口令验证:用户名密码方式验证

2)授权对象: 就是把权限授予给谁,如果是范围验证方式,那么授权对象就是ip地址,如果是口令验证,授权对象就是用户名。

3)权限信息:

  1. 数据节点(c:create)创建权限,授予权限的对象可以在数据节点下创建子节点。
  2. 数据节点(w:wirte)更新权限,授予权限的对象可以更新该数据节点
  3. 数据节点(r:read)读取权限,授予权限的对象可以读取该节点的内容以及子节点的列表信息。
  4. 数据节点(d:delete)删除权限,授予权限的对象可以删除该数据节点的子节点。
  5. 数据节点(a:admin)管理者权限,授予权限的对象可以对该数据节点体进行ACL权限设置。

可以通过getAcl来获取某个节点的权限信息,通过setAcl来设置某个节点的权限信息。

4,zookeeper的数据持久化

zookeeper和redis很像,数据都是在内存中的,持久化也是两种方式,一种是记录事务日志,一种是快照方式。
记录事务日志磁盘会进行IO操作,事务日志的不断增多会触发磁盘为文件开辟新的磁盘块,所以为了提升磁盘的效率,可以在创建文件的时候
就向操作系统申请一块大一点的磁盘块,通过参数zookeeper.preAllocSize配置。事务日志的存放地址通过zoo.cfg配置文件中的dataDir来指定。

5,Zookeeper 的通知机制是什么?

Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听,当服务端的一些指定事件,触发了这个 Watcher ,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。大致分为三个步骤:

1,客户端注册 Watcher

  • 调用 getData、getChildren、exist 三个 API ,传入Watcher 对象。
  • 标记请求request ,封装 Watcher 到 WatchRegistration 。
  • 封装成 Packet 对象,发服务端发送request 。
  • 收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理。
  • 请求返回,完成注册。

2,服务端处理 Watcher

  • 服务端接收 Watcher 并存储。
  • Watcher 触发
  • 调用 process 方法来触发 Watcher 。

3,客户端回调 Watcher

  • 客户端 SendThread 线程接收事件通知,交由 EventThread 线程回调Watcher 。
  • 客户端的 Watcher 机制同样是一次性的,一旦被触发后,该 Watcher 就失效了。

client 端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些 client 会收到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等。

Zookeeper 对节点的 watch 监听通知是永久的吗?
不是,一次性的。无论是服务端还是客户端,一旦一个 Watcher 被触发,Zookeeper都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。

6,说说Zookeeper中的脑裂?

1.脑裂是什么?

  简单点来说,脑裂(Split-Brain) 就是比如当你的 cluster 里面有两个节点,它们都知道在这个cluster 里需要选举出一个 master。那么当它们两个之间的通信完全没有问题的时候,就会达成共识,选出其中一个作为 master。但是如果它们之间的通信出了问题,那么两个结点都会觉得现在没有 master,所以每个都把自己选举成 master,于是 cluster 里面就会有两个 master。对于Zookeeper来说有一个很重要的问题,就是到底是根据一个什么样的情况来判断一个节点死亡down掉了?在分布式系统中这些都是有监控者来判断的,但是监控者也很难判定其他的节点的状态,唯一一个可靠的途径就是心跳,Zookeeper也是使用心跳来判断客户端是否仍然活着。使用ZooKeeper来做Leader HA基本都是同样的方式:每个节点都尝试注册一个象征leader的临时节点,其他没有注册成功的则成为follower,并且通过watch机制监控着leader所创建的临时节点,Zookeeper通过内部心跳机制来确定leader的状态,一旦leader出现意外Zookeeper能很快获悉并且通知其他的follower,其他flower在之后作出相关反应,这样就完成了一个切换,这种模式也是比较通用的模式,基本大部分都是这样实现的。但是这里面有个很严重的问题,如果注意不到会导致短暂的时间内系统出现脑裂,因为心跳出现超时可能是leader挂了,但是也可能是zookeeper节点之间网络出现了问题,导致leader假死的情况,leader其实并未死掉,但是与ZooKeeper之间的网络出现问题导致Zookeeper认为其挂掉了然后通知其他节点进行切换,这样follower中就有一个成为了leader,但是原本的leader并未死掉,这时候client也获得leader切换的消息,但是仍然会有一些延时,zookeeper需要通讯需要一个一个通知,这时候整个系统就很混乱可能有一部分client已经通知到了连接到新的leader上去了,有的client仍然连接在老的leader上,如果同时有两个client需要对leader的同一个数据更新,并且刚好这两个client此刻分别连接在新老的leader上,就会出现很严重问题。
  总结: 假死:由于心跳超时(网络原因导致的)认为leader死了,但其实leader还存活着。 脑裂:由于假死会发起新的leader选举,选举出一个新的leader,但旧的leader网络又通了,导致出现了两个leader ,有的客户端连接到老的leader,而有的客户端则连接到新的leader。

2.如何解决脑裂问题的?

要解决Split-Brain脑裂的问题,一般有下面几种种方法:

  • Quorums (法定人数) 方式: 比如3个节点的集群,Quorums = 2, 也就是说集群可以容忍1个节点失效,这时候还能选举出1个lead,集群还可用。比如4个节点的集群,它的Quorums = 3,Quorums要超过3,相当于集群的容忍度还是1,如果2个节点失效,那么整个集群还是无效的。这是zookeeper防止"脑裂"默认采用的方法。
  • Redundant communications (冗余通信)方式:集群中采用多种通信方式,防止一种通信方式失效导致集群中的节点无法通信。
  • Fencing (共享资源) 方式:比如能看到共享资源就表示在集群中,能够获得共享资源的锁的就是Leader,看不到共享资源的,就不在集群中。要想避免zookeeper"脑裂"情况其实也很简单,follower节点切换的时候不在检查到老的leader节点出现问题后马上切换,而是在休眠一段足够的时间,确保老的leader已经获知变更并且做了相关的shutdown清理工作了然后再注册成为master就能避免这类问题了,这个休眠时间一般定义为与zookeeper定义的超时时间就够了,但是这段时间内系统可能是不可用的,但是相对于数据不一致的后果来说还是值得的。

  zooKeeper默认采用了Quorums这种方式来防止"脑裂"现象。即只有集群中超过半数节点投票才能选举出Leader。这样的方式可以确保leader的唯一性,要么选出唯一的一个leader,要么选举失败。在zookeeper中Quorums作用如下:*集群中最少的节点数用来选举leader保证集群可用。通知客户端数据已经安全保存前集群中最少数量的节点数已经保存了该数据。*一旦这些节点保存了该数据,客户端将被通知已经安全保存了,可以继续其他任务。而集群中剩余的节点将会最终也保存了该数据。
  假设某个leader假死,其余的followers选举出了一个新的leader。这时,旧的leader复活并且仍然认为自己是leader,这个时候它向其他followers发出写请求也是会被拒绝的。因为每当新leader产生时,会生成一个epoch标号(标识当前属于那个leader的统治时期),这个epoch是递增的,followers如果确认了新的leader存在,知道其epoch,就会拒绝epoch小于现任leader epoch的所有请求。那有没有follower不知道新的leader存在呢,有可能,但肯定不是大多数,否则新leader无法产生。Zookeeper的写也遵循quorum机制,因此,得不到大多数支持的写是无效的,旧leader即使各种认为自己是leader,依然没有什么作用。zookeeper除了可以采用上面默认的Quorums方式来避免出现"脑裂",还可以可采用下面的预防措施:

  • 添加冗余的心跳线,例如双线条线,尽量减少“裂脑”发生机会。
  • 启用磁盘锁。正在服务一方锁住共享磁盘,“裂脑"发生时,让对方完全"抢不走"共享磁盘资源。但使用锁磁盘也会有一个不小的问题,如果占用共享盘的一方不主动"解锁”,另一方就永远得不到共享磁盘。现实中假如服务节点突然死机或崩溃,就不可能执行解锁命令。后备节点也就接管不了共享资源和应用服务。于是有人在HA中设计了"智能"锁。即正在服务的一方只在发现心跳线全部断开(察觉不到对端)时才启用磁盘锁。平时就不上锁了。
  • 设置仲裁机制。例如设置参考IP(如网关IP),当心跳线完全断开时,2个节点都各自ping一下 参考IP,不通则表明断点就出在本端,不仅"心跳"、还兼对外"服务"的本端网络链路断了,即使启动(或继续)应用服务也没有用了,那就主动放弃竞争,让能够ping通参考IP的一端去起服务。更保险一些,ping不通参考IP的一方干脆就自我重启,以彻底释放有可能还占用着的那些共享资源。

7,Zookeeper选举中投票信息的五元组是什么?

Leader:被选举的 Leader 的 SID
Zxid:被选举的 Leader 的事务 ID
Sid:当前服务器的 SID
electionEpoch:当前投票的轮次
peerEpoch:当前服务器的 Epoch
Epoch > Zxid > Sid
Epoch,Zxid 都可能一致,但是 Sid 一定不一样,这样两张选票一定会 PK 出结果。

8,Zookeeper集群支持动态添加机器吗?

其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式:
全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。
逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常用的方式。
3.5版本后支持动态扩容。

9,什么场景下会导致ZooKeeper发生延迟通知

watch事件延迟:节点被修改后,会有事件通知发往观察者,直到接收到watch事件,观察者才会知道节点被修改了;当管擦着接到watch事件的那一刻,该节点又被其他修改者修改了,而 近的watch事件还没有通知到观察者,就会造成延迟通知。


参考文献:
https://blog.csdn.net/u014374173/article/details/105173043
https://blog.csdn.net/weixin_38612401/article/details/125216821
leader选举:
https://blog.csdn.net/qq_35128600/article/details/104798113

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424467.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring】我抄袭了Spring,手写一套MySpring框架。。。

这篇博客实现了一个简单版本的Spring,主要包括Spring的Ioc和Aop功能 文章目录这篇博客实现了一个简单版本的Spring,主要包括Spring的Ioc和Aop功能🚀ComponentScan注解✈️Component注解🚁在spring中ioc容器的类是ApplicationConte…

迅为4412开发板Qt 界面切换

本节通过实验介绍通过创建窗口对象的方式实现界面切换: 步骤一: 在主界面 ui 文件添加 pushButton 按钮, 然后新建一个窗口,工程下创建新的 Qt 设计师界面类,如图 : 我们选择 Widget,用户可以根…

logstash+elasticsearch+Kibana(ELK)日志收集

文章目录一.安装elasticsearch二. 安装kibana三.配置logstash四.springboot整合logstash五.spring整合Elastic Search六. 定时清理不要一股脑执行以下语句,请观察修改要修改的地方 注意给logstash,elasticsearch,kibana释放端口,云服务器提供商和系统的端口 一.安装elasticsea…

为什么许多人吐槽C++11,那些语法值得我们学习呢?

致前行的人: 人生像攀登一座山,而找寻出路,却是一种学习的过程,我们应当在这过程中,学习稳定冷静,学习如何从慌乱中找到生机。 目录 1.C11简介 2.统一的列表初始化 2.1 {}初始化 …

linux-php 7.3.2安装

1.下载php wget http://am1.php.net/distributions/php-7.3.2.tar.gz 2.解压 tar -zxvf php-7.3.2.tar.gz 3.安装扩展 接下来进行参数配置,配置前如果没有libxml2和libxml2-devel会报错,所以应该更新libxml2并安装libxml2-devel,使用在线…

SpringBoot 项目整合 Redis 教程详解

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

Android Init(后期还会更加完善)

代码分析基于android-12.0.0_r28 前期阶段 kernel/init/main.c: static int __ref kernel_init(void *unused) {// ...省略一堆代码if (execute_command) {ret run_init_process(execute_command);if (!ret)return 0;panic("Requested init %s failed (err…

八百字讲清楚——BCEWithLogitsLoss二分类损失函数

BCEWithLogitsLoss是一种用于二分类问题的损失函数,它将Sigmoid函数和二元交叉熵损失结合在一起。 假设我们有一个大小为NNN的二分类问题,其中每个样本xix_ixi​有一个二元标签yi∈0,1y_i\in {0,1}yi​∈0,1,并且我们希望预测每个样本的概率…

RCNN系列发展历程

1. RCNN RCNN发表于CVPR 2014。是将深度学习应用于目标检测领域的开山之作,凭借卷积神经网络较之传统CV方法的强大特征提取能力,将PASCAL VOC数据集检测率从35.1%提升到53.7%。 RCNN的算法流程如下图所示,其过程主要分为4步: 生成…

Ubuntu中隐藏Apache的版本号等信息

Ubuntu中隐藏Apache的版本号等信息 vim /etc/apache2/apache2.conf在apache主配置文件的末尾增加以下内容: ServerTokens Prod ServerSignature offServerTokens: 默认阀值为Full,以apache-2.0.55为例,阀值可以设定为以下某项&a…

【完整项目开发】Springboot+jsp宠物医院信息管理系统设计和实现--依旧很干

Springbootvue宠物医院信息管理系统设计和实现 **大家好,今天分享最近做的一套系统。**起因源于小伙伴的需求 文末有的获取方式,如需定制系统,需求发来,我为你分忧,搞起 一、 项目介绍 宠物医院信息管理系统是一种…

香港轻量云服务器安全性如何?

​  之前,对于新手外贸站长而言,部署网站首要青睐是香港虚拟主机。但大多人也都清楚,每台香港虚拟主机的资源是由一台物理机分割来的。这无疑会带来一定的安全隐患,比如分割出来的多台香港虚拟主机会共用传统的系统、管理面板以…

Vue3评分(Rate)

可自定义设置以下属性: 是否允许再次点击后清除(allowClear),类型:boolean,默认 true 是否允许半选(allowHalf),类型:boolean,默认 false star …

Java每日一练(20230417)

目录 1. N 皇后 🌟🌟🌟 2. 搜索二维矩阵 🌟🌟 3. 发奖金问题 🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 …

神经网络之反向传播算法(自适应矩估计算法Adam变形形式之Adamax、Nadam)

文章目录自适应矩估计算法(Adam)的两种变形形式1、Adamax算法原理2、Nadam算法原理3、算法实现3.1 Adamax训练过程3.2 Adamax测试过程及结果3.3 Nadam训练过程3.4 Nadam测试过程及结果4、参考源码及数据集自适应矩估计算法(Adam)的…

打造安全无忧软件应用的十大最佳实践

安全无忧的软件开发最佳实践实在是很有必要,因为安全风险无处不在。在网络攻击盛行的时代,它们可能影响到每个人,包括个人、公司和政府。因此,确保软件开发的安全性至关重要。 本篇文章将解释了什么是安全的软件,如何…

你了解C语言中的柔性数组吗?

本篇博客主要讲解C99中的新语法:柔性数组。 1.什么是柔性数组? 柔性数组就是大小可以变化的数组。 注意跟C99中的变长数组区分开来,变长数组指的是可以使用变量来指定大小,并且不能初始化的数组,比如: i…

实例方法、类方法、静态方法、实例属性、类属性

背景:今天在复习类相关知识的时候,突然想到这几种类型的方法的区别和用法,感觉有点模棱两可,于是总结一下,加深记忆。 定义:想要区别和理解几种方法,首先要定义一个类,要在类中加深…

mysql如何修改时区

mysql 里CST时区的坑 一、 问题简述 mysql里CST时区是个非常坑的概念,因为在mysql里CST既表示中国也表示美国的时区。但是在JDK代码里,CST这个字符串被理解为CenTral Standard Time(USA)(GMT-6)&#xff…

java框架都有哪些

Java框架是对Java2中的一些基本概念进行抽象,封装成能被开发者使用的类库,使之能快速开发应用程序。它让开发者能够专注于业务逻辑而不是实现细节。可以说, Java框架是 Java开发中的重要组成部分,它极大地方便了开发者。下面为大家…