为了有效使用 ZooKeeper,需要了解 ZooKeeper 可能发生的故障种类及处理方式。
故障恢复
当客户端从 ZooKeeper 服务端获取响应时,可以肯定这个响应信息与其他响应信息能够保持一致性。而在连接丢失等无法保证一致性的情况下,客户端会使用 Disconnected 事件和 ConnectionLossException 异常来表示异常状态。
出现上述情况时,ZooKeeper 客户端会不断尝试连接到另一个 ZooKeeper 服务器,直到最终重新建立会话。会话重新建立会产生 SyncConnected 事件,开始处理请求,注册之前已经注册的监视点,并对失去连接这段时间的数据变更产生监视点事件。
如果发生异常时没有正在进行的请求,则对客户端几乎没有影响;如果存在正在进行的请求,就需要认真处理异常状况。
对于异常时正在进行的请求,比如 create 操作,客户端无法通过异常信息判断请求是否被处理,需要在重新建立连接后先获取节点状态,再根据节点状态选择是否重新执行 create 操作,而不能直接简单地重复操作。
故障导致 exists 监视点丢失事件
ZooKeeper 在故障重连后,对于数据没有发生变更的监视点会重新注册,对已经发生变化的节点产生监视点事件,但存在一种情况会错误监视点事件 —— exists 监视点。
exists 操作比较特殊,是对一个不存在的监视点设置监视点,如果在连接断开期间所监视的节点被创建然后删除,待重新连接后,没有发现这个节点,所以只是重新注册,并不会产生监视点事件。
因为这种特殊情况,所以要尽量避免监视一个 znode 节点的创建事件,如果一定要监视创建事件,应该尽量监视存活期较长的 znode 节点。
群首选举与外部资源
ZooKeeper 为所有客户端提供了系统的一致性视图,客户端与 ZooKeeper 的任何交互操作,ZooKeeper 都会保持同步,但 ZooKeeper 无法保护与外部设备的交互操作。
比如多个客户端通过群首选举让主节点持有外部资源的情况:客户端 A 首先称为主节点持有节点,但因为线程调度等原因(比如持续较长时间的垃圾回收),ZooKeeper 判断与 A 会话中止,重新选举客户端 B 为主节点并持有外部资源,待 A 恢复正常时发送已经队列化的更新到外部资源,损害系统状态。
为了解决上述问题,可以尽量确保应用不会在超载或时钟偏移的环境中运行,另外可以通过 ZooKeeper 来扩展对外部设备协作的数据,比如使用隔离符号。简单的隔离符号比如 只有持有最新符号的客户端才能访问资源,对外部资源进行访问时,客户端需要提供隔离符号,如果外部资源在之前已经接收过更高版本的符号,访问就会被拒绝。
数据字段和子节点限制
ZooKeeper 默认对数据字段的传输限制为 1MB,该限制为任意节点数据的最大存储字节数,同时也限制任意父节点可以拥有的子节点数。
ZooKeeper 默认的限制值已经足够大,需要避免接近该限制值的使用。如果有特殊用途可以通过修改配置调整限制值。