zookeeper学习笔记
2023-12-13 17:31:59 0 举报
AI智能生成
zookeeper学习笔记
作者其他创作
大纲/内容
部署
zoo.cfg
tickTime=2000dataDir=/var/lib/zookeeperdataLogDir=/var/lib/logclientPort=2181initLimit=5syncLimit=2server.1=IP1:2888:3888server.2=IP2:2888:3888server.3=IP3:2888:3888
每个集群都需要配置所有的ip:port ,必须相同
server.id=host:port1:port2
myid
dataDir 目录下创建名为 myid 的文件,在文件第一行写上对应的 Server ID。
需要知道所有的节点的ip,port 也就是知道了整个集群的规模. 在选举的时候, 必须大于 n/2的节点才能选举出 leader,否则不可用
牺牲可用性,保证一致性
zk 具体功能
节点类型
.持久结点(
持久顺序结点
.临时结点
临时顺序结点
节点状态信息
带version.可以执行 cas操作,只有是某一个 version时才更新
子主题 2
事务监听
1.当监听器监听的事件被触发,服务端会发送通知给客户端,但通知信息中不包括事件的具体内容。以监听ZNode结点数据变化为例,当Znode的数据被改变,客户端会收到事件类型为NodeDataChanged的通知,但该Znode的数据改变成了什么客户端无法从通知中获取,需要客户端在收到通知后手动去获取。
zab 协议
1.所有的事务请求都交由集群的Leader服务器来处理,Leader服务器会将一个事务请求转换成一个Proposal(提议),并为其生成一个全局递增的唯一ID,这个ID就是事务ID,即ZXID,Leader服务器对Proposal是按其ZXID的先后顺序来进行排序和处理的。
2.之后Leader服务器会将Proposal放入每个Follower对应的队列中(Leader会为每个Follower分配一个单独的队列),并以FIFO的方式发送给Follower服务器。
3.Follower服务器接收到事务Proposal后,首先以事务日志的方式写入本地磁盘,并且在成功后返回Leader服务器一个ACK响应。
4.Leader服务器只要收到过半Follower的ACK响应,就会广播一个Commit消息给Follower以通知其进行Proposal的提交,同时Leader自身也会完成Proposal的提交。
分布式的问题
通信异常
网络分区
三态(成功,失败,超时)
节点故障
CAP理论
一致性(consistence):数据在分布式环境下的多个副本之间能否保持一致性,这里的一致性更多是指强一致性
分布式系统一直处于可用状态,对于请求总是能在有限的时间内返回结果致性
除非整个网络故障,分布式系统在任何网络或者单点故障时,仍能对外提供满足一致性和可用性的服务
抉择
存储方案
Zookeeper的数据模型是树结构,在内存数据库中,存储了整棵树的内容,包括所有的节点路径、节点数据、ACL信息,Zookeeper会将这个数据存储到磁盘上。
定时
事务Commit 已写入内存为准
Zookeeper的内存数据库,管理Zookeeper的所有会话、DataTree存储和事务日志。ZKDatabase会定时向磁盘dump快照数据,同时在Zookeeper启动时,会通过磁盘的事务日志和快照文件恢复成一个完整的内存数据库。
zk的树 和 事务,会话分别存储
ZAB协议
设计目标
有序性
全局有序:如果消息 a 在消息 b 之前被投递,那么在任何一台服务器,消息 a都会在消息 b 之前被投递
因果有序:如果消息 a 在消息 b 之前发生(a 导致了 b),并被一起发送,则 a 始终在 b 之前被执行。
容错性
有 2f+1 台服务器,只要有大于等于 f+1 台的服务器正常工作,就能完全正常工作。
3/4 -> 2; 5/6->3, 7/8->4
一致性
协议类型
广播
广播(boardcast):Zab 协议中,所有的写请求都由 leader 来处理。正常工作状态下,leader 接收请求并通过广播协议来处理。
恢复
恢复(recovery):当服务初次启动,或者 leader 节点挂了,系统就会进入恢复模式,直到选出了有合法数量 follower 的新 leader,然后新 leader 负责将整个系统同步到最新状态。
协议实现
广播
简化的二阶段提交
过程
Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,叫做:zxid,通过 zxid 的大小比较即可实现因果有序这一特性。
Leader 通过先进先出队列(和每一个 flower都有队列)(通过 TCP 协议来实现,以此实现了全局有序这一特性)将带有 zxid 的消息作为一个提案(proposal)分发给所有 follower。
leader和 flower节点之间会有队列,接受有队列,发送也有队列.单线程处理(socket处理不支持并发)
当 follower 接收到 proposal,先将 proposal 写到硬盘,写硬盘成功后再向 leader 回一个 ACK。
当 leader 接收到合法数量的 ACKs 后,leader 就向所有 follower 发送 COMMIT 命令,同事会在本地执行该消息。
当 follower 收到消息的 COMMIT 命令时,就会执行该消息
和二阶段提交比较
二阶段提交会有回滚,zab 没有回滚
follower 要么回 ACK 给 leader,要么抛弃 leader,在某一时刻,leader 的状态与 follower 的状态很可能不一致
因为 Zab 的广播过程不需要终止事务,也就是说不需要所有 follower 都返回 ACK 才能进行 COMMIT,而是只需要合法数量(2f+1 台服务器中的 f+1 台) 的follower,也提升了整体的性能
因为二阶段提交要求所有的请求必须返回确认,才可以,有任意一个请求失败,则必须回滚
恢复
Zab 协议的广播部分不能处理 leader 挂掉的情况,Zab 协议引入了恢复模式来处理这一问题
目的
已经被处理的消息不能丢
被丢弃的消息不能再次出现
场景
当 leader 收到合法数量 follower 的 ACKs 后就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」。但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息
Commit也要求保证半数以上成功. 才会最终给客户端 ack
可能挂掉的时候, 有一部分节点还没有收到 commit 请求.此时需要恢复
选举策略
选举拥有 proposal 最大值(即 zxid 最大) 的节点作为新的 leader:
已经处理的消息不能丢
由于所有提案被 COMMIT 之前必须有合法数量的 follower ACK,即必须有合法数量的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保存了所有被 COMMIT 消息的 proposal 状态。
新的 leader 与 follower 建立先进先出的队列.先将自身有而 follower 没有的 proposal 发送给 follower,再将这些 proposal 的 COMMIT 命令发送给 follower,以保证所有的 follower 都保存了所有的 proposal、所有的 follower 都处理了所有的消息。
新的 leader 将自己事务日志中 proposal 但未 COMMIT 的消息处理。
已经处理的消息是指客户端已经认为 处理成功的请求,即 挂掉节点已经 commit 的请求
不包括flower 接收到proposal,但是leader还未 commit的请求. 这些请求客户端认为失败了, 是丢弃的请求
总结
新的leader 会将未 commit 的请求丢掉. 然后向其他follower同步,未 commit的请求. 或者未接受到的请求
被丢弃的消息不能再次出现
当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的。 此时,之前挂了的 leader 重新启动并注册成了 follower,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,需要将其删除。
挂掉的节点接收到 proposal但是还没有发送出去的.
如何实现
Zab 通过巧妙的设计 zxid 来实现这一目的。一个 zxid 是64位,高 32 是纪元(epoch)编号,每经过一次 leader 选举产生一个新的 leader,新 leader 会将 epoch 号 +1。低 32 位是消息计数器,每接收到一条消息这个值 +1,新 leader 选举后这个值重置为 0
旧的 leader 挂了后重启,它不会被选举为 leader,因为此时它的 zxid 肯定小于当前的新 leader。当旧的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有的拥有旧的 epoch 号的未被 COMMIT 的 proposal 清除。
只要和当前epoch不同的序号,且 未 commit的请求都会被干掉
重启时
在Zookeeper服务器启动期间,首先会进行数据初始化工作,用于将存储在磁盘上的数据文件加载到Zookeeper服务器内存中。
重建树, 避免所有数据都从 leader获取
一是简化二阶段提交,提升了在正常工作情况下的性能;二是巧妙地利用率自增序列,简化了异常恢复的逻辑,也很好地保证了顺序处理这一特性。
分支主题
一致性保证
单一视图是何意
同一个客户端无论连接到集群中的哪台机器上,都将会看到服务的同一视图。即:同一客户端无论什么时候连接到哪个服务器上,都不会看到比自己之前看到的数据更早版本的数据。
同一客户端
非跨客户端的视图
如果想在跨客户端获取最新的数据,调用 sync 将 client连接的 server和 leader同步, 成功后,异步等待通知
如何保证
连接过程
客户端通过服务器连接字符串、timeout等参数,创建客户端实例,启动客户端相关处理线程
♦ 客户端与服务端之间创建socket连接
♦ 客户端向服务端发送连接建立请求
♦ 服务端接收到连接建立请求后,会验证是否合法,决定是否建立连接
♦ 如果连接合法,那么将与客户端之间建立起连接,并开始请求处理流程
♦ 如果连接不合法,那么将拒绝连接,客户端将会寻找集群中的其他服务器,尝试建立连接
服务端
获取该客户端之前收到的zxid信息
• 验证客户端当前看到的数据版本信息是否比服务器的数据版本新,如果客户端当前看到的数据版本比较新,那么服务器将直接拒绝连接建立请求
保证客户端的zxid 一定小于服务端的
服务端每次对客户端的请求都会将自己最新的zxid 返回给客户端
通过客户端和服务端zxid 保证
当客户端正常连接集群中的一台服务器时,每次请求响应都会返回所连接的服务器上所处理的最新的事务id并进行记录。当客户端由于各种原因导致与服务器之间断连时,客户端将会以自己看到代表数据版本信息的zxid一起发送给服务端,请求建立连接。服务端在收到连接建立请求时,会进行判断:自己的数据版本没有客户端之前看到的数据版本新,服务端将会拒绝连接建立。从而保证客户端不会连接到数据版本比自己之前看到的旧的服务器上,因此不会请求到老版本的数据,从而保证了单一视图特性
网络延迟或者其他因素可能导致不同的客户端在不同的时刻感知某一监视事件,但是不同的客户端所看到的一切具有一致的顺序
如果是对zk进行读取操作,读取到的数据可能是过期的旧数据,不是最新的数据。
一致性保证
顺序一致性:来自客户端的更新将按照发送的顺序被写入到zk
原子性:更新操作要么成功要么失败,没有中间状态
可靠性:一旦应用更新,数据将被持久化,直到数据被再次更新,对于该保证有两个推论:1、如果客户端得到了成功的返回码,说明写入成功,数据被持久化,如果出现了通信错误,超时等一些故障,客户端将不知道更新是否已应用。我们采取措施尽量减少失败,但唯一的保证是只有成功的返回码。 (这在Paxos中称为单调性条件。)2、如果客户端已经读取到了数据或者写入成功了数据,都不会因为zk的失败而导致回滚;
及时性:任何客户端所看到的系统视图的滞后都是有限的,不会超过几十秒。如果一个服务器数据很陈旧就会关闭,并强迫客户端连接到新的服务器。
出于性能的原因,所有的读操作都是从ZooKeeper服务器的内存获得数据,它们不参与写操作的全局排序。
4.等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。
Zookeeper 本身提供了顺序保证(ordering guarantee):即客户端只有首先看到了监视事件后,才会感知到它所设置监视的znode发生了变化(a client will never see a change for which it has set a watch until it first sees the watch event)。
网络延迟或者其他因素可能导致不同的客户端在不同的时刻感知某一监视事件,但是不同的客户端所看到的一切具有一致的顺序
脑裂
分为follower 和 leader脑裂. 当脑裂发生时, 如果 follower和 leader 及其他节点通信延迟到某个值, 会导致 follower不可用.
leader 脑裂会自动选举 leader
网络分区后, 小于等于n/2的节点的集群都是不可用的,例如 5 个节点,其中 2/3分区, 2 节点的分区不可用
避免形成两个 leader,导致数据不一致
QA
11. Zookeeper怎样升级,影响是什么?
Zookeeper升级采用逐台重启,并且先Follower最后Leader的方式升级。重启Follower时,其上的连接经过CONNECTION_LOSS后会重新连上Zookeeper集群,到最后重启Leader时,集群将重新选主,期间服务不可用,最坏情况的选主时间按1MIN/GB来计算。
集群选主时,以连接的 session不会失效
假设客户端以30s新建Session成功后,OP把整个集群停掉1分钟,之后重启。这种场景下,客户端是能够重新与集群建立连接的。在集群停机的这段时间内,计时器是不会增加的,集群重启后,会把之前存在的Session全部刷新,并重启计时器。因此,只要客户端在30s内重新连上集群,该Session不会超时。
集群停机的这段时间内,计时器是不会增加的
Zookeeper对节点大小的限制是什么
默认节点大小不能超过1M,当Client尝试写或者创建超过限制的节点时,该Client会被Server直接关闭,API返回CONNECTION_LOSS。
zk实现特性
一致性:数据一致性,数据按照顺序分批入库。
顺序一致性 从同一个客户端发起的事务请求,最终将会严格按照其发起顺序被应用到zookeeper中
原子性:事务要么成功要么失败,不会局部化。
单一视图:客户端连接集群中任一zk节点,数据都是一致的。
可靠性:每次对zk的操作状态都会保存在服务端。
实时性:客户端可以读取到zk服务器的最新数据。
场景
发布订阅
发布与订阅即所谓的配置管理,顾名思义就是将数据发布到zk节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。例如全局的配置信息,地址列表等就非常适合使用。
1. 索引信息和集群中机器节点状态存放在zk的一些指定节点,供各个客户端订阅使用。
2. 系统日志(经过处理后的)存储,这些日志通常2-3天后被清除。
3. 应用中用到的一些配置信息集中管理,在应用启动的时候主动来获取一次,并且在节点上注册一个Watcher,以后每次配置有更新,实时通知到应用,获取最新配置信息。
4. 业务逻辑中需要用到的一些全局变量,比如一些消息中间件的消息队列通常有个offset,这个offset存放在zk上,这样集群中每个发送者都能知道当前的发送进度。
1. 在搜索系统中,如果集群中每个机器都生成一份全量索引,不仅耗时,而且不能保证彼此之间索引数据一致。因此让集群中的Master来进行全量索引的生成,然后同步到集群中其它机器。
5. 系统中有些信息需要动态获取,并且还会存在人工手动去修改这个信息。以前通常是暴露出接口,例如JMX接口,有了zk后,只要将这些信息存放到zk节点上即可。
分布式命名
这个主要是作为分布式命名服务,通过调用zk的create node api,能够很容易创建一个全局唯一的path,这个path就可以作为一个名称。
分布式通知/协调
1. 另一种心跳检测机制:检测系统和被检测系统之间并不直接关联起来,而是通过zk上某个节点关联,大大减少系统耦合。
2. 另一种系统调度模式:某系统有控制台和推送系统两部分组成,控制台的职责是控制推送系统进行相应的推送工作。管理人员在控制台作的一些操作,实际上是修改了ZK上某些节点的状态,而zk就把这些变化通知给他们注册Watcher的客户端,即推送系统,于是,作出相应的推送任务。
3. 另一种工作汇报模式:一些类似于任务分发系统,子任务启动后,到zk来注册一个临时节点,并且定时将自己的进度进行汇报(将进度写回这个临时节点),这样任务管理者就能够实时知道任务进度。
另一种工作汇报模式:一些类似于任务分发系统,子任务启动后,到zk来注册一个临时节点,并且定时将自己的进度进行汇报(将进度写回这个临时节点),这样任务管理者就能够实时知道任务进度。
使用zookeeper来进行分布式通知和协调能够大大降低系统之间的耦合。
集群管理
器在线率有较高要求的场景,能够快速对集群中机器变化作出响应。这样的场景中,往往有一个监控系统,实时检测集群机器是否存活。过去的做法通常是:监控系统通过某种手段(比如ping)定时检测每个机器,或者每个机器自己定时向监控系统汇报“我还活着”。 这种做法可行,但是存在两个比较明显的问题:1. 集群中机器有变动的时候,牵连修改的东西比较多。2. 有一定的延时。
多master管理 slaver时,可以使用zk 管理 slave .避免自己维护心跳
Master选举
Master选举的容灾措施是,可以随时进行手动指定master,就是说应用在zk在无法获取master信息时,可以通过比如http方式,向一个地方获取master。
分布式锁
zk的分布式锁不能严格保证同时只有一个节点获取锁, 当客户端网络超时时, 会导致zk 释放该节点, 其他节点获取到该锁,但是实际上该客户端还没有感知到自己失去了锁.
可以使用增大 session超时保证这个问题
将锁的超时时间小于session 过期时间
临时节点的生命期与Session绑定,当Session超时后,临时节点将被Zookeeper删除。通常在需要某种宕机检测的场景中使用临时节点,比如分布式锁,采用临时节点避免因宕机而死锁。
适用场景
在粗粒度分布式锁,分布式选主,主备高可用切换等不需要高TPS 支持的场景下有不可替代的作用,而这些需求往往多集中在大数据、离线任务等相关的业务领域,因为大数据领域,讲究分割数据集,并且大部分时间分任务多进程/线程并行处理这些数据集,但是总是有一些点上需要将这些任务和进程统一协调,这时候就是 ZooKeeper 发挥巨大作用的用武之地
不适用的场景
服务发现和健康监测场景下,随着服务规模的增大,无论是应用频繁发布时的服务注册带来的写请求,还是刷毫秒级的服务健康状态带来的写请求,还是恨不能整个数据中心的机器或者容器皆与注册中心有长连接带来的连接压力上,ZooKeeper 很快就会力不从心,而 ZooKeeper 的写并不是可扩展的,不可以通过加节点解决水平扩展性问题
海量物理机监控不适合,长连接心跳过多
在交易场景交易链路上,在主业务数据存取,大规模服务发现、大规模健康监测
zk性能
分支主题
纵轴为每秒响应的客户端请求数,横轴为读请求所占百分比。从图中可以清晰的看到,随着读请求所占百分比的提高,Zookeeper的QPS也不断提高。
Zookeeper集群的任意一个服务端节点都可以直接响应客户端的读请求
Zookeeper将全量数据存储于内存中,从内存中读取数据不需要进行磁盘IO,速度要快得多
3.Zookeeper放松了对分布式数据的强一致性要求,即不保证数据实时一致,允许分布式数据经过一个时间窗口达到最终一致,这也在一定程度上提高了其吞吐量。
curator & zookeeper 使用
session
每一个client都是一个 session
close 方法会向 server发送关闭 session信息
在一个应用中,只需要一个ZK实例就足够了.CuratorFramework实例都是线程安全的
在zookeeper中“滴答”(tick time)参数定义了基本时间周期,其他参数都根据该参数来定义。通常滴答参数设置为2秒,对应于允许的超时范围是4到40秒
状态
CONNECTING、CONNECTED、RECONNECTING、RECONNECTED 和 CLOSE
curator好处
1. 当ZooKeeper客户端内部出现异常, 将自动进行重连或重试, 该过程对外几乎完全透明
更清晰的API: 简化了ZooKeeper原生的方法, 事件等, 提供流式fluent的接口
提供了: 选举,共享锁, 路径cache, 分布式队列,分布式优先队列等
通过ClientListener实现。 通过CuratorFramework实例里的addListener()注册listener. listener实现以下方法: - eventReceived() 当一个后台操作完成或者指定的watch被触发时该方法被调用
通知模型
Zookeeper 就实现了这种服务端主动推送请求的机制
客户端使用『拉』的方式从服务端获取最新的状态,这种方式获取的状态很有可能都是过期的,需要客户端不断地通过轮询的方式获取服务端最新的状态
一次性事件通知
当设置监视的数据发生改变时,该监视事件会被发送到客户端,例如,如果客户端调用了getData("/znode1", true) 并且稍后 /znode1 节点上的数据发生了改变或者被删除了,客户端将会获取到 /znode1 发生变化的监视事件,而如果 /znode1 再一次发生了变化,除非客户端再次对/znode1 设置监视,否则客户端不会收到事件通知。
client不能宣称自己的session expired,session expired是由Zookeeper Server来决定的,client可以选择自己主动关闭session。
连接状态和管理
如何处理CONNECTION_LOSS
此时无法判断请求处理是成功还是失败,只能业务自己判断, 但是 zookeeper一定是成功或失败,不存在中间状态
在Zookeeper中,服务器和客户端之间维持一个长连接,CONNECTION_LOSS意味着这个连接断开了。客户端API返回CONNECTION_LOSS时,不能确定请求是成功还是失败(视连接断开发生在请求发送之前还是之后,遗憾的是无法区分这两种情况),应用需要自己的逻辑来确认操作是否成功
如何处理SESSION_EXPIRE
Session超时由服务端管理。客户端在初始化连接时会指定该Session的超时时间(下面用T表示),相当于服务端给客户端的一个Lease。客户端的每次请求到达服务端后,服务端会刷新该Session的Lease(续约),如果客户端在T/3时间内都无请求,则内部会发送一个PING来续约。正常情况下,客户端与服务端的Session将一直保持,当出现网络闪断或者连上的那台服务器断电等情况,
只要客户端在Lease时间内重连上Cluster中某台机器,Session将仍然有效。
如果服务端在时间T内未收到一个Session的任何信息时,Zookeeper认为该Session已经超时了,之后由集群的Leader来下发Session超时的命令,该Session的相关信息(Session本身、其创建的临时节点及添加的Watch)将被Zookeeper清除。在Session超时这一过程中,客户端通常会先看到连接断开,只有与Zookeeper重新建立连接后,客户端才能收到Session超时事件(也就是说SESSION_EXPIRE事件一定是服务端告诉客户端的,客户端本身没有相关的计时逻辑)。
收到SESSION_EXPIRE后,客户端要做的事情视应用的场景而定。一般情况,需要重新与Zookeeper建立建立(注意一定要关闭之前的连接),重新建立临时节点,重新添加的Watch。
zk 抛出异常时
处理连接断开事件中,应用开发者必须清楚处于闪断附近的那个请求是什么(这常常难以判断),该请求是否是幂等的,对于业务请求在Server端服务处理上对于”仅处理一次” “最多处理一次” “最少处理一次”语义要有选择和预期
例如
应用在收到 ConnectionLossException 时,之前的请求是Create操作,那么应用的catch到这个异常,应用一个可能的恢复逻辑就是,判断之前请求创建的节点的是否已经存在了,如果存在就不要再创建了,否则就创建
如果应用使用了exists Watch 去监听一个不存在的节点的创建的事件,那么在ConnectionLossException的期间,有可能遇到的情况是,在这个闪断期间,其它的客户端进程可能已经创建了节点,并且又已经删除了,那么对于当前应用来说,就miss了一次关心的节点的创建事件,这种miss对应用的影响是什么?是可以忍受的还是不可接受?需要应用开发者自己根据业务语义去评估和处理。
SessionExpiredException 和 SessionExpired 事件
Session 超时是一个不可恢复的异常,这是指应用Catch到这个异常的时候,应用不可能在同一个Session中恢复应用状态,必须要重新建立新Session,老Session关联的临时节点也可能已经失效,拥有的锁可能已经失效
重连
重连发生在两种情况,其一是socket连接发生异常,其二是socket连接正常,但是2T/3时间内未收到服务端的响应。
通知
不支持永久Watch的原因是Zookeeper无法保证性能。永久Watch意味着数据的每一次修改都要通知到所有的观察者,这是无法接受的。在大多数情况下,客户端并不需要追踪节点的每一次变化。
Watch机制为什么只通知改变,而不同时发送改变之后的数据?
在Zookeeper最初始的版本中,事件通知带上了具体的变更内容,比如/a的值变成了v2,但这很难被正确使用。Watch的目的是用来追踪节点最近的变化,直接通知内容会有如下问题:比如Client A首先获取/a的内容为v1,并设置了Watch,之后Client B将/a的值依次设置为v2,v3,这样Client A将只能获取到/a的内容变成了v2,无法得知其已经变为v3。
能否捕获节点每次的数据变化吗
收到通知与重新添加Watch不是原子的,如果在之间节点的内容被修改多次,这中间的修改将不被感知。
如果一定需要追踪节点每次的变化,需要仔细的设计观察者与写者之间的协议,可参考ZKC一致性cache的做法。
watch注意事项
a. Watch的通知是一次性的;
b. 客户端在CONNECTIONLOSS之后有重新连上Zookeeper(未发生SESSION超时),那么这个连接注册的Watch依然在。内部会重新发送添加过的Watch,并且如果Watch的节点在CONNECTIONLOSS阶段发生了改变,重连上之后会收到对应的事件(不会因为与Zookeeper的连接断开而丢失事件);
c. 需要注意的一种情况是:对一个不存在的节点添加exists的Watch,之后该Session与Zookeeper断开连接,在重新连上之前,这个节点被创建了,又被删除了,该Session重新连上之后,将不会收到通知。
d. 变化指节点的版本号,即使已相同的值set该节点,将触发CHANGED事件;
e. 对同一个节点多次注册Watch,只会收到一次事件,如执行zoo_wexists(“/a”)两次,当/a被创建或者被删除时,该Session只会收到一次通知;
f. 切忌在回调函数中抛出异常
curator 中的状态
CONNECTED 第一次连接
SUSPENDED 对应原生的Disconnected
LOST 对应原生的Expired
zk 原生状态
SyncConnected 连接成功和重连成功时触发
Disconnected 连接断开时触发
Expired session过期时触发
java 客户端 使用及原理
创建ZooKeeper对象时,也会创建两个线程:IO线程和事件线程。所有IO都发生在IO线程上(使用Java NIO)。所有事件回调都发生在事件线程上。会话维护(例如重新连接到ZooKeeper服务器和维护心跳)在IO线程上完成。同步方法的响应也在IO线程中处理。异步方法和监视事件的所有响应都在事件线程上处理
异步调用和观察者回调的所有完成将按顺序进行,一次一个。调用者可以进行他们希望的任何处理,但在此期间不会处理任何其他回调。
回调不会阻止IO线程的处理或同步调用的处理。
同步调用可能无法按正确顺序返回。例如,假设客户端执行以下处理:发出节点/ a的异步读取,并将 watch设置为true,然后在读取的完成回调中执行/ a的同步读取。(也许不是很好的做法,但也不是非法的,这只是一个简单的例子。)请注意,如果异步读取和同步读取之间存在/ a更改,则客户端库将在同步读取的响应之前接收监视事件/更改,但由于完成回调阻止了事件队列,在 处理监视事件之前,同步读取将返回新值/ a
所有的zk事件都在EventThread中按顺序执行,如果一个事件长时间执行会导致其他事件无法及时响应。
如果在事件 process过程中堵塞,其他事件即使发生了,也只会放到本地队列中,暂时不会执行。
临时节点使用
在synconnected 事件
判断是否存在该节点,如果存在是否需要删除重建.
存在的话,创建会 报错
对sessionId发生了变化且EPHEMERAL节点已经存在的情况要先删除后重建
不能仅仅判断节点是否存在,存在的可能性存在 于对应的客户端处在将要超时还未超时的间隙
每个节点都会存在 sessionId,需要判断是否相同
0 条评论
下一页