大纲
1.zk单机模式是如何启动的
2.zk集群是如何部署和启动的
3.zk集群部署要用什么样配置的机器
4.如何合理设置zk的JVM参数以及内存大小
5.zk配置的核心参数之tickTime、dataDir和dataLogDir
6.影响Leader与Follower组成集群的两个核心参数之initLimit和syncLimit
7.zk什么时候进行数据快照(snapCount = 10000)
8.一台机器上最多能启动多少个zk客户端(maxClientCnxns = 60)
9.一个znode中最多能存储多少数据量(jute.maxbuffer = 1M)
10.运行时的Leader与Follower会通过2888和3888端口进行通信
11.事务日志和数据快照是如何进行定时清理的
12.在2PC阶段写入的事务日志也有丢失的风险
13.Leader相关的两个参数之leaderServers和cnxTimeout
14.zk提供给运维使用的命令说明
1.zk单机模式是如何启动的
下面先通过bin/zkServer.sh脚本来启动单机模式的zk,然后再通过bin/zkCli.sh脚本 + 2181端口连接到zk。
$ cd zookeeper
$ sudo bin/zkServer.sh start
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/demo/Documents/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED$ ps -ef |grep java
$ sudo bin/zkCli.sh
/usr/bin/java
Connecting to localhost:2181
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
2.zk集群是如何部署和启动的
要部署zk集群,可以准备三台机器,每台机器上部署一个zk进程。每台机器上的zk配置文件添加如下内容,让每个节点感知集群中有几台机器。
server.1=zookeeper01:2888:3888
server.2=zookeeper02:2888:3888
server.3=zookeeper03:2888:3888
zk集群的每个节点都有一个ID编号,需要在指定的dataDir目录下创建一个myid文件,把该zk节点的ID编号写在里面。
zk的端口号分为2888和3888。其中3888是用来进行Leader选举的,2888是用来进行数据同步的。
3.zk集群部署要用什么样配置的机器
zk属于基础架构类的中间件系统,一般部署的机器比较少(通常3-5台),但不建议用太普通的配置。部署zk、Kafka、Hbase、HDFS等的机器,所需要的配置都是比较高的。
4核8G的机器,每秒可以抗1000并发。
8核16G的机器,每秒可以抗几千并发。
16核32G的机器,每秒可以抗上万或几万并发。
一般采用3台机器(8核16G/16核32G + SSD固态硬盘)来部署一个zk集群,三台这种机器的小集群每秒可以抗十几万的并发。
比如3台16核32G的机器:1个Leader + 2个Follower。其中,Leader主要负责写,每秒可以抗几万写并发。Follower负责读,每秒可以抗5万~10万读并发。
虽然写QPS无法线性的扩展,但读QPS可通过Observer节点来扩展。设置Observer节点很简单,只需修改配置强制要求其角色是Observer,不能是Leader或Follower即可。
4.如何合理设置zk的JVM参数及内存大小
zk本身是用Java写的,是基于JVM虚拟机来运行的。启动zk就是启动一个JVM进程,JVM进程里面会执行zk的全部代码,所以需要合理设置JVM的三大参数。
一.首先分配各块内存区域的大小
包括堆内存、栈内存、Metaspace区域的内存,根据机器内存去设置。比如机器有16G的内存,堆内存可分配10G,栈内存可分配每个线程的栈1MB,Metaspace区域可以分配512MB。
二.然后设置垃圾回收器
通常Java应用的新生代 + 老年代的垃圾回收器会设置为ParNew + CMS,但大内存机器不建议使用这个组合,建议使用G1垃圾回收器。
三.JVM启动前要加入一些参数
比如GC日志要写入哪个目录中,发生OOM时要自动dump内存快照出来放哪个目录去。
当这三大JVM参数都合理设置好之后,就可以启动zk并开始使用了。在各种情况下以及一些运气高峰期,还要使用jstat观察一下zk的JVM情况:包括新生代的对象增长速率 + YGC的频率 + 老年代增长速率 + FGC的频率。如果GC有问题,就要进行GC调优,合理优化JVM参数。如果有监控系统,需要对zk运行时的JVM的情况进行监控。
5.zk配置的核心参数之tickTime、dataDir和dataLogDir
正式启动zk之前,还需要配置zk的一些参数:
$ cat conf/zoo.cfg
(1)tickTime
tickTime的默认值是2000ms,表示zk里的最小时间单位。其他的一些参数就会以这个tickTime为基准来进行设置,比如有的参数就是tickTime * 2。
(2)dataDir
用来存放zk里的数据快照。zk里会存储很多数据,在磁盘里会有一份内存数据的快照,这样zk停机重启后才能恢复之前的数据。
(3)dataLogDir
写数据时有2PC机制,首先会写Proposal提议,也就是事务日志。每台机器会将事务日志写入到本地磁盘。所以如果使用SSD固态硬盘,可以提升写性能。
6.影响Leader与Follower组成集群的两个核心参数之initLimit和syncLimit
(1)initLimit
initLimit的默认值是10,意思是10 * tickTime,即20s。表示Leader在启动后会等待Follower跟自己建立连接,最长等待时间是20s。所以在20s内Follower必须要跟Leader建立连接,否则Leader就不等Follower,直接进入消息广播模式,对外提供服务了。如果zk里存储的数据量比较大,Follower恢复数据需要的时间比较长,此时就可调大该参数。
(2)syncLimit
syncLimit的默认值是5,意思是5 * tickTime,即10s。Leader会向Follower发起心跳检测,如果超过10s没有心跳响应,Leader就会把这个Follower给踢除出去。
7.zk什么时候进行数据快照(snapCount = 10000)
zk里的数据分成两份:一份是磁盘上的事务日志(dataLogDir),一份是内存里的数据。
理论上两份数据是一致的。即使Follower宕机,也只丢失内存里的数据,磁盘上的事务日志是存在的。即使Follower没收到事务日志就宕机,也可以重启后找Leader同步数据。
比如zk在磁盘里有一份事务日志,它启动后应该如何重建内存里的数据?难道把事务日志进行回放?重新执行每条事务日志到内存里去吗?
所以zk会有一个数据快照机制,每次执行一定数量的事务后,就会把内存里的数据存储到dataDir目录中,作为zk当前的一个数据快照。
比如现在事务日志里有1000个事务,已经把1000个事务对应的内存数据写入到dataDir里作为一个数据快照了。此后继续写数据写到事务日志里有1032个事务时,zk进行重启。zk重启时就可以把包含1000个事务的快照直接加载到内存里,然后把1000之后的32个事务,在内存里回放一遍,即可恢复重启前的数据。
对应的参数是snapCount,默认是10万个事务存储一次快照。表示的是如果没到10万条事务zk就重启了,那么此时是没有数据快照的,也就是10万条事务以内不需要快照。
8.一台机器上最多能启动多少个zk客户端(maxClientCnxns = 60)
一台机器可以创建多少个zk客户端,可以跟zk服务端建立多少个连接?这是有限制的,默认最多60个,也就是zk服务端最多只允许一台机器和它建立60个连接,但可通过maxClientCnxns参数来设置。
如果开发时不注意没有使用单例模式,每次请求都创建一个zk客户端建立连接进行通信,然后再销毁zk客户端。当多个并发请求一起连接zk时,就会导致一台机器上有很多zk客户端,可能最终导致这台机器发出的zk请求被zk服务端拒绝。
9.一个znode中最多能存储多少数据量(jute.maxbuffer = 1M)
一个znode中最多能存储的数据量由参数jute.maxbuffer设定,默认是1M。对应的数值是1048575,单位bytes,换算成M就是1M。一般建议不要在一个znode中存储过多数据量,几百个字节~几百K即可。
10.运行时的Leader与Follower会通过2888和3888端口进行通信
3888端口,用于在集群恢复模式时进行Leader选举投票。2888端口,用于在Leader和Follower之间进行数据同步和运行时通信。
11.事务日志和数据快照是如何进行定时清理的
zk在不停的运行,事务日志会越来越多,但不可能是无限多的,所以zk会切割出多个事务日志文件。每次执行一次数据快照时,都会有一个独立的数据快照文件。最后zk的磁盘上会存在多个事务日志文件,多个数据快照文件。
默认是没有开启定时清理数据文件的功能,所以应该按如下配置进行开启。这样每隔1小时会让zk在后台自动清理多余的事务日志文件和数据快照文件,而且最多保存3个文件。
autopurge.purgeInterval=1
autopurge.snapRetainCount=3
12.在2PC阶段写入的事务日志也有丢失的风险
事务进行Commit提交时,有没有日志丢失的风险?是有的。在2PC的第一个阶段,Proposal提议时各机器会把事务日志写入磁盘时,一般会写入OS Cache。在2PC的第二个阶段,Commit提交时才会强制把写的事务日志fsync到磁盘上。
因此,参数"forceSync: yes"指的就是:在Commit提交时,会强制把OS Cache中的事务日志fsync到磁盘上去。
在Commit提交时,最好将OS Cache中的事务日志fsync到磁盘上。否则如果机器挂了,那么就有可能丢失OS Cache里还没刷入磁盘的事务日志数据。
虽然zk在处理写请求时,会涉及到多台机器往磁盘写事务日志。但是由于写事务日志是顺序写磁盘,这与随机写内存的性能差不多,所以性能也很高。而且写事务日志一开始就是往OS Cache里写的,所以性能就可以更高了。
13.Leader相关的两个参数之leaderServers和cnxTimeout
(1)参数leaderServers,默认值是yes
表示Leader是否接收客户端的连接,所有写请求由Follower转发给Leader,Leader只接收Follower转发的写请求。
(2)参数cnxTimeout,默认5000
在进行Leader选举时,各个机器会基于3888端口建立TCP长连接,在这个过程中建立TCP连接的超时时间默认是5000毫秒。
一般来说,在启动zk集群之前,首先需要在zoo.cfg配置文件里设置好参数,比如设置zk集群server.1、server.2的信息,设置dataDir、dataLogDir的目录,开启自动清理数据文件等。然后再使用zkServer.sh命令,分别启动Leader和Follower等多个节点。