- 基础:
- 功能:服务生产者将自己提供的服务注册到Zookeeper中心,服务的消费者在进行服务调用的时候先到Zookeeper中查找服务,获取到服务生产者的详细信息之后,再去调用服务生产者的内容与数据。
- 选举机制:
- 首次启动:根据启动顺序投票 投给myid最大的服务器 然后当超过半数时leader就被选出
- Leader挂掉后,投票给最大的id的服务器
- 特点:
- 顺序一致性:从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
- 原子性:所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
- 单一系统映像:论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。
- 可靠性:一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖
- 优化:
- 日志相关:
- Zookeeper默认是关闭日志清理的 但服务运行一段时间 会发现磁盘被日志给打满了 所以要开启日志的自动清理
- 日志相关:
清理配置:
autopurge.purgeInterval=1 # 指定清理频率,单位为小时 (default: 0 表示不开启自动清理)。
autopurge.snapRetainCount=3 # 指定需要保留的文件数目 (default: 3)。
- 设置系统日志目录 默认是写入到zookeeper.out文件目录下的 该文件不会自动切分和定期清理 长时间运行会导致磁盘占用过大 也不方便排除问题 所以要将系统日志输出到固定的目录下 并配置切分和清理的策略
- 适时地开启Observer模式:
- 压力过大时 启用Observer可以分担集群的压力 通过增加更多的Observer,可以接收更多读请求的流量,却不会牺牲写操作的吞吐量,因为Observer节点不参与决策,不会增加决策的复杂度。严格来说,增加 Observer并不是完全没有损耗,新的Observer在转发一个写操作后会收到一条额外的INFORM消息,但对该消息的处理很快,带来的性能损耗基本可以忽略
- 跨数据中心部署时,启用Observer减小网络延迟带来的影响 把leader/follower节点分散到多个数据中心,会因为数据中心之间的网络延迟,导致系统被拖慢。此时,可以将leader/follower部署在同一中心,Observer部署在其他中心,数据更新操作在同一个数据中心处理后,再同步到其他数据中心的Observer,而client则直接请求本地机房的Observer。 阿里的分布式数据库[中美异地机房]同步系统-Otter就使用了该模式。
- 使用JDK8 有一个类在JDK8中做了一些升级 性能提升了6倍以上
- Zookeeper自身的配置
- leaderServes如果ZK集群出现事务更新缓慢之类的情况,则可考虑修改该参数值为no。zookeeper.leaderServes参数用于控制Leader节点是否可以被Client端连接,默认值为 yes。 理论上Leader可以处理所有Client的读写请求,但是在ZooKeeper的架构设计中,Leader的主要作用是处理事务更新请求,以及集群本身运行的协调。所以,设置成no,可使得Leader节点不接受Client端的连接请求,以提高事务处理能力。
- jute.maxbuffer 如果ZK集群因为业务方的写入或请求的数据量过大,导致了性能问题,则需要考虑降低该参数的值。同时,我们经过Benchmark测试之后,发现写入数据量在超过10KB之后,会出现明显的性能下降。jute.maxbuffer用于控制单个ZNode上最大可以存储的数据量,默认值为1048575 (1M - 1, 由BinaryInputArchive.maxBuffer变量控制)。 ZooKeeper旨在存储大小为千字节 (1KB) 的数据,通常情况下,需要下调这个阀值。 需要注意的是,该参数并不是在Server和Client端同时设置才会生效。实际情况是,在客户端设置后,ZooKeeper将控制从Server端读取数据的大小 (outgoingBuffer);而在服务端设置后,则是控制从Client端写入数据的大小 (incomingBuffer)。
- globalOutstandingLimit zookeeper.globalOutstandingLimit参数用于控制服务器最大请求堆积量,默认值为 1000。 为防止服务端资源(内存、CPU、网络) 被耗尽,根据服务器最大处理能力,可做适当调整。
- 适时地开启Observer模式:
- 问题:
- Zookeeper的事务ID(ZXID)溢出,导致集群重启
我们的线上Kafka集群,由于对Zookeeper的操作过于频繁,导致了Zookeeper两个月左右会进行一次强制自重启,对业务产生了一定的影响。经过分析发现,自重启是由于ZXID溢出导致的。经过对源码的分析得知,ZXID的高32位用于epoch(LE选举轮次)、低32位用于记录Leader节点处理的事务数。假设一个Zookeeper集群承担的TPS为1K的话,那么只要2^{32} / (86400 * 1000) = 49.7 days就会将ZXID耗尽。 一个可行的方案是重新设计ZXID。高24位用于epoch,低40位用于事务counter,按照1K TPS算,那么需要2^{40} / (86400 * 1000 * 365) = 34.9 years之后才会进行一次强制选举。(该方案我们已提交至社区,ZOOKEEPER-2789 / PR#262,欢迎加入讨论)。