六、Java API操作
6.1 原生 API
1)Maven依赖
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<type>pom</type>
</dependency>
2)相关操作
(1)获得客户端对象
private ZooKeeper zooKeeper;
@Before
public void getCline() throws Exception{
zooKeeper = new ZooKeeper("192.168.134.99:2181",2000,null);
}
(2)获取节点值
@Test
public void getData()throws Exception{
/*获取节点值*/
byte[] data = zooKeeper.getData("/baizhi/123", null, null);
System.out.println(new String(data));
}
(3)获取节点孩子
@Test
public void getChild() throws Exception{
/*获取当前输入节点下的子节点*/
List<String> children = zooKeeper.getChildren("/baizhi/gjf", null);
children.forEach((a)->{
System.out.println(a);
});
}
(4)创建节点
@Test
public void createNode() throws Exception{
/*创建持久节点*/
Object value = null;
value = "12312312";
byte[] bytes = ((String) value).getBytes();
String s = zooKeeper.create("/baizhi/123", bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(s);
}
(5)更新节点值
@Test
public void setData() throws Exception{
Stat stat = zooKeeper.setData("/baizhi/123", new String("123123").getBytes(), -1);
System.out.println(stat);
}
(6)判断节点是否存在
@Test
public void exist() throws Exception{
Stat stat = zooKeeper.exists("/baizhi/13", false);
if (stat==null) {
System.out.println("该节点不存在!");
}else {
System.out.println("该节点存在!");
}
}
6.2 zkCline API
1)Mavne依赖
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.8</version>
</dependency>
2)核心API
ZkClient client=new ZkClient("ip:port");
3)相关操作
package test;
import org.I0Itec.zkclient.ZkClient;
import java.util.List;
/**
* Create by GuoJF on 2019/3/12
*/
public class Main {
public static void main(String[] args) {
ZkClient zkClient = new ZkClient("192.168.134.5:2181");
/*
* 获取根目录下所有的node信息
*
* */
List<String> children = zkClient.getChildren("/");
children.forEach((a)->{
System.out.println(a);
});
}
}
(1)创建节点
@Test
public void createNode() {
String result = zkClient.create("/baizhi/001", "001", CreateMode.PERSISTENT);
System.out.println(result);
}
(2)获取节点
@Test
public void getData() {
Object readData = zkClient.readData("/baizhi/001");
System.out.println(readData.toString());
}
(3)更新节点值
@Test
public void setData() {
zkClient.writeData("/baizhi/001", "123123");
}
(4)删除节点
@Test
public void delNode() {
boolean delete = zkClient.delete("/baizhi/001");
if (delete) {
System.out.println("删除成功!");
} else {
System.out.println("删除失败或者节点不存在!");
}
}
(5)判断节点是否存在
@Test
public void exist(){
boolean exists = zkClient.exists("/baizhi/001");
if (exists){
System.out.println("该节点已经存在!");
}else {
System.out.println("该节点不存在!");
}
}
(6)获取孩子节点
@Test
public void getChild(){
List<String> children = zkClient.getChildren("/baizhi");
for (String child : children) {
System.out.println(child);
}
}
6.3 Curator API
1)Maven依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.7.1</version>
</dependency>
2)相关操作
(1)获取客户端对象
private CuratorFramework curatorFramework;
@Before
public void getClient() {
/*
* 重连策略 四种实现
* ExponentialBackoffRetry、RetryNTimes、RetryOneTimes、RetryUntilElapsed
* */
ExponentialBackoffRetry backoffRetry = new ExponentialBackoffRetry(1000, 1000);
curatorFramework = CuratorFrameworkFactory.newClient("192.168.134.99:2181", backoffRetry);
curatorFramework.start();
}
(2)创建节点
@Test
public void createNode() throws Exception {
String s = curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath("/baizhi/002", new String("123").getBytes());
System.out.println(s);
}
(3)获取节点
@Test
public void getData() throws Exception {
byte[] bytes = curatorFramework.getData().forPath("/baizhi/002");
System.out.println(new String(bytes));
}
(4)更新节点值
@Test
public void setData() {
try {
curatorFramework.setData().forPath("/baizhi/001", new String("123123").getBytes());
System.out.println("更新成功!");
} catch (KeeperException.NoNodeException e) {
System.out.println("更新失败,该节点不存在!");
} catch (Exception e) {
e.printStackTrace();
}
}
(5)获取孩子节点
@Test
public void getChild() throws Exception {
curatorFramework.getChildren().forPath("/baizhi").forEach((child) -> {
System.out.println(child);
});
}
(6)删除节点
@Test
public void delNode() throws Exception {
curatorFramework.delete().forPath("/baizhi/002");
}
6.4 Watcher接口
1)原生API实现Watch接口
在这里使用的是原生的Apache的Java API
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<type>pom</type>
</dependency>
ZooKeeper Watcher监视使客户端能够接收来自ZooKeeper服务器的通知,并在发生时处理这些事件。 ZooKeeper Java API提供了一个名为Watcher
的公共接口,客户端事件处理程序类必须实现该接口才能接收有关来自ZooKeeper服务器的事件通知。 以编程方式,使用这种客户端的应用程序通过向客户端注册回调(callback)对象来处理这些事件。
package test;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.UUID;
/**
* Create by GuoJF on 2019/3/12
*/
public class DataUpdater {
private static String hostPort = "192.168.134.5:2181";
private static String zooDataPath = "/baizhi/gjf";
ZooKeeper zk;
public DataUpdater() throws IOException {
try {
zk = new ZooKeeper(hostPort, 2000, null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() throws InterruptedException, KeeperException {
while (true) {
String uuid = UUID.randomUUID().toString();
byte zoo_data[] = uuid.getBytes();
zk.setData(zooDataPath, zoo_data, -1);
try {
Thread.sleep(5000); // Sleep for 5 secs
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
DataUpdater dataUpdater = new DataUpdater();
dataUpdater.run();
}
}
package test;
import org.apache.zookeeper.*;
/**
* Create by GuoJF on 2019/3/13
*/
public class DataWatcher implements Watcher,Runnable {
ZooKeeper zooKeeper;
public DataWatcher() {
try {
zooKeeper = new ZooKeeper("192.168.134.5:2181",2000,this);
if (zooKeeper.exists("/baizhi/gjf",this)==null) {
zooKeeper.create("/baizhi/gjf", "get".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
DataWatcher dataWatcher = new DataWatcher();
dataWatcher.run();
}
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDataChanged){
System.out.println("数据发改变了吧");
try {
byte[] data = zooKeeper.getData("/baizhi/gjf", this, null);
String s = new String(data);
System.out.println(s);
}catch (Exception e){
}
}
}
public void run() {
try {
synchronized (this) {
while (true) {
wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
2)ZkClient实现Watcher接口
@Test
public void watcherInterface() throws Exception {
zkClient.subscribeDataChanges("/baizhi/gjf", new IZkDataListener() {
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("节点名称:" + dataPath);
System.out.println("节点名称:" + data.toString());
}
@Override
public void handleDataDeleted(String dataPath) throws Exception {
}
});
Thread.sleep(Integer.MAX_VALUE);
}
3)Curator API实现Watcher接口
ZooKeeper原生的API支持通过注册Watcher来进行事件监听,但是Watcher通知是一次性的,因此开发过程中需要反复注册Watcher,比较繁琐。Curator引入了Cache来监听ZooKeeper服务端的事件。Cache对ZooKeeper事件监听进行了封装,能够自动处理反复注册监听,简化了ZooKeeper原生API繁琐的开发过程。
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.7.1</version>
</dependency>
(1)NodeCache
监听指定的数据变化
/*
*NodeCache
*
* */
//在注册监听器的时候,如果传入此参数,当事件触发时,逻辑由线程池处理
ExecutorService pool = Executors.newFixedThreadPool(2);
NodeCache nodeCache = new NodeCache(curatorFramework, "/baizhi/gjf", false);
nodeCache.start(true);
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println(new String(nodeCache.getCurrentData().getData()));
}
}, pool);
(2)PathChildrenCache
监听指定节点下所有子节点的数据变化
/**
* 监听子节点的变化情况
*/
PathChildrenCache childrenCache = new PathChildrenCache(curatorFramework, "/baizhi", true);
childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
childrenCache.getListenable().addListener(
new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event)
throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
System.out.println("CHILD_ADDED: " + event.getData().getPath());
break;
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED: " + event.getData().getPath());
break;
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED: " + event.getData().getPath());
break;
default:
break;
}
}
},
pool
);
七、Zookeeper ACL
7.1 Shell 操作
zookeeper本身提供了ACL机制,表示为scheme: id:permissions,第一个字段表示采用哪一种机制,第二个id表示用户,permissions表示相关权限(如只读,读写,管理等)。
7.1 .1 scheme :id 介绍
- world: 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的
- auth: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication),使用auth来设置权限的时候,需要在zk里注册一个用户才可以
- digest: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication
- ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
- super: 在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)
7.1 .2 permissions
权限 | ACL简写 | 描述 |
---|---|---|
CREATE | c | 可以创建子节点 |
DELETE | d | 可以删除子节点(仅下一级节点) |
READ | r | 可以读取节点数据及显示子节点列表 |
WRITE | w | 可以设置节点数据 |
ADMIN | a | 可以设置节点访问控制列表权限 |
7.1.3 ACL Shell 命令
命令 | 使用方式 | 描述 |
---|---|---|
getAcl | getAcl
| 读取ACL权限 |
setAcl | setAcl
| 设置ACL权限 |
addauth | addauth | 添加认证用户 |
7.1.4 操作
World scheme
其实默认就是Word Scheme
语法
setAcl <path> world:anyone:<acl>
#随便创建一个节点
[zk: localhost:2181(CONNECTED) 61] create /baizhiedu 1
Created /baizhiedu
[zk: localhost:2181(CONNECTED) 62] getAcl /baizhiedu
'world,'anyone
: cdrwa
#在创建完成后相关节点,还可以通过setAcl的方式设置相关权限
[zk: localhost:2181(CONNECTED) 64] setAcl的方式设置相关权限 /baizhiedu world:anyone:cdrw
cZxid = 0x1c631
ctime = Tue Jul 09 08:37:06 CST 2019
mZxid = 0x1c631
mtime = Tue Jul 09 08:37:06 CST 2019
pZxid = 0x1c631
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
[zk: localhost:2181(CONNECTED) 67] getAcl /baizhiedu
'world,'anyone
: cdrw
IP scheme
对于特定IP适用,其他没有设置过的IP没有相关权限
语法
setAcl <path> ip:<ip>:<acl>
[zk: localhost:2181(CONNECTED) 73] setAcl /baizhi01 ip:192.168.123.111:cdrwa
cZxid = 0x1c635
ctime = Tue Jul 09 08:44:14 CST 2019
mZxid = 0x1c635
mtime = Tue Jul 09 08:44:14 CST 2019
pZxid = 0x1c635
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
[zk: localhost:2181(CONNECTED) 78] getAcl /baizhi01
'ip,'192.168.123.111
: cdrwa
[zk: localhost:2181(CONNECTED) 79] get /baizhi01
Authentication is not valid : /baizhi01
Auth scheme
语法
addauth digest <user>:<password> #添加认证用户
setAcl <path> auth:<user>:<acl>
[zk: localhost:2181(CONNECTED) 81] addauth digest gjf:root
[zk: localhost:2181(CONNECTED) 82] setAcl /baizhi03 auth:gjf:root
cZxid = 0x1c637
ctime = Tue Jul 09 08:47:00 CST 2019
mZxid = 0x1c637
mtime = Tue Jul 09 08:47:00 CST 2019
pZxid = 0x1c637
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
[zk: localhost:2181(CONNECTED) 95] getAcl /baizhi03
'digest,'gjf:bbYGkKPfBgiZDzcwrmVylqDlXnI=
: cdrwa
Digest scheme
语法
setAcl <path> digest:<user>:<password>:<acl>
计算密文
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
[root@GuoJiafeng01 ~]# echo -n gjf:root | openssl dgst -binary -sha1 | openssl base64
bbYGkKPfBgiZDzcwrmVylqDlXnI=
[zk: localhost:2181(CONNECTED) 98] create /baizhi04 1
Created /baizhi04
[zk: localhost:2181(CONNECTED) 99] setAcl /baizhi04 digest:gjf:bbYGkKPfBgiZDzcwrmVylqDlXnI=:a
cZxid = 0x1c641
ctime = Tue Jul 09 08:59:18 CST 2019
mZxid = 0x1c641
mtime = Tue Jul 09 08:59:18 CST 2019
pZxid = 0x1c641
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
[zk: localhost:2181(CONNECTED) 100] getAcl /baizhi04
'digest,'gjf:bbYGkKPfBgiZDzcwrmVylqDlXnI=
: a
# 当前是没有权限的
[zk: localhost:2181(CONNECTED) 101] get /baizhi04
Authentication is not valid : /baizhi04
# 在当前session中添加认证用户
[zk: localhost:2181(CONNECTED) 102] addauth digest gjf:root
#就能获取到相关的权限了
[zk: localhost:2181(CONNECTED) 107] get /baizhi04
1
cZxid = 0x1c641
ctime = Tue Jul 09 08:59:18 CST 2019
mZxid = 0x1c641
mtime = Tue Jul 09 08:59:18 CST 2019
pZxid = 0x1c641
cversion = 0
dataVersion = 0
aclVersion = 2
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
7.2 Java API
@Before
public void getClient() {
/*
* 重连策略 四种实现
* ExponentialBackoffRetry、RetryNTimes、RetryOneTimes、RetryUntilElapsed
* */
ACLProvider aclProvider = new ACLProvider() {
private List<ACL> acl ;
@Override
public List<ACL> getDefaultAcl() {
if(acl ==null){
ArrayList<ACL> acl = ZooDefs.Ids.CREATOR_ALL_ACL;
acl.clear();
acl.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", "admin:123") ));
this.acl = acl;
}
return acl;
}
@Override
public List<ACL> getAclForPath(String path) {
return null;
}
};
ExponentialBackoffRetry backoffRetry = new ExponentialBackoffRetry(1000, 1000);
//curatorFramework = CuratorFrameworkFactory.builder().aclProvider(aclProvider).authorization("digest", "admin:123".getBytes()).connectString("192.168.134.99:2181").retryPolicy(backoffRetry).build();
curatorFramework = CuratorFrameworkFactory.newClient("192.168.134.99:2181", backoffRetry);
this.curatorFramework.start();
}
八、应用
8.1 分布式高可用(简单)
package test.ha;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Create by rechen on 2020/7/10
*/
public class App {
public static void main(String[] args) throws Exception {
Integer port = 1233;
ExponentialBackoffRetry backoffRetry = new ExponentialBackoffRetry(1000, 1000);
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("192.168.134.99:2181", backoffRetry);
curatorFramework.start();
Stat stat = curatorFramework.checkExists().forPath("/baizhi/test01");
if (stat == null) {
curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath("/baizhi/test01", new String("localhost:" + port).getBytes());
soutFunction(port);
} else {
System.out.println("当前节点已经存在,主机服务为:" + new String(curatorFramework.getData().forPath("/baizhi/test01")));
System.out.println("当前主机自动切换为StandyBy状态");
}
/*
*NodeCache
*
* */
//在注册监听器的时候,如果传入此参数,当事件触发时,逻辑由线程池处理
ExecutorService pool = Executors.newFixedThreadPool(2);
/**
* 监听子节点的变化情况
*/
PathChildrenCache childrenCache = new PathChildrenCache(curatorFramework, "/baizhi", true);
childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
childrenCache.getListenable().addListener(
new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event)
throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
System.out.println("节点上线: " + event.getData().getPath());
break;
case CHILD_REMOVED:
System.out.println("节点下线: " + event.getData().getPath());
System.out.println("正在上线其他节点,请稍后。");
if (event.getData().getPath().endsWith("/baizhi/test01")) {
try {
curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath("/baizhi/test01", new String("localhost:" + port).getBytes());
System.out.println("当前节点上线成功");
soutFunction(port);
} catch (Exception e) {
if (e instanceof KeeperException.NodeExistsException) {
System.out.println("当前节点上线失败,已有其他节点上线");
}
}
}
break;
case CHILD_UPDATED:
System.out.println("节点更新: " + event.getData().getPath());
break;
default:
break;
}
}
},
pool
);
Thread.sleep(Integer.MAX_VALUE);
}
public static void soutFunction(Integer port) {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("localhost:" + port + ",正在提供服务");
}
}
}
8.2 分布式高可用(优雅)
package test.ha;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.GetChildrenBuilder;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Create by rechen on 2020/7/10
*/
public class AppPro {
public static void main(String[] args) throws Exception {
final String[] lockip = {null};
final Integer[] port = {1233, 1234, 1235, 1236};
ExponentialBackoffRetry backoffRetry = new ExponentialBackoffRetry(1000, 1000);
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("192.168.123.129:2181", backoffRetry);
curatorFramework.start();
List<String> stringList = curatorFramework.getChildren().forPath("/ha");
System.out.println(stringList.size());
if (stringList.size() == 0) {
curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/ha/test01" + port[0], new String("localhost:" + port[0]).getBytes());
soutFunction(port[0]);
} else {
System.out.println("当前节点已经存在,主机服务为:" + lockip);
System.out.println("当前主机自动切换为StandyBy状态");
}
/*
*NodeCache
*
* */
//在注册监听器的时候,如果传入此参数,当事件触发时,逻辑由线程池处理
ExecutorService pool = Executors.newFixedThreadPool(2);
/**
* 监听子节点的变化情况
*/
PathChildrenCache childrenCache = new PathChildrenCache(curatorFramework, "/ha", true);
childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
final String[] currentPath = {""};
List<String> childers = curatorFramework.getChildren().forPath("/ha");
Collections.sort(childers);
currentPath[0] = childers.get(0);
childrenCache.getListenable().addListener(
new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event)
throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
//System.out.println("节点上线: " + event.getData().getPath());
break;
case CHILD_REMOVED:
if (event.getData().getPath().endsWith(currentPath[0])) {
System.out.println("节点下线: " + event.getData().getPath());
System.out.println("正在上线其他节点,请稍后。");
String path = curatorFramework.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/ha/test01", new String("localhost:" + port[0]).getBytes());
List<String> childers = curatorFramework.getChildren().forPath("/ha");
Collections.sort(childers);
currentPath[0] = childers.get(0);
if (path.endsWith(childers.get(0))) {
System.out.println("当前节点上线成功");
soutFunction(port[0]);
} else {
System.out.println("当前节点上线失败!");
System.out.println("删除当前节点!");
try {
curatorFramework.delete().forPath((path));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println((path) + "节点已经删除!");
}
}
break;
case CHILD_UPDATED:
System.out.println("节点更新: " + event.getData().getPath());
break;
default:
break;
}
}
},
pool
);
Thread.sleep(Integer.MAX_VALUE);
}
public static void soutFunction(Integer port) {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("localhost:" + port + ",正在提供服务");
}
}
}
九、集群搭建
9.1 集群配置
1)添加添加配置文件
tickTime=2000
dataDir=/home/zk/data
clientPort=2181
initLimit=5
syncLimit=2
server.1=guojiafeng01:2887:3887
server.2=guojiafeng01:2888:3888
server.3=guojiafeng01:2889:3889
server.id=host:port:port
指出了不同的zk的服务器的自身的标示,作为集群中一部分及其应该知道集群中其他的机器,在datadir目录中创建一个文件名为myid的文件,这个文件仅仅含有一行内容,制定的是自身的id值。比如服务器的id是1就在这个文件写1,第一个port是保持和主机通信,第二个port是做选举的。
2)新建myid文件
在上述配置文件中对的data目录下,创建一个myid文件,在节点1中的myid中写 1 (就一个数字1),在节点2中写数字2,依次列推
3)复制配置启动
9.2 配置文件详解
1)ZK的最小配置
最小配置是指Zookeeper运行所需的最小配置,Zookeeper只需要配置这些项就可以正常的运行Zookeeper。
clientPort
配置ZK监听客户端连接的端口
dataDir
内存数据库快照存放地址,如果没有指定事务日志存放地址(dataLogDir),默认也是存放在这个路径下,建议两个地址分开存放到不同的设备上。
tickTime
心跳基本时间单位,毫秒级
2)ZK的高级配置(可选)
高级配置是指有的需要直接通过系统属性进行设置)
dataLogDir
将事务日志存储在该路径下,比较重要,这个日志存储的设备效率会影响ZK的写吞吐量。
globalOutstandingLimit
(Java system property: zookeeper.globalOutstandingLimit)默认值是1000,限定了所有连接到服务器上但是还没有返回响应的请求个数(所有客户端请求的总数,不是连接总数),这个参数是针对单台服务器而言,设定太大可能会导致内存溢出。
preAllocSize
(Java system property: zookeeper.preAllocSize)默认值64M,以KB为单位,预先分配额定空间用于后续transactionlog 写入,每当剩余空间小于4K时,就会又分配64M,如此循环。如果SNAP做得比较频繁(snapCount比较小的时候),那么请减少这个值。
snapCount
(Java system property: zookeeper.snapCount)默认值100,000,当transaction每达到snapCount/2+rand.nextInt(snapCount/2)时,就做一次SNAPSHOT,默认情况下是50,000~100,000条transactionlog就会做一次,之所以用随机数是为了避免所有服务器可能在同一时间做snapshot.
traceFile (Java system property: requestTraceFile)
maxClientCnxns
默认值是10,一个客户端能够连接到同一个服务器上的最大连接数,根据IP来区分。如果设置为0,表示没有任何限制。设置该值一方面是为了防止DoS攻击。
clientPortAddress
与clientPort匹配,表示某个IP地址,如果服务器有多个网络接口(多个IP地址),如果没有设置这个属性,则clientPort会绑定到所有IP地址上,否则只绑定到该设置的IP地址上。
minSessionTimeout
最小的session time时间,默认值是2个tick time,客户端设置的session time 如果小于这个值,则会被强制协调为这个最小值。
maxSessionTimeout
最大的session time 时间,默认值是20个tick time. ,客户端设置的session time 如果大于这个值,则会被强制协调为这个最大值。
3)ZK的集群配置选项
electionAlg
领导选举算法,默认是3(fast leader election,基于TCP),0表示leader选举算法(基于UDP),1表示非授权快速选举算法(基于UDP),2表示授权快速选举算法(基于UDP),目前1和2算法都没有应用,不建议使用,0算法未来也可能会被干掉,只保留3(fast leader election)算法,因此最好直接使用默认就好。
initLimit
tickTime的个数,表示在leader选举结束后,followers与leader同步需要的时间,如果followers比较多或者说leader的数据非常多时,同步时间相应可能会增加,那么这个值也需要相应增加。当然,这个值也是follower和observer在开始同步leader的数据时的最大等待时间(setSoTimeout)
syncLimit
tickTime的个数,这时间容易和上面的时间混淆,它也表示follower和observer与leader交互时的最大等待时间,只不过是在与leader同步完毕之后,进入正常请求转发或ping等消息交互时的超时时间。
leaderServes
(Java system property: zookeeper.leaderServes) 如果该值不是no,则表示该服务器作为leader时是需要接受客户端连接的。为了获得更高吞吐量,当服务器数三台以上时一般建议设置为no。
cnxTimeout
(Java system property: zookeeper.cnxTimeout) 默认值是5000,单位ms 表示leaderelection时打开连接的超时时间,只用在算法3中。
4)ZK安全配置
skipACL
(Java systemproperty: zookeeper.skipACL) 默认值是no,忽略所有ACL检查,相当于开放了所有数据权限给任何人。
forceSync
(Java systemproperty: zookeeper.forceSync) 默认值是yes, 表示transactionlog在commit时是否立即写到磁盘上,如果关闭这个选项可能会在断电时丢失信息。
jute.maxbuffer
(Java system property: jute.maxbuffer)默认值0xfffff,单位是KB,表示节点数据最多1M。如果要设置这个值,必须要在所有服务器上都需要设置。
授权认证配置项
DigestAuthenticationProvider.superDigest
(Java system property only: zookeeper.DigestAuthenticationProvider.superDigest) 设置这个值是为了确定一个超级用户,它的值格式为
super:<base64encoded(SHA1(idpassword))> ,一旦当前连接addAuthInfo超级用户验证通过,后续所有操作都不会checkACL.
到这里zookeeper就更新完成了
创作不易,希望大家给个三连吧~