一、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