目录
1 集群搭建
2 Java连接
本文将演示ZooKeeper的伪集群搭建过程,用一台虚拟机来模拟搭建三个节点的集群效果。我虚拟机的ip是192.168.253.129,ZooKeeper的版本是3.4.14(我一开始安装的是ZooKeeper3.5.5,但是配置完了之后启动一直是失败的。所以如果你也有如此问题出现,可以尝试换成3.4.14版本来搭建)。
我的ZooKeeper安装目录在/usr/zookeeper/zookeeper-3.4.14/这个路径下,首先将该路径下的conf目录下的zoo_sample.cfg文件改名为zoo.cfg:
mv zoo_sample.cfg zoo.cfg
接着退回上一级,在zookeeper-3.4.14目录下创建一个zookeeper-cluster的目录并在其下分别创建2181、2182和2183三个子目录:
mkdir zookeeper-cluster
cd zookeeper-cluster
mkdir 2181
mkdir 2182
mkdir 2183
将之前改过名的zoo.cfg文件分别放进这三个子目录下,其中需要更改和添加的内容如下所示:
2181/zoo.cfg:
dataDir=/usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2181/data
dataLogDir=/usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2181/logs
clientPort=2181
server.1=192.168.253.129:2287:3387
server.2=192.168.253.129:2288:3388
server.3=192.168.253.129:2289:3389
2182/zoo.cfg:
dataDir=/usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2182/data
dataLogDir=/usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2182/logs
clientPort=2182
server.1=192.168.253.129:2287:3387
server.2=192.168.253.129:2288:3388
server.3=192.168.253.129:2289:3389
2183/zoo.cfg:
dataDir=/usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2183/data
dataLogDir=/usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2183/logs
clientPort=2183
server.1=192.168.253.129:2287:3387
server.2=192.168.253.129:2288:3388
server.3=192.168.253.129:2289:3389
然后在每个子目录下分别创建data和logs目录,用于上面的相关配置。
mkdir data
mkdir logs
在对三个子节点的目录下都创建了data和logs目录之后,紧接着在每个data目录下创建一个myid的文件:
vim myid
其中的内容存放的是当前节点的myid:
2181/data/myid:
1
2182/data/myid:
2
2183/data/myid:
3
至此我们算是配置好了相关的内容。最后是启动ZooKeeper,跳到zookeeper-3.4.14/bin目录下,使用下面的命令来分别启动三个节点:
zkServer.sh start /usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2181/zoo.cfg
zkServer.sh start /usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2182/zoo.cfg
zkServer.sh start /usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2183/zoo.cfg
运行效果如下:
随后我们可以通过下面的命令来查看三个节点的运行状态:
zkServer.sh status /usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2181/zoo.cfg
zkServer.sh status /usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2182/zoo.cfg
zkServer.sh status /usr/zookeeper/zookeeper-3.4.14/zookeeper-cluster/2183/zoo.cfg
运行效果如下:
可以看到,在我的ZooKeeper集群里,2182节点是主节点,而2181和2183节点是从节点。最后我们就可以用zkCli来连接客户端了,随便在一个节点上执行下面的命令(我是在2181节点上操作的):
zkCli.sh -server 192.168.253.129:2181
运行结果如下:
之后我们就可以使用ZooKeeper的命令了。
这里我是通过Curator来对ZooKeeper进行连接的,pom依赖如下所示(注:因为我使用的Zookeeper版本是3.4.14,所以这里使用的Curator版本不能是高版本):
org.apache.curator
curator-recipes
2.13.0
简单的测试代码如下所示:
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import java.util.List;
import java.util.concurrent.*;
public class CuratorBase {
/**
* ZooKeeper地址
*/
private static final String CONNECT_ADDR = "192.168.253.129:2181,192.168.253.129:2182,192.168.253.129:2183";
/**
* session超时时间
*/
private static final int SESSION_OUTTIME = 10000;
public static void main(String[] args) throws Exception {
//重试策略,初试时间为1s,重试10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
//创建连接
CuratorFramework cf = CuratorFrameworkFactory.builder().connectString(CONNECT_ADDR).sessionTimeoutMs(SESSION_OUTTIME).retryPolicy(retryPolicy).build();
cf.start();
//创建节点
cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/super/c1", "c1内容".getBytes());
cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/super/c2", "c2内容".getBytes());
//读取节点
String c1 = new String(cf.getData().forPath("/super/c1"));
System.out.println(c1);
//修改节点
cf.setData().forPath("/super/c1", "修改c1内容".getBytes());
String c2 = new String(cf.getData().forPath("/super/c1"));
System.out.println(c2);
//读取子节点
List list = cf.getChildren().forPath("/super");
for (String p : list) {
System.out.println(p);
}
//判断节点是否存在
Stat stat = cf.checkExists().forPath("/super/c2");
System.out.println(stat);
//删除节点
cf.delete().guaranteed().deletingChildrenIfNeeded().forPath("/super");
//绑定回调函数
ExecutorService pool = new ThreadPoolExecutor(10, 20, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(1024), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).inBackground((curatorFramework, curatorEvent) -> {
System.out.println("code:" + curatorEvent.getResultCode());
System.out.println("type:" + curatorEvent.getType());
System.out.println("线程为:" + Thread.currentThread().getName());
}, pool).forPath("/super/c3", "c3内容".getBytes());
System.out.println("主线程:" + Thread.currentThread().getName());
Thread.sleep(Integer.MAX_VALUE);
cf.close();
}
}