一、zookeeper简介
Apache ZooKeeper是一个开源的分布式协调服务,可以为分布式应用程序提供高效且可靠的分布式协调服务。它是Hadoop和Kafka等著名分布式系统的重要组成部分。ZooKeeper可以看作是分布式应用程序基础设施的核心,提供了诸如数据同步、配置管理、分布式锁、分布式队列等功能。ZooKeeper采用了集中式的设计和分布式的实现,是一种典型的Paxos算法实现,通过数据的“write-once, read-many”方式提供高性能、高可靠性的服务,具有良好的可扩展性和可靠性。
二、k8szookeeper基础操作
创建zookeeper服务
我们可以通过kubernetes创建zookeeper服务,我们可以通过以下yml示例来创建一个zookeeper服务:
apiVersion: v1
kind: Service
metadata:
name: my-zookeeper-service
spec:
selector:
app: my-zookeeper
ports:
- name: zk-client
protocol: TCP
port: 2181
targetPort: 2181
- name: zk-server
protocol: TCP
port: 2888
targetPort: 2888
- name: zk-election
protocol: TCP
port: 3888
targetPort: 3888
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-zookeeper
spec:
serviceName: my-zookeeper-service
replicas: 3
selector:
matchLabels:
app: my-zookeeper
template:
metadata:
labels:
app: my-zookeeper
spec:
containers:
- name: zookeeper
image: zookeeper:3.4.9
ports:
- containerPort: 2181
- containerPort: 2888
- containerPort: 3888
volumeMounts:
- name: data
mountPath: /data
- name: conf
mountPath: /conf
command: ["/bin/bash"]
args: ["-c", "ln -s /conf/zoo.cfg ./conf/zoo.cfg; zkServer.sh start-foreground"]
volumes:
- name: data
persistentVolumeClaim:
claimName: my-zk-pvc
- name: conf
configMap:
name: my-zk-cm
访问zookeeper服务
我们可以通过Port Forwarding的方式在本地直接访问zookeeper服务,具体操作步骤如下所示:
1. 获取zookeeper服务的pod名称:
$ kubectl get pods
2. 执行Port Forwarding命令:
$ kubectl port-forward 2181:2181
3. 在本地通过2181端口访问zookeeper服务:
$ zkCli -server localhost:2181
配置zookeeper
我们可以通过配置文件来修改zookeeper的配置信息,例如我们可以修改zookeeper的dataDir、clientPort等参数。以下为zookeeper的配置文件示例:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/data clientPort=2181 server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
监控zookeeper
ZooKeeper提供了丰富的监控指标,可以通过JMX监控、ZooKeeper-Monitor、Cadvisor等工具对其进行监控。下面我们将介绍如何通过JMX监控zookeeper。
监控zookeeper的JMX指标
我们可以通过添加如下JAVA_OPTS来启用JMX监控ZooKeeper:
-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=7199 -Djava.rmi.server.hostname=192.168.XX.XX
然后我们可以通过JConsole等JMX监控工具来访问ZooKeeper的JMX端口,获取ZooKeeper的监控指标信息。
三、k8szookeeper集群管理
创建k8szookeeper集群
我们可以通过kubernetes创建k8szookeeper集群,以下为创建一个3节点k8szookeeper集群的yml示例:
apiVersion: v1
kind: ConfigMap
metadata:
name: zookeeper-config
data:
zoo.cfg: |
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data
clientPort=2181
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
spec:
ports:
- name: zk-client
port: 2181
targetPort: 2181
clusterIP: None
selector:
app: zookeeper
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zookeeper
spec:
replicas: 3
serviceName: zookeeper
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: zookeeper
image: zookeeper:3.4.9
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: election
env:
- name: ZOO_MY_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: ZOO_SERVERS
value: "server.1=zookeeper-0.zookeeper:2888:3888 server.2=zookeeper-1.zookeeper:2888:3888 server.3=zookeeper-2.zookeeper:2888:3888"
volumeMounts:
- name: datadir
mountPath: /data
- name: config-volume
mountPath: /conf
volumes:
- name: datadir
persistentVolumeClaim:
claimName: zookeeper-pv-claim
- name: config-volume
configMap:
name: zookeeper-config
增加k8szookeeper节点
我们可以通过以下步骤来增加k8szookeeper节点:
1. 创建一个新的zookeeper服务,并指定新的serverID。
2. 修改zookeeper集群中已有节点的配置文件,添加新的server。
3. 将新的zk数据目录复制到新的服务器中。
4. 启动新的节点,并加入到zookeeper集群中。
删除k8szookeeper节点
我们可以通过以下步骤来删除k8szookeeper节点:
1. 停止zk服务。
2. 从zookeeper集群配置文件中删除该节点的配置信息。
3. 删除该节点的数据目录。
四、k8szookeeper应用场景
分布式锁
ZooKeeper提供一个基于节点的锁系统,可以用于分布式系统中的锁定需求。分布式锁是一个常见的需求,例如分布式计算、分布式任务调度、分布式事务等等。ZooKeeper作为一个分布式协调服务,可以提供高效、稳定、可靠的分布式锁服务。下面是一个Java实现的分布式锁示例:
public class DistributedLock {
private static final String LOCK_ROOT = "/locks";
private ZooKeeper zk;
private String lockName;
private String lockPath;
private String watchNode;
private String currentNode;
public DistributedLock(ZooKeeper zk, String lockName) {
this.zk = zk;
this.lockName = lockName;
}
public void lock() throws Exception {
// 创建锁的根目录
Stat stat = zk.exists(LOCK_ROOT, false);
if (stat == null) {
zk.create(LOCK_ROOT, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// 创建锁节点
lockPath = zk.create(LOCK_ROOT + "/" + lockName, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
currentNode = lockPath.substring(lockPath.lastIndexOf("/") + 1);
// 获取所有的子节点,并排序
List children = zk.getChildren(LOCK_ROOT, false);
Collections.sort(children);
if (currentNode.equals(children.get(0))) {
// 获取锁
return;
} else {
// 同步监控当前节点的前一个节点
int index = Collections.binarySearch(children, currentNode);
watchNode = children.get(index - 1);
zk.getData(LOCK_ROOT + "/" + watchNode, true, null);
}
// 等待前一个节点释放锁
synchronized (this) {
wait();
}
}
public void unlock() throws Exception {
zk.delete(lockPath, -1);
}
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(LOCK_ROOT + "/" + watchNode)) {
synchronized (this) {
notifyAll();
}
}
try {
zk.getData(LOCK_ROOT + "/" + watchNode, true, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
分布式配置管理
ZooKeeper可以用作分布式配置管理工具,从而实现了分布式系统中的配置管理。通过在ZooKeeper中创建一个节点作为配置存储的根目录,然后以配置文件的形式保存系统配置信息,即可用ZooKeeper实现分布式配置管理。下面是一个Java实现的分布式配置管理示例:
public class ConfigManager {
private ZooKeeper zk;
private Watcher watcher;
private Config config;
private static final String CONFIG_NODE = "/config";
public ConfigManager(ZooKeeper zk, Config config) {
this.zk = zk;
this.config = config;
this.watcher = new Watcher() {
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDataChanged) {
try {
byte[] data = zk.getData(CONFIG_NODE, watcher, null);
String configStr = new String(data, "UTF-8");
ConfigManager.this.config.load(configStr);
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
}
public void syncConfig() throws Exception {
Stat stat = zk.exists(CONFIG_NODE, watcher);
if (stat == null) {
zk.create(CONFIG_NODE, "".getBytes("UTF-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} else {
byte[] data = zk.getData(CONFIG_NODE, watcher, null);
String configStr = new String(data, "UTF-8");
this.config.load(configStr);
}
}
public Config getConfig() {
return config;
}
public void submitConfig(String configStr) throws Exception {
Stat stat = zk.exists(CONFIG_NODE, false);
if (stat == null) {
zk.create(CONFIG_NODE, "".getBytes("UTF-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
zk.setData(CONFIG_NODE, configStr.getBytes("UTF-8"), -1);
}
}
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/297975.html
微信扫一扫
支付宝扫一扫