1. Zookeeper 集群模式介绍
Zookeeper 集群模式一共有三种类型的角色:
①:Leader: 处理所有的事务请求(写请求),可以处理读请求,集群中只能有一个Leader
②:Follower: 只能处理读请求,同时作为 Leader的候选节点,即如果Leader宕机,Follower节点 要参与到新的Leader选举中,有可能成为新的Leader节点。
③:Observer: 只能处理读请求。不能参与选举
2. zookeeper 集群搭建
本例搭建的是伪集群模式,即一台机器上启动四个zookeeper实例组成集群,真正的集群模式无非就是实例IP地址不同,搭建方法没有区别,步骤如下:
1. 下载并解压zookeeper
wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz
tar -zxvf apache-zookeeper-3.5.8-bin.tar.gz
cd apache-zookeeper-3.5.8-bin
2. 集群准备工作
# 创建存放集群节点的文件夹
mkdir zkCluster
# 在zkCluster内部分别创建每一个集群节点
cd zkCluster
mkdir zk1 zk2 zk3 zk4
# 为每一个集群节点的myid文件中,写入一个唯一id,用来标识节点身份
echo 1 > /zk1/myid
echo 2 > /zk2/myid
echo 3 > /zk3/myid
echo 4 > /zk4/myid
3. 编辑集群配置文件
# 为每一个集群节点建立配置文件
cp conf/zoo_sample.cfg conf/zoo1.cfg
# 配置zoo1.cfg的文件存储位置
vim zoo1.cfg
dataDir=/tuling/apache-zookeeper-3.5.8-bin/zkCluster/zk1
# 配置zoo1.cfg节点的端口号
clientPort=2191
# 在zoo1.cfg尾部添加以下集群配置,代表集群节点有哪些,详解见下文
server.1=192.168.100.100:2001:3001
server.2=192.168.100.100:2002:3002
server.3=192.168.100.100:2003:3003
server.4=192.168.100.100:2004:3004:observer //observer节点
# 其他三个节点可以复制zoo1.cfg中的配置,只需修改端口号和数据存储位置即可!
cp conf/zoo1.cfg conf/zoo2.cfg
。。。此处省略
其中集群配置server.1=192.168.100.100:2001:3001:observer 命令解析如下:
命令 | 含义 |
---|---|
server.1 | 其中.1代表的是第几号服务器,取值是在zk1中的myid中配置好的 |
192.168.100.100 | 这个服务器的 ip 地址 |
2001 | 这个服务器与集群中的 Leader 服务器交换信息的端口 |
3001 | 用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 服务器的 ip 地址都一样,为了防止端口冲突,所以要给它们分配不同的端口号 |
observer | 如果需要通过添加不参与集群选举以及事务请求的过半机制的 Observer节点,可以在此位置,添加observer标识 |
4. 启动集群服务器
bin/zkServer.sh start conf/zoo1.cfg
bin/zkServer.sh start conf/zoo2.cfg
bin/zkServer.sh start conf/zoo3.cfg
bin/zkServer.sh start conf/zoo4.cfg
通过状态查看启动是否成功,也可查看当前节点是master、follower、observe哪一种节点类型
bin/zkServer.sh status conf/zoo2.cfg
zoo2.cfg 节点属于leader节点
5. 连接集群客户端
①:连接集群所有客户端
./bin/zkCli.sh -server 192.168.100.100:2191,192.168.100.100:2192,192.168.100.100:2193,192.168.100.100:2194
连接成功如下图:
②:连接集群单个客户端
./bin/zkCli.sh -server 192.168.100.100:2191
连接成功如下图:
以上两种方式的区别在于:
- 如果只连接单个客户端,如果当前连接的服务器挂掉,当前客户端连接也会挂掉,连接失败
- 如果是连接所有客户端的形式,则允许集群中半数以下的服务挂掉!当半数以上服务挂掉才会停止服务,可用性更高一点!
注意:集群中的节点信息被存放在每一个节点/zookeeper/config/目录下!
测试:在2191服务器上创建一个test节点,检测节点是否被同步到别的服务器上
2191服务器:
2193服务器:
从结果上可以看到,数据已经同步!此时zookeeper集群搭建成功!
3. 使用curate客户端连接zookeeper集群
3.1 创建连接
@Slf4j
public abstract class CuratorStandaloneBase {
//zookeeper连接
private final static String CLUSTER_CONNECT_STR="192.168.100.100:2191,192.168.100.100:2192,192.168.100.100:2193,192.168.100.100:2194";
//session超时时间
private static final int sessionTimeoutMs = 60*1000;
//连接超时时间
private static final int connectionTimeoutMs = 5000;
private static CuratorFramework curatorFramework;
@Before
public void init() {
//重试策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000, 30);
//流式编程,创建zookeeper连接
curatorFramework = CuratorFrameworkFactory.builder().connectString(getConnectStr())
.retryPolicy(retryPolicy)
.sessionTimeoutMs(sessionTimeoutMs) // 会话超时时间
.connectionTimeoutMs(connectionTimeoutMs) // 连接超时时间
.canBeReadOnly(true)
.build();
//添加监听器
curatorFramework.getConnectionStateListenable().addListener((client, newState) -> {
if (newState == ConnectionState.CONNECTED) {
log.info("连接成功!");
}
});
log.info("连接中......");
curatorFramework.start();
}
public void createIfNeed(String path) throws Exception {
Stat stat = curatorFramework.checkExists().forPath(path);
if (stat==null){
String s = curatorFramework.create().forPath(path);
log.info("path {} created! ",s);
}
}
public static CuratorFramework getCuratorFramework() {
return curatorFramework;
}
@After
public void test(){
try {
//主线程持续监听
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//获取客户端方法
protected String getConnectStr(){
return CONNECT_STR;
}
}
测试连接:从zookeeper集群中获取数据
@Test
public void testCluster() throws Exception {
CuratorFramework curatorFramework = getCuratorFramework();
String pathWithParent = "/test";
byte[] bytes = curatorFramework.getData().forPath(pathWithParent);
System.out.println(new String(bytes));
//每个一段时间获取一次数据
while (true) {
try {
byte[] bytes2 = curatorFramework.getData().forPath(pathWithParent);
System.out.println(new String(bytes2));
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
testCluster();
}
}
}
在集群任一服务器节点上为test节点设置数据hahaha
set /test hahaha
接下来运行测试代码,运行结果如下:
接下来就可以使用Cutate来操作zookeeper了!
另外,Zookeeper 3.5.0 以前,Zookeeper集群角色要发生改变的话,只能通过停掉所有的Zookeeper服务,修改集群配置,重启服务来完成,这样集群服务将有一段不可用的状态。
为了应对高可用需求,Zookeeper 3.5.0 提供了支持动态扩容/缩容的新特性。但是通过客户端API可以变更服务端集群状态是件很危险的事情,所以在zookeeper 3.5.3 版本要用动态配置,需要开启超级管理员身份验证模式 ACLs。如果是在一个安全的环境也可以通过配置 系统参数 -Dzookeeper.skipACL=yes 来避免配置维护acl 权限配置。具体步骤点此查看!!