首先将源码 clone 下来:
➜ gitee git clone https://github.com/apache/zookeeper.git
导入到 IDEA 中:
可以将 conf/zoo_sample.cfg 复制到自定义目录。这里直接拷贝到当前conf目录下,并命名为 zoo1.cfg:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/Users/dongguabai/Desktop/temp/zookeeper/z1/data dataLogDir=/Users/dongguabai/Desktop/temp/zookeeper/z1/log clientPort=2181
在 conf/log4j.properties
的日志配置拷贝一份到 zookeeper/zookeeper-server/src/main/resources
。这样才能打印出更多的日志提供调试。
注意还要将 zookeeper-server/src/main/resources 标记为资源目录,否则日志会不生效。
我们都知道,ZooKeeper 平时是使用 zkServer.sh
启动的。查看一下这个 shell 脚本:
start) echo -n "Starting zookeeper ... " if [ -f "$ZOOPIDFILE" ]; then if kill -0 `cat "$ZOOPIDFILE"` > /dev/null 2>&1; then echo $command already running as process `cat "$ZOOPIDFILE"`. exit 1 fi fi nohup "$JAVA" $ZOO_DATADIR_AUTOCREATE "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" \ "-Dzookeeper.log.file=${ZOO_LOG_FILE}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \ -XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='kill -9 %p' \ -cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN 这里标记着 ZOOMAIN 方法 "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null & ZOOMAIN ZOOCFG 为参数 .... ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only =$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain" 从此处可以知道,QuorumPeerMain 类就是 ZooKeeper Server 的启动类了。
从 shell 文件中看到,QuorumPeerMain
类就是 ZooKeeper Server 的启动类了。
配置启动参数:
zookeeper-jute 需要 mvn compile 生成,IDEA 可能不会自动导入,可以编译一些:
还可能会出现很多编译报错,直接 install 一下:
mvn clean install -DskipTests
还有的可能需要添加一些依赖:
编译问题处理后,直接 debug 走起:
可以发现已经启动成功了。
测试一波:
package dongguabai.zookeeper; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; import java.util.concurrent.CountDownLatch; /** * @author Dongguabai * @description * @date 2021-04-23 13:53 */ public class OriginalZkTest { //static final String CONNECT_ADDR = "172.16.140.131:2181,172.16.140.131:2181,172.16.140.131:2181"; static final String CONNECT_ADDR = "localhost:2181"; static final int SESSION_OUTTIME = 2000;//ms static final CountDownLatch connectedSemaphore = new CountDownLatch(1); public static void main(String[] args) throws Exception { ZooKeeper zk = new ZooKeeper(CONNECT_ADDR, SESSION_OUTTIME, new Watcher() { public void process(WatchedEvent event) { KeeperState keeperState = event.getState(); EventType eventType = event.getType(); if (KeeperState.SyncConnected == keeperState) { if (EventType.None == eventType) { connectedSemaphore.countDown(); System.out.println("zk connected"); } } } }); connectedSemaphore.await(); String s = zk.create("/testRoot1", "testRoot1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println(s); System.out.println("connected.."); zk.close(); } }
输出:
zk connected /testRoot1 connected..
查看节点是否创建了:
➜ bin sh zkServer.sh -server localhost:2181 [zk: localhost:2181(CONNECTED) 0] ls / [testRoot1, zookeeper]
可以发现单机版启动成功。
首先在之前的 conf 目录中增加3个配置文件,名字分别为zoo1.cfg
、zoo2.cfg
和zoo3.cfg:
zoo1.cfg:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/Users/dongguabai/Desktop/temp/zookeeper/z1/data dataLogDir=/Users/dongguabai/Desktop/temp/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
zoo2.cfg:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/Users/dongguabai/Desktop/temp/zookeeper/z2/data dataLogDir=/Users/dongguabai/Desktop/temp/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
zoo3.cfg:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/Users/dongguabai/Desktop/temp/zookeeper/z3/data dataLogDir=/Users/dongguabai/Desktop/temp/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
当然,相关的目录也要建好:
接下来配置 myid 文件,ZK 在集群模式下运行时会读取位于 dataDir
目录下的 myid
文件:
内容分别为 1、2、3。
接下来多配置几个启动器:
分别运行一下试试:
查看各个节点的状态:
➜ bin telnet localhost 2181 Trying ::1... Connected to localhost. Escape character is '^]'. stat Zookeeper version: 3.8.0-SNAPSHOT-1590a424cb7a8768b0ae01f2957856b1834dd68d-dirty, built on 2021-04-23 10:09 UTC Clients: /0:0:0:0:0:0:0:1:62163[0](queued=0,recved=1,sent=0) /127.0.0.1:62157[1](queued=0,recved=2,sent=2) Latency min/avg/max: 3/3.0/3 Received: 3 Sent: 2 Connections: 2 Outstanding: 0 Zxid: 0x100000006 Mode: follower Node count: 6 Connection closed by foreign host.
➜ bin telnet localhost 2182 Trying ::1... Connected to localhost. Escape character is '^]'. stat Zookeeper version: 3.8.0-SNAPSHOT-1590a424cb7a8768b0ae01f2957856b1834dd68d-dirty, built on 2021-04-23 10:09 UTC Clients: /127.0.0.1:62154[1](queued=0,recved=10,sent=10) /0:0:0:0:0:0:0:1:62204[0](queued=0,recved=1,sent=0) Latency min/avg/max: 0/1.2222/4 Received: 11 Sent: 10 Connections: 2 Outstanding: 0 Zxid: 0x200000000 Mode: leader Node count: 6 Proposal sizes last/min/max: -1/-1/-1 Connection closed by foreign host.
➜ bin telnet localhost 2183 Trying ::1... Connected to localhost. Escape character is '^]'. stat Zookeeper version: 3.8.0-SNAPSHOT-1590a424cb7a8768b0ae01f2957856b1834dd68d-dirty, built on 2021-04-23 10:09 UTC Clients: /0:0:0:0:0:0:0:1:62206[0](queued=0,recved=1,sent=0) /0:0:0:0:0:0:0:1:62162[1](queued=0,recved=12,sent=12) Latency min/avg/max: 0/0.5455/2 Received: 13 Sent: 12 Connections: 2 Outstanding: 0 Zxid: 0x100000006 Mode: follower Node count: 6 Connection closed by foreign host.
当然也可以客户端访问:
至此 ZK 集群已经搭建完毕!