一、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/zh-hk/n/297975.html
微信掃一掃
支付寶掃一掃