一、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-hant/n/297975.html