首先简单介绍一下zookeeper
zookeeper的重要概念
- znode
zookeeper在使用时不直接暴露原语,使用的时由一小部分调用方法组成的类似树状文件系统的API,以便我们实现自己的原语,增加使用的灵活性。而由我们自己维护的这个文件系统的每一个数据节点称为znode。其中znode可以分为两种节点,临时节点和持久节点,他们的区别是,持久节点只能通过delete的操作删除,而临时节点当客户端失去与zookeeper的连接时便会被删除,当然临时节点也可以被delete操作删除。zookeeper暴露了六个API供我们维护这个文件系统,create、delete、exists、setData、getData、getChildren。 - 版本
zookeeper为了管理集群服务,在每个znode上面都会设置一个版本号,类似于SVN的管理,当一个znode被创建后,每次数据变化都会变更版本号,当多个客户端操作同一个znode的时候,会进行版本号对比,如果对不上版本时,操作便不会成功,就像SVN同一个版本check下来的项目,别人先commit了,自己就commit不了了。 - 会话
客户端与服务端建立的TCP长连接,这个会话能够进行心跳检测、Watch事件、发送请求、接收响应等多个工作,而且每个会话都有各自的SessionID,全局唯一。 - 监视器
zookeeper分布式很重要的特性,通过注册和通知实现分布式协调服务。 - ACL
与Linux的文件系统ACL权限控制相似,zookeeper可以对每个节点进行ACL权限控制 - zookeeper仲裁
在集群模式下,每个客户端发起的请求会同步到各个机器节点上,然后再返回信息给客户端,但是如果在一个大集群中存在网络延迟、机器性能等问题时,要在同步到全部节点上显得处理时间太长,为解决这个问题就引出仲裁,而这个仲裁的基础是zookeeper判断集群健壮性的原则(n/2+1)。所谓仲裁,就是众人成虎,假设集群节点数为n,那么只要客户端的请求同步到n/2+1的节点上,就能保证这个请求在正常的集群状态下最终一定能同步到全部节点上。因此这个n/2+1既是健壮性原则,也是zookeeper仲裁法定人数的最小值。
举个例子:现在有5个节点,客户端向节点1发起了请求,节点1同步信息到节点2了,如果这时我们设定的法定人数为2,那么集群就会认为可以给客户端返回请求确认的信息了,然而在返回与客户端发起监听的过程中,1、2节点挂了,与客户端的连接也丢失了,这时3、4、5节点正常,正常节点大于n/2,所以zookeeper觉得集群正常,就继续工作,然而3、4、5节点还没来得及同步客户端的请求,那么客户端重新连接过来时,发起的监听请求就找不到要监听的节点了,这就造成了数据的丢失了。
zookeeper概述
- ZooKeeper 是一个开源的分布式协调服务,ZooKeeper框架最初是在“Yahoo!"上构建的,用于以简单而稳健的方式访问他们的应用程序。 后来,Apache ZooKeeper成为Hadoop,HBase和其他分布式框架使用的有组织服务的标准。
- ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
- Zookeeper 一个最常用的使用场景就是用于担任服务生产者和服务消费者的注册中心。 服务生产者将自己提供的服务注册到Zookeeper中心,服务的消费者在进行服务调用的时候先到Zookeeper中查找服务,获取到服务生产者的详细信息之后,再去调用服务生产者的内容与数据。
zookeeper特点
- zookeeper是一个用java编写的分布式程序。
- zookeeper将数据保存在内存中,这也就保证了数据的高吞吐量和低延迟。
- zookeeper的数据节点有临时和持久的类型。
- Zookeeper底层只提供了两个功能:1、管理(存储、读取)用户程序提交的数据;2、为用户程序提交数据节点监听服务。
zookeeper模式
zookeeper独立模式
只有一个单独的zookeeper服务器,zookeeper状态无法复制。zookeeper仲裁模式
具有一组zookeeper服务器,它们之间可以进行状态的复制和同时为客户端服务。
这里要明确的一点是,我们说的zookeeper服务器不是我们硬件意义上的一台服务器,而是该服务器上部署了一个zookeeper,就是说我们一台硬件意义上的服务器可以部署多个zookeeper,并且成功通讯,这样的模式也是仲裁模式。==
安装过程
- 下载zookeeper,地址 http://archive.apache.org/dist/zookeeper/
- 解压
# 新建一个zookeeper用户
cd /export/server
tar -xvzf apache-zookeeper-3.5.7.tar.gz
mv apache-zookeeper-3.5.7 zookeeper3.5.7
- 配置JDK环境变量
vi ~/.bash_profile,添加:
JAVA_HOME=/usr/java/jdk1.8.0_141”
PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin
Export PATH
source ~/.bash_profile
- 修改配置文件
cp /export/server/zookeeper3.5.7/conf/zoo_sample.cfg /export/server/zookeeper3.5.7/conf/zoo.cfg
配置文件参考下面即可
[root@server2 test]# vim /export/server/zookeeper3.5.7/conf/zoo.cfg | grep -v "#"
### 必要配置(没有默认值)
# 心跳检测时间,单位ms(毫秒),一般为3000毫秒,设置更低的值可以更早发现服务器超时问题
tickTime=2000
# 内存数据库保存的模糊快照目录,集群的id文件也需要再这个目录下
dataDir=/epxort/server/zookeeper3.5.7/data
# 事务日志目录
dataLogDir=/export/server/zookeeper3.5.7/log
#服务器建婷端口,客户端的连接会发到这个端口
clientPort=52181
# 四字命令白名单,为了方便监控,给出了这些命令权限
4lw.commands.whitelist=mntr,stat,cons,conf
## 集群配置
# follower连接到leader是的超时值,时间为10个ticktime,即20秒,因为连接过程中会做相当的数据同步,如果内存数据较大可以适当增加该值
initLimit=10
# follower与leader同步的超时值,时间为5个ticktime,即10秒,如果网络延迟较大或事务日志较多,可以适当增大该值
syncLimit=5
# 集群服务器配置参数,格式为server.x=ip:port1:port2[:observer],port1用于事务日志同步,port2用于leader选举,observer配置可以让服务器变成观察者模式,如需要使用观察者,需要在观察者服务器新增一行配置 peerType=observer
server.1=ip1:2222:2223
server.2=ip2:3333:3334
server.3=ip3:4444:4445
(上面ip1/2/3具体为对应集群主机的ip,集群中所有主机的ip都要配上去。配置文件支持主机名代替ip,但是需要配置好主机名和机器上主机名解析等配置,因此直接使用ip较为简单直观)
## 集群配置
### 必要配置(没有默认值)
### 可选配置(有默认值)
## 存储配置
# 预分配的事务日志文件大小,单位是KB,默认值为64MB,但是往往不会达到这么大,设置该值可基于snapCount值和平局事务大小情况而定,必要时增大该值。默认的preAllocSize适用于默认的snapCount值和平均事务超过512KB的情况。
preAllocSize=10240
# 每次快照之间的事务数,默认值是100000,因为进行快照时会影响性能,所以不应该设置太小。
# snapCount=100000
# 对快照和日志进行垃圾回收操作,单位是小时,默认值是0,0代表不会执行清理操作,现设置为20天清理一次,其实就是定时执行了zk的bin目录下的zkCleanup.sh脚本。
Autopurge.purgeInterval=480
# 执行清理操作时,保留的快照梳理和其对应的事务日志文件数量,默认是3,也是最小值,即保留3个文件
Autopurge.snapRetainCount=10
## 存储配置
## 扩展配置
# 如要禁用jetty程序,可使用这配置
# admin.enableServer=false
# jetty监听端口
admin.serverPort=58080
## 扩展配置
### 可选配置(有默认值)
#上面ip1/2/3具体为对应集群主机的ip,集群中所有主机的ip都要配上去。配置文件支持主机名代替ip,但是需要配置好主机名和机器上主机名解析等配置,因此直接使用ip较为简单直观
- 日志配置
vi /export/server/zookeeper3.5.7/conf/log4j.properties,修改以下配置:
zookeeper.root.logger=INFO, CONSOLE,ROLLINGFILE
zookeeper.log.dir=/export/server/zookeeper3.5.7/logs
log4j.appender.ROLLINGFILE=org.apache.log4j.DailyRollingFileAppender
以上过程3台服务器都要执行
- 创建myid
这个步骤需要分别在server1,server2,server3创建不同的id来区分集群的机器,而且这个id必须跟上面zoo.cfg中server.后面的数字对应。
server1: echo “1” > /export/server/zookeeper3.5.7/data/myid
Server2: echo “2” > /export/server/zookeeper3.5.7/data/myid
Server3: echo “3” > /export/server/zookeeper3.5.7/data/myid
- 启动
zookeeper提供两种启动方式:
1.zkServer.sh start-foreground(有启动日志显示,方便查看配置环境是否有错误)
2.zkServer.sh start(没有明显日志,成功或失败都不会显示,需要自行查看运行日志)
这里使用第二种方式。
建立启动脚本:
cd ~/bin/
vi start_zookeeper.sh,添加 :
cd /export/server/zookeeper3.5.7/bin
./zkServer.sh start
启动完成后
./zkServer.sh status 或者 echo stat | nc localhost 52181获取服务状态,确认是否启动成功。成功的话就可以看到集群的主从关系。(注意新版本3.4.10以后需要把需要用的四字命令加到配置文件白名单才可以使用四字命令,在zoo.cfg添加4lw.commands.whitelist=stat)
- 详细配置
参数 | 说明 |
---|---|
clientPort | 客户端连接server的端口,即对外服务端口,一般设置为2181吧。 |
dataDir | 存储快照文件snapshot的目录。默认情况下,事务日志也会存储在这里。建议同时配置参数dataLogDir, 事务日志的写性能直接影响zk性能。 |
tickTime | ZK中的一个时间单元。ZK中所有时间都是以这个时间单元为基础,进行整数倍配置的。例如,session的最小超时时间是2*tickTime。 |
dataLogDir | 事务日志输出目录。尽量给事务日志的输出配置单独的磁盘或是挂载点,这将极大的提升ZK性能。 |
globalOutstandingLimit | 最大请求堆积数。默认是1000。ZK运行的时候, 尽管server已经没有空闲来处理更多的客户端请求了,但是还是允许客户端将请求提交到服务器上来,以提高吞吐性能。当然,为了防止Server内存溢出,这个请求堆积数还是需要限制下的。 |
preAllocSize | 预先开辟磁盘空间,用于后续写入事务日志。默认是64M,每个事务日志大小就是64M。如果ZK的快照频率较大的话,建议适当减小这个参数。 |
snapCount | 每进行snapCount次事务日志输出后,触发一次快照(snapshot), 此时,ZK会生成一个snapshot.文件,同时创建一个新的事务日志文件log.。默认是100000.(真正的代码实现中,会进行一定的随机数处理,以避免所有服务器在同一时间进行快照而影响性能) |
traceFile | 用于记录所有请求的log,一般调试过程中可以使用,但是生产环境不建议使用,会严重影响性能。 |
maxClientCnxns | 单个客户端与单台服务器之间的连接数的限制,是ip级别的,默认是60,如果设置为0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端机器与单台ZK服务器之间的连接数限制,不是针对指定客户端IP,也不是ZK集群的连接数限制,也不是单台ZK对所有客户端的连接数限制。指定客户端IP的限制策略,这里有一个patch,可以尝试一下:http://rdc.taobao.com/team/jm/archives/1334 |
clientPortAddress | 对于多网卡的机器,可以为每个IP指定不同的监听端口。默认情况是所有IP都监听clientPort指定的端口。New in 3.3.0 |
minSessionTimeoutmaxSessionTimeout | Session超时时间限制,如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。默认的Session超时时间是在2 * tickTime ~ 20 * tickTime这个范围 New in 3.3.0 |
fsync.warningthresholdms | 事务日志输出时,如果调用fsync方法超过指定的超时时间,那么会在日志中输出警告信息。默认是1000ms。 |
autopurge.purgeInterval | 在上文中已经提到,3.4.0及之后版本,ZK提供了自动清理事务日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是0,表示不开启自动清理功能。 |
autopurge.snapRetainCount | 这个参数和上面的参数搭配使用,这个参数指定了需要保留的文件数目。默认是保留3个。 |
electionAlg | 在之前的版本中, 这个参数配置是允许我们选择leader选举算法,但是由于在以后的版本中,只会留下一种“TCP-based version of fast leader election”算法,所以这个参数目前看来没有用了,这里也不详细展开说了。 |
initLimit | Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader允许F在initLimit时间内完成这个工作。通常情况下,我们不用太在意这个参数的设置。如果ZK集群的数据量确实很大了,F在启动的时候,从Leader上同步数据的时间也会相应变长,因此在这种情况下,有必要适当调大这个参数了 |
syncLimit | 在运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。如果L发出心跳包在syncLimit之后,还没有从F那里收到响应,那么就认为这个F已经不在线了。注意:不要把这个参数设置得过大,否则可能会掩盖一些问题。 |
leaderServes | 默认情况下,Leader是会接受客户端连接,并提供正常的读写服务。但是,如果你想让Leader专注于集群中机器的协调,那么可以将这个参数设置为no,这样一来,会大大提高写操作的性能。 |
server.x=[hostname]:nnnnn[:nnnnn] | 这里的x是一个数字,与myid文件中的id是一致的。右边可以配置两个端口,第一个端口用于F和L之间的数据同步和其它通信,第二个端口用于Leader选举过程中投票通信。 |
group.x=nnnnn[:nnnnn]weight.x=nnnnn | 对机器分组和权重设置,可以 参见这里 |
cnxTimeout | Leader选举过程中,打开一次连接的超时时间,默认是5s。ZK权限设置相关,具体参见《使用super身份对有权限的节点进行操作》 和 《ZooKeeper权限控制》 |
skipACL | 对所有客户端请求都不作ACL检查。如果之前节点上设置有权限限制,一旦服务器上打开这个开头,那么也将失效。 |
forceSync | 这个参数确定了是否需要在事务日志提交的时候调用FileChannel.force来保证数据完全同步到磁盘。 |
jute.maxbuffer | 每个节点最大数据量,是默认是1M。这个限制必须在server和client端都进行设置才会生效。 |