参考
过程
从github clone到本地
git clone https://github.com/apache/zookeeper.git
commit的版本是:ae7f72d31e4dc9c6e307b1c14271e74950b022dc
idea maven导入,然后mvn compile一把
增加必要的配置
在conf文件夹里加入配置: zoo1.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/z1/data # 创建好data目录
dataLogDir=/tmp/zookeeper/z1/log # 定义好日志文件
clientPort=2181
将log4j.properties复制到我们要用的server文件夹里:
github/zookeeper/zookeeper-server/src/main/resources/log4j.properties
然后配置好启动server:
debug方式启动server。
我遇到的坑
log4j jar包找不到
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at org.apache.zookeeper.server.quorum.QuorumPeerMain.<clinit>(QuorumPeerMain.java:76)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
如果遇到找不到log4j的情况,是因为没有真正把log4j相关的jar包引入到
classpath里。可以通过配置 java -cp xxx.jar 引入
找不到log4j.properties
log4j:WARN No appenders could be found for logger (org.apache.zookeeper.server.quorum.QuorumPeerConfig).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
是因为idea没有将github/zookeeper/zookeeper-server/src/main/resources
这个文件夹标志为resources文件夹,所以拷贝进去了也没用。idea里右键标记一把。
同理配置好启动client:
成功运行
成功了!折腾了半天终于搞定!
集群模式
将conf里的zoo1.cfg 分别拷贝出zoo2.cfg和zoo3.cfg;同时要给每个节点创建一个myid文件,填入当前server的id
zoo1.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/z1/data
dataLogDir=/tmp/zookeeper/z1/log
clientPort=2181
server.1=127.0.0.1:2887:3887
server.2=127.0.0.1:2888:3888
server.3=127.0.0.1:2889:3889
mkdir -p /tmp/zookeeper/z1/data
echo 1 > /tmp/zookeeper/z1/data/myid
zoo2.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/z2/data
dataLogDir=/tmp/zookeeper/z2/log
clientPort=2182
server.1=127.0.0.1:2887:3887
server.2=127.0.0.1:2888:3888
server.3=127.0.0.1:2889:3889
mkdir -p /tmp/zookeeper/z2/data
echo 2 > /tmp/zookeeper/z2/data/myid
zoo3.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/z3/data
dataLogDir=/tmp/zookeeper/z3/log
clientPort=2183
server.1=127.0.0.1:2887:3887
server.2=127.0.0.1:2888:3888
server.3=127.0.0.1:2889:3889
mkdir -p /tmp/zookeeper/z3/data
echo 3 > /tmp/zookeeper/z3/data/myid
分别在idea里配置不同的application里的命令行参数,然后运行
那就可以看到验证了我们理论上的:
顺序启动,中间server是leader
选举流程是:
1、server1启动,投票给自己,发送选票给其他小伙伴,其他小伙伴没有反应,只好不断重试
2、server2启动,投票给自己,收到了server1的自荐选票,发现server1并没有自己牛皮(排序规则:epoch>zxid>serverid,server2赢在了serverid),于是发送投自己的选票给其他小伙伴
2020-05-12 17:00:48,122 [myid:2] - INFO [WorkerReceiver[myid=2]:FastLeaderElection$Messenger$WorkerReceiver@389] - Notification: my state:LOOKING; n.sid:1, n.state:LOOKING, n.leader:1, n.round:0x1, n.peerEpoch:0x0, n.zxid:0x0, message format version:0x2, n.config version:0x0
2020-05-12 17:00:48,124 [myid:2] - INFO [WorkerReceiver[myid=2]:FastLeaderElection$Messenger$WorkerReceiver@389] - Notification: my state:LOOKING; n.sid:1, n.state:LOOKING, n.leader:2, n.round:0x1, n.peerEpoch:0x0, n.zxid:0x0, message format version:0x2, n.config version:0x0
2020-05-12 17:00:48,326 [myid:2] - INFO [QuorumPeer[myid=2](plain=[0:0:0:0:0:0:0:0]:2182)(secure=disabled):QuorumPeer@857] - Peer state changed: leading
3、server1收到了server2的自荐,发现自己确实没server1牛皮,于是乖乖改自己选票也选server1
4、达到了quorum条件,server1和server2都知道谁是老大了,于是server2成功当了老大,LEADING,server1乖乖FOLLOWING
5、那么server3再启动的时候是怎样的呢?
如日志所示,server3启动的时候,会给server1和server2广播,要选自己当老大;server1和server2都已经选好了当然不答应:
代码:
server1和server2收到server3的选票,一看兄弟你这epoch跟不上潮流,就把最新的选票发给server3了,于是server3可以收到来自server1和server2的选票,就知道自己不是当老大的料
然后就灰溜溜的改成FOLLOWING了。
通过debug模式再确认下,server1和3用run的,server2用debug
断点打在上面的代码
server3启动之后,server2果然在上面断点了,server2果然收到了server3自荐的选票
THE END
环境搭好了以后可以看下写请求的细节了,美滋滋。