一、前言
ZooKeeper
的功能特性通过ZooKeeper
配置文件来进行控制管理( zoo.cfg
配置文件)。 ZooKeeper这样的设计其实是有它自身的原因的。通过前面对ZooKeeper
的配置可以看出,对ZooKeeper
集群进行配置的时候,它的配置文档是完全相同的(对于集群伪分布模式来说,只有很少的部分是不同的)。这样的配置方使得在部署ZooKeeper
服务的时候非常地方便。另外,如果服务器使用不同的配置文件,必须要确保不同配置文件中的服务器列表相匹配。
在设置ZooKeeper
配置文档的时候,某些参数是可选的,但是某些参数是必须的。这些必须的参数就构成了ZooKeeper
配置文档的最低配置要求。
最近发现在用zookeeper出现经常出现连接超时,出现连接中断,数据丢失等原因。后面看了官网配置自己整理优化几点:
2.1错误日志: 2016-04-11 15:00:58,981 [myid:] - WARN [SyncThread:0:FileTxnLog@334] - fsync-ing the write ahead log in SyncThread:0 took 13973ms which will adversely effect operation latency. See the ZooKeeper troubleshooting guide >2.2,错误原因分析 “FOLLOWER”在跟“LEADER”同步时,fsync操作时间过长,导致超时。 第一步:分析服务器问题: 我查看了服务器io和负载都不高。内存空间实际使用率不高。可是编辑文件出现了卡顿. 可以发现: 服务器并没有占用很多内存的进程; 服务器也没有存在很多的进程; cat /var/log/message查看系统日志并没有发现什么异常; 另外ping服务器只有0.1ms多的延迟,因此不是网络问题。 后面发现硬盘有故障重新更换了一块硬盘。或者更换服务器。 >2.3,错误解决 增加“tickTime”或者“initLimit和syncLimit”的值,或者两者都增大。 >2.4,其他 这个错误在上线“使用ZooKeeper获取地址方案”之前也存在,只不过过没有这么高频率,而上线了“ZooKeeper获取地址方案”之后,ZooKeeper Server之间的同步数据量增大,ZooKeeper Server的负载加重,因而最终导致高频率出现上述错误。
二、配置文件:
下面是在最低配置要求中必须配置的参数:
### 最小配置 最小配置意味着所有的配置文件中必须要包含这些配置选项。 #### clientPort 服务器监听客户端连接的端口,亦即客户端尝试连接到服务器上的指定端口。 ##### dataDir ZooKeeper存储内存数据库快照文件的路径,并且如果没有指定其它路径的话,数据库更新的事务日志也将存储到该路径下。 注意:事务日志会影响ZooKeeper服务器的整体性能,所以建议将事务日志放置到由dataLogDir参数指定的路径下。 ##### tickTime 单个tick的时间长度,它是ZooKeeper中使用的基本时间单元,以毫秒为单位。它用来调节心跳和超时时间。例如,最小会话超时时间是2个tick。
生产环境例子:
tickTime:CS通信心跳数 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。 tickTime=2000 initLimit:LF初始通信时限 集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。 initLimit=5 syncLimit:LF同步通信时限 集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。 syncLimit=2 dataDir:数据文件目录 Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。 dataDir=/home/michael/opt/zookeeper/data dataLogDir:日志文件目录 Zookeeper保存日志文件的目录。 dataLogDir=/home/michael/opt/zookeeper/log clientPort:客户端连接端口 客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。 clientPort=2333 服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口) 这个配置项的书写格式比较特殊,规则如下: server.N=YYY:A:B 其中N表示服务器编号,YYY表示服务器的IP地址,A为LF通信端口,表示该服务器与集群中的Leader交换的信息的端口。B为选举端口,表示选举新Leader时服务器间相互通信的端口(当Leader挂掉时,其余服务器会相互通信,选择出新的Leader)。一般来说,集群中每个服务器的A端口都是一样,每个服务器的B端口也是一样。但是当所采用的为伪集群时,IP地址都一样,只能时A端口和B端口不一样。 #下面是一个非伪集群的例子: server.0=233.34.9.144:2008:6008 server.1=233.34.9.145:2008:6008 server.2=233.34.9.146:2008:6008 server.3=233.34.9.147:2008:6008 #下面是一个伪集群的例子: server.0=127.0.0.1:2008:6008 server.1=127.0.0.1:2007:6007 server.2=127.0.0.1:2006:6006 server.3=127.0.0.1:2005:6005
三、高级配置项说明
本节的配置选项是可选的。你可以使用它们进一步的优化ZooKeeper服务器的行为。有些可以使用Java系统属性来设置,一般的格式是“zookeeper.keyword”。如果有具体的系统属性,会在配置选项下面标注出来。
说明:设置Java系统属性可以在启动时后面加“-D”参数,比如:-Dzookeeper.keyword=xxx。而这些配置项默认可以通过$ZOOKEEPER_HOME/conf/zoo.cfg进行配置。
dataLogDir
没有对应的Java系统属性。
该参数用于配置ZooKeeper服务器存储事务日志文件的路径,ZooKeeper默认将事务日志文件和数据快照存储在同一个目录下,应尽量将它们分开存储。
注意:将事务日志文件存储到一个专门的日志设备上对于服务器的吞吐量和稳定的延迟有很大的影响。事务日志对磁盘性能要求比较高,为了保证数据一致性,ZooKeeper 在响应客户端事务请求之前,需要将请求的事务日志写到磁盘上,所以事务日志的写入性能直接影响ZooKeeper服务器处理请求的吞吐。所以建议给事务日志的输出配置一个单独的磁盘或者挂载点。
globalOutstandingLimit
对应的Java系统属性:zookeeper.globalOutstandingLimit。
客户端提交请求的速度可能比ZooKeeper处理的速度快得多,特别是当客户端的数量非常多的时候。为了防止ZooKeeper因为排队的请求而耗尽内存,ZooKeeper将会对客户端进行限流,即限制系统中未处理的请求数量不超过globalOutstandingLimit设置的值。默认的限制是 1000。
preAllocSize
对应的Java系统属性:zookeeper.preAllocSize。
用于配置ZooKeeper事务日志文件预分配的磁盘空间大小。默认的块大小是64M。改变块大小的其中一个原因是当数据快照文件生成比较频繁时可以适当减少块大小。比如 1000次事务会新产生一个快照(参数为snapCount),新产生快照后会用新的事务日志文件,假设一个事务信息大小100b,那么事务日志预分配的磁盘空间大小为100kb会比较好。
snapCount
对应的Java系统属性:zookeeper.snapCount。
ZooKeeper 将事务记录到事务日志中。当 snapCount 个事务被写到一个日志文件后,启动一个快照并创建一个新的事务日志文件。snapCount 的默认值是 100,000。
traceFile
对应的Java系统属性:requestTraceFile。
如果定义了该选项,那么请求将会记录到一个名为traceFile.year.month.day的跟踪文件中。使用该选项可以提供很有用的调试信息,但是会影响性能。
注意:requestTraceFile这个系统属性没有zookeeper前缀,并且配置的变量名称和系统属性不一样。
maxClientCnxns
没有对应的Java系统属性
在socket级别限制单个客户端到ZooKeeper集群中单台服务器的并发连接数量,可以通过IP地址来区分不同的客户端。它用来阻止某种类型的DoS攻击,包括文件描述符资源耗尽。默认值是60。将值设置为0将完全移除并发连接的限制。
clientPortAddress
服务器监听客户端连接的地址(ipv4,ipv6或主机名),亦即客户端尝试连接到服务器上的地址。该参数是可选的,默认我们以这样一种方式绑定,即对于服务器上任意 address/interface/nic,任何连接到clientPort的请求将会被接受。
minSessionTimeout
没有对应的Java系统属性
服务器允许客户端会话的最小超时时间,以毫秒为单位。默认值是2倍的tickTime。
maxSessionTimeout
没有对应的Java系统属性
服务器允许客户端会话的最大超时时间,以毫秒为单位。默认值是20倍的tickTime。
fsync.warningthresholdms
对应的Java系统属性:fsync.warningthresholdms。
用于配置ZooKeeper进行事务日志(WAL)fsync操作消耗时间的报警阈值,一旦超过这个阈值将会打印输出报警日志。该参数的默认值是1000,以毫秒为单位。参数值只能作为系统属性来设置。
autopurge.snapRetainCount
没有对应的Java系统属性。
当启用自动清理功能后,ZooKeeper将只保留autopurge.snapRetainCount个最近的数据快照(dataDir)和对应的事务日志文件(dataLogDir),其余的将会删除掉。默认值是3。最小值也是3。
autopurge.purgeInterval
没有对应的Java系统属性。
用于配置触发清理任务的时间间隔,以小时为单位。要启用自动清理,可以将其值设置为一个正整数(大于 1)。默认值是0。
syncEnabled
对应的Java系统属性:zookeeper.observer.syncEnabled。
和参与者一样,观察者现在默认将事务日志以及数据快照写到磁盘上,这将减少观察者在服务器重启时的恢复时间。将其值设置为“false”可以禁用该特性。默认值是 “true”。
四、集群配置选项说明
本节中的选项主要用于ZooKeeper集群。
electionAlg
没有对应的Java系统属性。
用于选择使用的Leader选举算法。”0”对应于原始的基于UDP的版本,“1”对应于快速Leader选举基于UDP的无身份验证的版本,“2”对应于快速Leader选举有基于UDP的身份验证的版本,而“3”对应于快速Leader选举基于TCP的版本。目前默认值是算法3。
注意:Leader选举0,1,2这三种实现已经废弃,在接下来的版本中将会移除它们,这样就只剩下FastLeaderElection算法。
initLimit
没有对应的Java系统属性。
默认值是10,即tickTime属性值的10倍。它用于配置允许Followers连接并同步到Leader的最大时间。如果ZooKeeper管理的数据量很大的话可以增加这个值。
leaderServes
对应的Java系统属性:zookeeper.leaderServes。
用于配置Leader是否接受客户端连接,默认值是“yes”,即Leader将会接受客户端连接。在ZooKeeper中,Leader服务器主要协调事务更新请求。对于事务更新请求吞吐很高而读取请求吞吐很低的情况可以配置Leader不接受客户端连接,这样就可以专注于协调工作。
注意:当ZooKeeper集群中服务器的数量超过3个时,建议开启Leader选举。
server.x=[hostname]:nnnnn:nnnnn
没有对应的Java系统属性。
组成ZooKeeper集群的服务器。当服务器启动时,可以通过查找数据目录中的myid文件来决定它是哪一台服务器。myid文件包含服务器编号,并且它要匹配“server.x”中的x。
客户端用来组成ZooKeeper集群的服务器列表必须和每个ZooKeeper服务器中配置的ZooKeeper服务器列表相匹配。
有两个端口号nnnnn,第一个是Followers用来连接到Leader,第二个是用于Leader选举。如果想在单台机器上测试多个服务,则可以为每个服务配置不同的端口。
syncLimit
没有对应的Java系统属性。
默认值是5,即tickTime属性值的5倍。它用于配置Leader和Followers间进行心跳检测的最大延迟时间。如果在设置的时间内Followers无法与Leader进行通信,那么Followers将会被丢弃。
group.x=nnnnn[:nnnnn]
没有对应的Java系统属性。
Enables a hierarchical quorum construction.”x” 是一个组的标识,等号右边的数字对应于服务器的标识。赋值操作右边是冒号分隔的服务器标识。注意:组必须是不相交的,并且所有组联合后必须是 ZooKeeper 集群。
weight.x=nnnnn
没有对应的Java系统属性。
和“group”一起使用,当形成集群时它给每个服务器赋权重值。这个值对应于投票时服务器的权重。ZooKeeper中只有少数部分需要投票,比如Leader选举以及原子的广播协议。服务器权重的默认值是1。如果配置文件中定义了组,但是没有权重,那么所有服务器的权重将会赋值为1。
cnxTimeout
对应的Java系统属性:zookeeper.cnxTimeout。
用于配置Leader选举过程中,打开一次连接(选举的Server互相通信建立连接)的超时时间。默认值是5s。
五、身份认证和授权选项说明
本节的选项允许通过身份认证和授权来控制服务执行。
zookeeper.DigestAuthenticationProvider.superDigest
对应的Java系统属性:zookeeper.DigestAuthenticationProvider.superDigest。
该功能默认是禁用的。
能够使ZooKeeper集群管理员可以作为一个“super”用户来访问ZNode层级结构。特别是对于一个已经认证为超级管理员的用户不需要ACL检查。
org.apache.zookeeper.server.auth.DigestAuthenticationProvider可以用来生成superDigest,调用它带有“super:“参数的方法。当启动集群中的每台服务器时,将生成的“super:“作为系统属性提供。
当ZooKeeper客户端向ZooKeeper服务器进行身份认证时,会传递一个“digest”和“super:“的认证数据。注意摘要式身份验证将认证数据以普通文本的形式传递给服务器,在网络中需要谨慎使用该认证方法,要么只在本机上或通过一个加密的连接。
六、实验性选项/特性说明
本节列举了一些目前还处于实验阶段的新特性。
服务器只读模式
对应的Java系统属性:readonlymode.enabled。
将其设置为true将会启用服务器只读模式支持,默认是禁用的。ROM允许请求了ROM支持的客户端会话连接到服务器,即使当服务器可能已经从集群中分隔出去。在该模式中,ROM客户端仍然可以从ZK服务中读取值,但是不能进行写操作以及看见其它客户端所做的一些变更。更多详细信息可以参见ZOOKEEPER-784获取更多详细信息。
不安全的选项
下面的选项会很有用,但是使用的时候需要特别小心。
forceSync
对应的Java系统属性:zookeeper.forceSync。
用于配置是否需要在事务日志提交的时候调用FileChannel.force来保证数据完全同步到磁盘。默认值是“yes”。如果该选项设置为“no”,ZooKeeper将不会强制同步事务更新日志到磁盘。
jute.maxbuffer
对应的Java系统属性:jute.maxbuffer。没有zookeeper前缀。
用于指定一个ZNode中可以存储数据量的最大值,默认值是0xfffff,或1M内。如果这个选项改变了,那么该系统属性必须在所有的服务端和客户端进行设置,否则会出现问题。ZooKeeper旨在存储大小为千字节数量的数据。
skipACL
对应的Java系统属性:zookeeper.skipACL。
用于配置ZooKeeper服务器跳过ACL权限检查。这将一定程度的提高服务器吞吐量,但是也向所有客户端完全开放数据访问。
quorumListenOnAllIPs
当设置为true时,ZooKeeper服务器将会在所有可用的IP地址上监听来自其对等点的连接请求,而不仅是配置文件的服务器列表中配置的地址。它会影响处理ZAB协议和Fast Leader Election协议的连接。默认值是false。
七、ZooKeeper优化建议
1、将ZooKeeper与其他应用分开部署,避免相互影响;
对于ZooKeeper来说,如果在运行过程中,需要和其它应用程序来竞争磁盘、CPU、网络、内存资源,那么整体性能将会大打折扣。我们在使用ZooKeeper初期尝试将ZooKeeper与其他应用公用机器,在系统流量上涨后,由于IO及CPU被其他应用使用很大,造成ZooKeeper的Session经常超时甚至应用与ZooKeeper的连接断开。因此,建议ZooKeeper与其他应用分开部署;
2、将数据文件和事务日志分开存放,提高ZooKeeper性能;
我们先分析一下磁盘对ZooKeeper性能的影响。客户端对ZK的更新操作都是永久的,不可回退的。为做到这点,ZK会将每次更新操作以事务日志的形式写入磁盘,写入成功后才会给予客户端响应。明白这点之后,你就会明白磁盘的吞吐性能对于ZK的影响了,磁盘写入速度制约着ZK每个更新操作的响应。因此,我们在选择机型时尽量选择多块硬盘的机器,ZK的事务日志输出是一个顺序写文件的过程,本身性能是很高的,所以尽量保证不要和其它随机写的应用程序共享一块磁盘,尽量避免对磁盘的竞争。
3、尽量避免内存与磁盘空间的交换,确保设置一个合理的JVM堆大小;
如果设置太大,会让内存与磁盘进行交换,这将使ZK的性能大打折扣。例如一个4G内存的机器的,如果你把JVM的堆大小设置为4G或更大,那么会使频繁发生内存与磁盘空间的交换,通常设置成3G就可以了。
八、启动内存设置实例
新建zookeeper/conf/java.env文件。
java.env文件内容如下:
#!/bin/sh export JAVA_HOME=/usr/java/jdk # heap size MUST be modified according to cluster environment export JVMFLAGS=”-Xms512m -Xmx1024m $JVMFLAGS”
对于内存的分配,还是根据项目和机器情况而定。如果内存够用,适当的大点可以提升ZK性能。
ZooKeeper配置文件修改如下:
maxClientCnxns=1000 minSessionTimeout=30000 maxSessionTimeout=60000
九、日志优化实例
log4j配置,由于ZK是通过nohup启动的,会有一个zookeeper.out日志文件,该文件中记录的是输出到console的日志。log4j中只要配置输出到console即可,zookeeper.out日积月累会不断变大,要放在容量大的磁盘上。
修改配置文件(zoo.cfg)如下:
zookeeper.root.logger=INFO, CONSOLE zookeeper.console.threshold=INFO log4j.rootLogger=${zookeeper.root.logger} log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold} log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
zoo.cfg文件中,dataDir是存放快照数据的,dataLogDir是存放写前日志的。这两个目录不要配置成一个路径,要配置到不同的磁盘上。如果磁盘是使用了RAID,系统就一块磁盘,那配置到一块磁盘上也可以。写前日志的部分对写请求的性能影响很大,保证dataLogDir所在磁盘性能良好。
十、其它优化配置实例
1、zoo.cfg文件中skipACL=yes,忽略ACL验证,可以减少权限验证的相关操作,提升一点性能。
2、zoo.cfg文件中forceSync=no,这个对写请求的性能提升很有帮助,是指每次写请求的数据都要从pagecache中固化到磁盘上,才算是写成功返回。当写请求数量到达一定程度的时候,后续写请求会等待前面写请求的forceSync操作,造成一定延时。如果追求低延时的写请求,配置forceSync=no,数据写到pagecache后就返回。但是机器断电的时候,pagecache中的数据有可能丢失。
3、zk的dataDir和dataLogDir路径下,如果没有配置ZK自动清理,会不断的新增数据文件。可配置成ZK系统自动清理数据文件,但是最求系统最高性能的话,建议人工手动清理文件:
zkCleanup.sh -n 3
这样保留三份文件。
4、配置fsync.warningthresholdms=20,单位是毫秒,在forceSync=yes的时候,如果数据固化到磁盘的操作fsync超过20ms的时候,将会在zookeeper.out中输出一条warn日志。这个目前zk的3.4.5和3.5版本有bug,在zoo.cfg中配置不生效。我的做法是在conf/java.env中添加java系统属性:
export JVMFLAGS="-Dfsync.warningthresholdms=20 $JVMFLAGS"
参考:
http://www.chinacloud.cn/upload/2014-04/14042009468555.pdf
http://blog.csdn.net/u013673976/article/details/50153631
http://zlfwmm.blog.51cto.com/5892198/1710111
http://www.52yunwei.net/767.html(以上部分内容转自此篇文章)
http://www.cnblogs.com/fanweiwei/p/4517012.html(以上内容部分转自此篇博客)