Zookeeper仲裁模式

目标

  1. 在一台机器上配置三个Zookeeper服务。
  2. 启动服务并选出群首(Leader)
  3. 测试当有一个服务丢失时,客户端可以自动连接到其它服务上

 

配置说明

目录结构

  • /zookeeper
  • /z1/z1.cfg
  • /z1/data/myid
  • /z2/z2.cfg
  • /z2/data/myid
  • /z3/z3.cfg
  • /z3/data/myid

/zookeeper

Zookeeper的程序

/z1/z1.cfg

第一台服务器的配置文件

tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2181
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445
  • dataDir:是配置这个服务的数据文件存在哪个目录
  • clientPort:是给客户端用的
  • server.X:是配置这组集群都有哪些服务器(包含自己这台)
    • 第一段127.0.0.1:是集群服务器的IP,如果是局域网内其他机器上要配置成192.168.x.x或172.18.x.x等
    • 第二段2222:是用于仲裁通信的接口(暂时还不明是干什么的),对应服务启动时会开启这个端口,如果是在一台机器上启动多个服务,必须设成不同的端口
    • 第三段2223:是用户选举群首的接口

/z1/data/myid

这个文件用来标识是第几台服务器

1

里面只有一个1说明这个服务对应的是/z1/z1.cfg中的server.1,将开启2181,2222,2223这三个端口。

/data这个目录也是在/z1/z1.cfgdataDir配置的。

启动Zookeeper的时候应该会根据dataDir找到myid这个文件

/z2/z2.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2182
server.1=127.0.0.1:2222:2223
server.2=127.0.0.1:3333:3334
server.3=127.0.0.1:4444:4445

/z1/z1.cfg基本一致,只是clientPort改为了2182,因为同一台机器启动多个服务不能占用同一个端口。

启动服务时将开启2182,3333,3334端口

/z2/data/myid

2

功能和/z1/data/myid一样,只是内容改为了2用来标识是第二个服务器

/z3/z3.cfg 和 /z3/data/myid

和z2一样,只是换掉了对应的端口和服务器id

启动服务

只启动一个服务

cd ./z1
../zookeeper/bin/zkServer.sh start-foreground ./z1.cfg

进入./z1目录启动zookeeper服务,因为配置文件里写的dataDir=./data,会基于运行命令时的路径找data目录,所以需要先进入z1后再执行启动命令,如果dataDir配置的是系统的绝对路径,则没有这个问题。

为了方便查看日志,使用了start-foreground,以前台方式启动服务。正常情况下可以直接使用start后台启动,日志会生成到同目录下的zookeeper.out中。

./z1.cfg是选用的配置文件,比如这里,他会开启2181端口,然后找到./data/myid,发现自己是1号服务器,然后再根据server.1的设置再开启22222223端口。同时会去尝试链接server.2server.3

启动后会一直抛出这样的错误:

2018-01-04 11:52:01,382 [myid:1] - WARN  [WorkerSender[myid=1]:[email protected]] - Cannot open channel to 2 at election address /127.0.0.1:3334
java.net.ConnectException: Connection refused (Connection refused)
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:400)
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:243)
	at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:225)
	at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:402)
	at java.base/java.net.Socket.connect(Socket.java:591)
	at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:558)
	at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:534)
	at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:454)
	at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:435)
	at java.base/java.lang.Thread.run(Thread.java:844)
2018-01-04 11:52:01,385 [myid:1] - INFO  [WorkerSender[myid=1]:[email protected]] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1
2018-01-04 11:52:01,387 [myid:1] - WARN  [WorkerSender[myid=1]:[email protected]] - Cannot open channel to 3 at election address /127.0.0.1:4445
java.net.ConnectException: Connection refused (Connection refused)
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:400)
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:243)
	at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:225)
	at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:402)
	at java.base/java.net.Socket.connect(Socket.java:591)
	at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:558)
	at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:534)
	at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:454)
	at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:435)
	at java.base/java.lang.Thread.run(Thread.java:844)
2018-01-04 11:52:01,388 [myid:1] - INFO  [WorkerSender[myid=1]:[email protected]] - Resolved hostname: 127.0.0.1 to address: /127.0.0.1

这是因为现在只启动了一个服务,集群中配置了三个服务,要想达成选举,必须至少有两个存活的服务。这时,他会一直尝试连接另两个服务的选举端口33344445

启动第二个服务

cd ./z2
../zookeeper/bin/zkServer.sh start-foreground ./z2.cfg

启动第二个服务后,达成了选举条件。

其中一个服务会输出这样的信息:说明已经选举出自己为群首。

2018-01-04 11:52:59,961 [myid:2] - INFO  [QuorumPeer[myid=2]/0:0:0:0:0:0:0:0:2182:[email protected]] - LEADING - LEADER ELECTION TOOK - 2312

其它服务会出现这样的信息:说明已经选举出群首,但不是自己,自己需要追随群首

2018-01-04 11:52:59,960 [myid:1] - INFO  [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:[email protected]] - FOLLOWING - LEADER ELECTION TOOK - 58587

现在已达成目标2,选举出群首,为了达成目标3:”测试当有一个服务丢失时,客户端可以自动连接到其它服务上”, 先不启动第三个服务。

 

客户端连接服务

./zookeeper/bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

客户端连接的时候需要指定需要使用集群中的哪些服务,目前将所有的服务都填进去。

因为是随机连接到某个服务,如果集群是跨机房的,可以只选择离自己近一些快一些的服务,但也有可能点儿背选的服务全挂了而其它服务都是好的。

成功连接后会出现这样的信息:

2018-01-04 12:00:30,748 [myid:] - INFO  [main-SendThread(127.0.0.1:2182):[email protected]] - Socket connection established to 127.0.0.1/127.0.0.1:2182, initiating session

说明已经成功连接到了server.2(127.0.0.1:2182)。

quitControl+C关掉客户端连接,反复重试几次,有可能出现这样的信息:

2018-01-04 12:00:35,228 [myid:] - INFO  [main-SendThread(127.0.0.1:2183):[email protected]] - Opening socket connection to server 127.0.0.1/127.0.0.1:2183. Will not attempt to authenticate using SASL (unknown error)
2018-01-04 12:00:35,247 [myid:] - WARN  [main-SendThread(127.0.0.1:2183):[email protected]] - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused
	at java.base/sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
	at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
	at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361)
	at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1144)
JLine support is enabled
[zk: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183(CONNECTING) 0] 2018-01-04 12:00:35,357 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):[email protected]] - Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
2018-01-04 12:00:35,359 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):[email protected]] - Socket connection established to 127.0.0.1/127.0.0.1:2181, initiating session
2018-01-04 12:00:35,406 [myid:] - INFO  [main-SendThread(127.0.0.1:2181):[email protected]] - Session establishment complete on server 127.0.0.1/127.0.0.1:2181, sessionid = 0x100081e1ee00001, negotiated timeout = 30000

说明客户端在尝试连接server.3(127.0.0.1:2183)的时候失败了,重新连接了另一台服务器server.1(127.0.0.1:2181)。