CentOS7中zookeeper集群服务的安装
Zookeeper集群搭建
ZooKeeper是一个开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。
- 最终一致性:client不论连接到那个Server,展示给它的都是同一个视图。
- 可靠性:具有简单、健壮、良好的性能、如果消息m被到一台服务器接收,那么消息m将被所有服务器接收。
- 实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
- 等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。
- 原子性:更新只能成功或者失败,没有中间状态。
- 顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。
Zookeeper工作原理
在zookeeper的集群中,各个节点共有下面3种角色和4种状态:
角色:leader,follower,observer
状态:leading,following,observing,looking
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议(ZooKeeper Atomic Broadcast protocol)。Zab协议有两种模式,它们分别是恢复模式(Recovery选主)和广播模式(Broadcast同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
每个Server在工作过程中有4种状态:
LOOKING:当前Server不知道leader是谁,正在搜寻。
LEADING:当前Server即为选举出来的leader。
FOLLOWING:leader已经选举出来,当前Server与之同步。
OBSERVING:observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。
- Zookeeper节点部署越多,服务的可靠性越高,建议部署奇数个节点,因为zookeeper集群是以宕机个数过半才会让整个集群宕机的。
- 需要给每个zookeeper 1G左右的内存,如果可能的话,最好有独立的磁盘,因为独立磁盘可以确保zookeeper是高性能的。如果你的集群负载很重,不要把zookeeper和RegionServer运行在同一台机器上面,就像DataNodes和TaskTrackers一样。
实验环境:
| 主机名 | 系统 | IP地址 |
| ZFVM-APP-0-150 | CentOS Linux release 7.0.1406 (Core) | 192.168.0.150 |
| ZFVM-APP-0-151 | CentOS Linux release 7.0.1406 (Core) | 192.168.0.151 |
| ZFVM-APP-0-152 | CentOS Linux release 7.0.1406 (Core) | 192.168.0.152 |
二、Zookeeper安装
Zookeeper运行需要java环境,需要安装jdk,注:每台服务器上面都需要安装zookeeper、jdk,建议本地下载好需要的安装包然后上传到服务器上面,服务器上面下载速度太慢。
JDK下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html
这里以下载好的jdk-1.8为例,jdk-8u60-linux-x64.tar.gz
# mv jdk-8u60-linux-x64.tar.gz /usr/src/ # mkdir -p /data/local/java # cd /usr/src/ # tar zxvf jdk-8u60-linux-x64.tar.gz -C /data/local/java/
更改环境变量
# vim /etc/profile JAVA_HOME=/data/local/java/jdk1.8.0_60 JRE_HOME=/data/local/java/jdk1.8.0_60/jre PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin CLASSPATH=.:$PATH:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_JRE/lib/rt.jar:$JAVA_HOME/lib export JAVA_HOME JRE_HOME PATH CLASSPATH
# source /etc/profile
2.2、Zookeeper安装
Zookeeper下载链接地址:https://archive.apache.org/dist/zookeeper/,官网:http://zookeeper.apache.org/
这里以下载好的zookeeper-3.4.11.tar.gz为例
# tar zxvf zookeeper-3.4.11.tar.gz -C /data/local/ # cd /data/local/zookeeper-3.4.11/conf # cp zoo_sample.cfg zoo.cfg # mv zoo_sample.cfg zoo_sample.cfg.bak 配置环境变量
# vim /etc/profile JAVA_HOME=/data/local/java/jdk1.8.0_60 JRE_HOME=/data/local/java/jdk1.8.0_60/jre ZOOKEEPER_HOME=/data/local/zookeeper-3.4.11 PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin:$ZOOKEEPER_HOME/bin CLASSPATH=.:$PATH:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_JRE/lib/rt.jar:$JAVA_HOME/lib export JAVA_HOME JRE_HOME PATH CLASSPATH
# source /etc/profile
三、Zookeeper集群配置
注意:搭建zookeeper集群时,一定要先停止已经启动的zookeeper节点。
#修改过后的配置文件zoo.cfg,如下:
# cat zoo.cfg
tickTime=2000 initLimit=10 syncLimit=5 dataLogDir=/data/local/zookeeper-3.4.11/logs dataDir=/data/local/zookeeper-3.4.11/data clientPort=2181 autopurge.snapRetainCount=500 autopurge.purgeInterval=24 server.1=192.168.0.150:2888:3888 server.2=192.168.0.151:2888:3888 server.3=192.168.0.152:2888:3888
创建相关目录,三台节点都需要
# mkdir -p /opt/zookeeper/{logs,data}
#其余zookeeper节点安装完成之后,同步配置文件zoo.cfg。
tickTime这个时间是作为zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是说每个tickTime时间就会发送一个心跳。
initLimit这个配置项是用来配置zookeeper接受客户端(这里所说的客户端不是用户连接zookeeper服务器的客户端,而是zookeeper服务器集群中连接到leader的follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。
当已经超过10个心跳的时间(也就是tickTime)长度后 zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20秒。
syncLimit这个配置项标识leader与follower之间发送消息,请求和应答时间长度,最长不能超过多少个tickTime的时间长度,总的时间长度就是5*2000=10秒。
dataDir顾名思义就是zookeeper保存数据的目录,默认情况下zookeeper将写数据的日志文件也保存在这个目录里;
clientPort这个端口就是客户端连接Zookeeper服务器的端口,Zookeeper会监听这个端口接受客户端的访问请求;
server.A=B:C:D中的A是一个数字,表示这个是第几号服务器,B是这个服务器的IP地址,C第一个端口用来集群成员的信息交换,表示这个服务器与集群中的leader服务器交换信息的端口,D是在leader挂掉时专门用来进行选举leader所用的端口。
除了修改zoo.cfg配置文件外,zookeeper集群模式下还要配置一个myid文件,这个文件需要放在dataDir目录下。
这个文件里面有一个数据就是A的值(该A就是zoo.cfg文件中server.A=B:C:D中的A),在zoo.cfg文件中配置的dataDir路径中创建myid文件。
#在192.168.0.150服务器上面创建myid文件,并设置值为1,同时与zoo.cfg文件里面的server.1保持一致,如下
# echo "1" > /data/local/zookeeper-3.4.11/data/myid
#在192.168.0.151服务器上面创建myid文件,并设置值为2,同时与zoo.cfg文件里面的server.2保持一致,如下
# echo "2" > /data/local/zookeeper-3.4.11/data/myid
#在192.168.0.152服务器上面创建myid文件,并设置值为3,同时与zoo.cfg文件里面的server.3保持一致,如下
# echo "3" > /data/local/zookeeper-3.4.11/data/myid
到此,相关配置已完成
四、Zookeeper集群查看
# /data/local/zookeeper-3.4.11/bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /data/local/zookeeper-3.4.11/bin/../conf/zoo.cfg Starting zookeeper ... STARTED # /data/local/zookeeper-3.4.11/bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /data/local/zookeeper-3.4.11/bin/../conf/zoo.cfg Mode: follower
2、启动完成之后查看每个节点的状态



从上面可以看出:192.168.0.150/151两台服务器zookeeper的状态是follow模式,192.168.0.152这台服务器zookeeper的状态是leader模式。 Zookeeper集群搭建完毕之后,可以通过客户端脚本连接到zookeeper集群上面,对客户端来说,zookeeper集群是一个整体,连接到zookeeper集群实际上感觉在独享整个集群Zookeeper原理:
http://blog.csdn.net/wuliu_forever/article/details/52053557
http://www.cnblogs.com/luxiaoxun/p/4887452.html
伪集群模式
伪集群模式就是在单机环境下模拟集群的Zookeeper服务。
在zookeeper集群配置文件中,clientPort参数用来设置客户端连接zookeeper服务器的端口。server.1=IP1:2888:3888中,IP1指的是组成Zookeeper服务器的IP地址,2888为组成zookeeper服务器之间的通信端口,3888为用来选举leader的端口。由于伪集群模式中,我们使用的是同一台服务器,也就是说,需要在单台机器上运行多个zookeeper实例,所以我们必须要保证多个zookeeper实例的配置文件的client端口不能冲突。
下面简单介绍一下如何在单台机器上建立伪集群模式。首先将zookeeper-3.4.9.tar.gz分别解压到server1,server2,server3目录下:
# tar -zxvf zookeeper-3.4.9.tar.gz /home/jxwch/server1 # tar -zxvf zookeeper-3.4.9.tar.gz /home/jxwch/server2 # tar -zxvf zookeeper-3.4.9.tar.gz /home/jxwch/server3
然后在server1/data/目录下创建文件myid文件并写入“1”,同样在server2/data/,目录下创建文件myid并写入“2”,server3进行同样的操作。
# mkdir server1/{data,logs} # mkdir server2/{data,logs} # mkdir server3/{data,logs} # echo "1" > server1/data/myid # echo "2" > server2/data/myid # echo "3" > server3/data/myid
下面分别展示在server1/conf/、server2/conf/、server3/conf/目录下的zoo.cfg文件:
server1/conf/zoo.cfg文件
# vim conf/zoo.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/jxwch/server1/data dataLogDir=/home/jxwch/server1/data/logs clientPort=2181 server.1= 127.0.0.1:2888:3888 server.2= 127.0.0.1:2889:3889 server.3= 127.0.0.1:2890:3890
以下是解释其中的含义的
# Server 1 # The number of milliseconds of each tick # 服务器与客户端之间交互的基本时间单元(ms) tickTime=2000 # The number of ticks that the initial # synchronization phase can take # 此配置表示允许follower连接并同步到leader的初始化时间,它以tickTime的倍数来表示。当超过设置倍数的tickTime时间,则连接失败。 initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement # Leader服务器与follower服务器之间信息同步允许的最大时间间隔,如果超过次间隔,默认follower服务器与leader服务器之间断开链接 syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. # 保存zookeeper数据,日志路径 dataDir=/home/jxwch/server1/data dataLogDir=/home/jxwch/server1/data/logs # the port at which the clients will connect # 客户端与zookeeper相互交互的端口 clientPort=2181 server.1= 127.0.0.1:2888:3888 server.2= 127.0.0.1:2889:3889 server.3= 127.0.0.1:2890:3890 #server.A=B:C:D 其中A是一个数字,代表这是第几号服务器;B是服务器的IP地址;C表示服务器与群集中的“领导者”交换信息的端口;当领导者失效后,D表示用来执行选举时服务器相互通信的端口。 # the maximum number of client connections. # increase this if you need to handle more clients # 限制连接到zookeeper服务器客户端的数量 maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
server2/conf/zoo.cfg文件,server3/conf/zoo.cfg文件依据上面所示类推。
从上述三个代码清单可以发现,除了clientPort不同之外,dataDir和dataLogDir也不同。另外,不要忘记dataDir所对应的目录中创建的myid文件来指定对应的zookeeper服务器实例。
Zookeeper伪集群模式运行
当上述伪集群环境安装成功后就可以测试是否安装成功啦,我们可以尝尝鲜:
首先启动server1服务,其次启动server2,server3服务:
# cd server1/bin # sh zkServer.sh start ZooKeeper JMX enabled by default Using config: /data/local/zookeeper-3.4.11/zk3/bin/../conf/zoo.cfg Starting zookeeper ... STARTED # sh zkServer.sh status ZooKeeper JMX enabled by default Using config: /data/local/zookeeper-3.4.11/zk3/bin/../conf/zoo.cfg Mode: follower
打开zookeeper.out文件:
2017-02-23 16:17:46,419 [myid:] - INFO [main:QuorumPeerConfig@124] - Reading configuration from: /home/jxwch/server1/bin/../conf/zoo.cfg 2017-02-23 16:17:46,496 [myid:] - INFO [main:QuorumPeer$QuorumServer@149] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1 2017-02-23 16:17:46,496 [myid:] - INFO [main:QuorumPeer$QuorumServer@149] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1 2017-02-23 16:17:46,497 [myid:] - INFO [main:QuorumPeer$QuorumServer@149] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1 2017-02-23 16:17:46,497 [myid:] - INFO [main:QuorumPeerConfig@352] - Defaulting to majority quorums 2017-02-23 16:17:46,511 [myid:1] - INFO [main:DatadirCleanupManager@78] - autopurge.snapRetainCount set to 3 2017-02-23 16:17:46,511 [myid:1] - INFO [main:DatadirCleanupManager@79] - autopurge.purgeInterval set to 0 2017-02-23 16:17:46,511 [myid:1] - INFO [main:DatadirCleanupManager@101] - Purge task is not scheduled. 2017-02-23 16:17:46,525 [myid:1] - INFO [main:QuorumPeerMain@127] - Starting quorum peer 2017-02-23 16:17:46,631 [myid:1] - INFO [main:NIOServerCnxnFactory@89] - binding to port 0.0.0.0/0.0.0.0:2181 2017-02-23 16:17:46,664 [myid:1] - INFO [main:QuorumPeer@1019] - tickTime set to 2000 2017-02-23 16:17:46,664 [myid:1] - INFO [main:QuorumPeer@1039] - minSessionTimeout set to -1 2017-02-23 16:17:46,664 [myid:1] - INFO [main:QuorumPeer@1050] - maxSessionTimeout set to -1 2017-02-23 16:17:46,665 [myid:1] - INFO [main:QuorumPeer@1065] - initLimit set to 10 2017-02-23 16:17:46,771 [myid:1] - INFO [main:FileSnap@83] - Reading snapshot /home/jxwch/server1/data/version-2/snapshot.400000015 2017-02-23 16:17:46,897 [myid:1] - INFO [ListenerThread:QuorumCnxManager$Listener@534] - My election bind port: /127.0.0.1:3888 2017-02-23 16:17:46,913 [myid:1] - INFO [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:QuorumPeer@774] - LOOKING 2017-02-23 16:17:46,915 [myid:1] - INFO [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:FastLeaderElection@818] - New election. My id = 1, proposed zxid=0x500000026 2017-02-23 16:17:46,922 [myid:1] - INFO [WorkerReceiver[myid=1]:FastLeaderElection@600] - Notification: 1 (message format version), 1 (n.leader), 0x500000026 (n.zxid), 0x1 (n.round), LOOKING (n.state), 1 (n.sid), 0x5 (n.peerEpoch) LOOKING (my state) 2017-02-23 16:17:46,940 [myid:1] - WARN [WorkerSender[myid=1]:QuorumCnxManager@400] - Cannot open channel to 2 at election address /127.0.0.1:3889 java.net.ConnectException: 拒绝连接 at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:579) at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:381) at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:354) at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:452) at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:433) at java.lang.Thread.run(Thread.java:745) 2017-02-23 16:17:46,943 [myid:1] - INFO [WorkerSender[myid=1]:QuorumPeer$QuorumServer@149] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1 2017-02-23 16:17:46,944 [myid:1] - WARN [WorkerSender[myid=1]:QuorumCnxManager@400] - Cannot open channel to 3 at election address /127.0.0.1:3890 java.net.ConnectException: 拒绝连接 at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:579) at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:381) at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:354) at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:452) at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:433) at java.lang.Thread.run(Thread.java:745) 2017-02-23 16:17:46,944 [myid:1] - INFO [WorkerSender[myid=1]:QuorumPeer$QuorumServer@149] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1
产生上述两条Waring信息是因为zookeeper服务的每个实例都拥有全局的配置信息,他们在启动的时候需要随时随地的进行leader选举,此时server1就需要和其他两个zookeeper实例进行通信,但是,另外两个zookeeper实例还没有启动起来,因此将会产生上述所示的提示信息。当我们用同样的方式启动server2和server3后就不会再有这样的警告信息了。
当三台服务器均成功启动后切换至server1/bin/目录下执行以下命令
# sh zkServer.sh status



说明server1被选为leader

浙公网安备 33010602011771号