zookeeper分布式服务集群与负载监控讲解 梦里梦外; 2022-04-04 03:12 147阅读 0赞 ZooKeeper是一个[分布式][Link 1]的,开放源码的[分布式应用程序][Link 2]协调服务,是[Google][]的Chubby一个[开源][Link 3]的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70][] 对于zookeeper的安装,大家可以先按照zookeeper官网上的介绍进行安装,因为直接在网上找到的安装步骤可能会存在问题,所以大家应该养成一个良好的习惯,尽量在官方网站获取最权威的介绍与知识,就向我们都源码是一样的。官方的价值是最高的。 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 1][] 重点zookeeper是一个开源的进行协调服务的中间件,高性能,分布式。它能做什么呢?数据存储、服务注册与发现、集群管理、分布式锁等。而且zookeeper的部署支持单机和集群,具有一定的灵活性。 zookeeper的底层数据结构是树形结构,每一个节点成为数据节点,注意,节点存储的是数据,而不是文件或者其他。数据节点成为znode,它是zookeeper结构的最小组成单元。 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 2][] 创建节点的命令是: -s : 有序节点 无须节点 -e : 临时节点 持久节点 create -s -e path data acl 节点的特性有两种:一个是临时性节点,它的生命周期与当前该节点所属的会话相关联,在会话结束后的一段时间后,临时性节点会自动删除。这里注意的一点是为什么是会话结束一段时间之后才删除节点呢?是因为设计者在设计的时候考虑的网络抖动的问题,这可能不是人为的结束会话,而是由于网络的故障或者其他的故障,当值当前的会话被迫结束,如果立即删除调zookeeper中存储的节点数据,显然,这不是我们想要的,所以,在设计的时候,考虑到网络心跳的问题,在会话结束的一段时间后,数据节点才会通过某些算法执行自动删除。在临时行节点的数据中有一个属性字段是EphemeralOwner,它存储的是该节点所属会话的会话id,是一个唯一的值。另一个是持久化节点,它在创建之后,不会随着会话的声明周期而影响自己的生命周期。当创建节点时,不写 -s -e 参数的时候,默认创建的是持久化节点。 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 3][] 另外需要注意的是,只有持久化节点才可以创建子节点,临时节点是不可以创建子节点的。zookeeper的树形结构在深度上是无限制的,在广度上一般也没有限制。节点名称在同一级目录下必须唯一。 通过get命令,我们可以获取到该节点的数据信息。 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 4][] 下面看一下这些属性都分别表示什么: cZxid : 表示创建事务id ctime :表是常见时间 mzxid : 表示修改事务时间 pzxid : 只有子节点列表变更才会更新 cversion : 与乐观锁相关 任何客户端对数据库字段修改之后 对应的字段递增 下面通过程序来实现一下结构的构建与服务的调用: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 5][] 目前通过java api 连接zookeeper服务端的方式有两种 : zkClient 和 curator 我们采用第一种,代码如下: 服务提供者 A 与 B 代码相同 : package com.jd.zk; import com.sun.xml.internal.ws.resources.ProviderApiMessages; import org.I0Itec.zkclient.ZkClient; import java.io.IOException; public class ProviderA { private String serviceName = "serviceA"; private final String ROOT = "/configcenter"; public void init(){ // 产生连接 判断根节点是否存在 不存在则创建 String zkServer = "192.168.11.142:2181"; ZkClient zkClient = new ZkClient(zkServer); if(!zkClient.exists(ROOT)){ zkClient.createPersistent(ROOT); } // 启动服务 判断当前服务节点是否注册过 if(!zkClient.exists(ROOT + "/" + serviceName)){ zkClient.createPersistent(ROOT + "/" + serviceName); // 注意是全路径 } String ip = "192.128.11.130:8080"; zkClient.createEphemeral(ROOT + "/" + serviceName + "/" + ip); System.out.println("providerA服务启动成功"); } public static void main(String[] args) throws IOException { ProviderA providerA = new ProviderA(); providerA.init(); System.in.read(); } } 消费者调用服务: package com.jd.zk; import org.I0Itec.zkclient.IZkChildListener; import org.I0Itec.zkclient.ZkClient; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * 消费者 调用配置中心的地址 来访问生产者 * 从根节点开始读取 * */ public class Consumer { private List<String> serverList = new ArrayList<String>(); private String serviceName = "serviceA"; public void init() throws Exception { String zkServer = "192.168.11.142:2181"; ZkClient zkClient = new ZkClient(zkServer); String servicePath = "/configcenter/" + serviceName; boolean isExist = zkClient.exists(servicePath); if(isExist){ serverList = zkClient.getChildren(servicePath); }else{ throw new Exception("Errow"); } // 实现服务注册监听发现 zkClient.subscribeChildChanges(servicePath, new IZkChildListener() { public void handleChildChange(String s, List<String> list) throws Exception { System.out.println("服务节点发生变化,节点的信息 : " + list); serverList = list; } }); } // 实现负载均衡与监听 只不过这里采取的是随机负载 public void consumer(){ Random random = new Random(); int i = random.nextInt(serverList.size()); System.out.println(i); System.out.println("调用 :" + serverList.get(i) + "提供服务" ); } public static void main(String[] args) throws Exception { Consumer consumer = new Consumer(); consumer.init(); consumer.consumer(); System.in.read(); } } 先启动providerA 和 providerB ,然后执行Consumer 效果如下: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 6][] [Link 1]: https://baike.baidu.com/item/%E5%88%86%E5%B8%83%E5%BC%8F/19276232 [Link 2]: https://baike.baidu.com/item/%E5%88%86%E5%B8%83%E5%BC%8F%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/9854429 [Google]: https://baike.baidu.com/item/Google [Link 3]: https://baike.baidu.com/item/%E5%BC%80%E6%BA%90/246339 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70]: /images/20220404/989be708bed741c2b29857830166876d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 1]: /images/20220404/4346c29447164afd967b3e56127bf348.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 2]: /images/20220404/a5c0f023b63145eebc7a17f132e8abe2.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 3]: /images/20220404/c680ac94d12546c697dbc1c3c3b82571.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 4]: /images/20220404/90162f2e27254e89a0241a4f78cf51e3.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 5]: /images/20220404/c01c278e183246c4aa89cd7c4442d77b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0lCTGlwbHVz_size_16_color_FFFFFF_t_70 6]: /images/20220404/790c682489d6414d82cae799a84ae19d.png
还没有评论,来说两句吧...