在分布式架构的系统中,系统经常被暴露为服务以供其他系统调用,这也是SOA或微服务架构常用的模式。

为了使服务之间能够互相通信,需要有一个协调系统来管理这些服务,以便这些服务能够互相找到对方,这就是服务注册以发现机制。这个协调系统有时也被称作“注册中心”;

下面,我们将基于zookeeper来实现服务注册与发现功能。

新建springboot项目,添加一下依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.10</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

服务注册接口与实现:

package com.fish.learn.zookeeper.service.registry;/*** @Description:* @Author devin.jiang* @CreateDate 2019/4/30 20:41*/
public interface ServiceRegistry {/*** 注册服务* @param serviceName* @param serviceAddress*/void registry(String serviceName, String serviceAddress);}
package com.fish.learn.zookeeper.service.registry.impl;import com.fish.learn.zookeeper.service.constant.Constant;
import com.fish.learn.zookeeper.service.registry.ServiceRegistry;
import org.I0Itec.zkclient.ZkClient;/*** @Description:* @Author devin.jiang* @CreateDate 2019/4/30 20:44*/
public class ZkServiceRegistry implements ServiceRegistry {private String zkAddress = "localhost";private ZkClient zkClient;public void init() {zkClient = new ZkClient(zkAddress,Constant.ZK_SESSION_TIMEOUT,Constant.ZK_CONNECTION_TIMEOUT);System.out.println(">>> connect to zookeeper");}@Overridepublic void registry(String serviceName, String serviceAddress) {//创建registry节点(持久)String registryPath = Constant.ZK_REGISTRY;if (!zkClient.exists(registryPath)) {zkClient.createPersistent(registryPath);System.out.println(">>> create registry node:" + registryPath);}//创建service节点(持久)String servicePath = registryPath + "/" + serviceName;if (!zkClient.exists(servicePath)) {zkClient.createPersistent(servicePath);System.out.println(">>>create service node:" + servicePath);}//创建address节点(临时)String addressPath = servicePath + "/address-";String addressNode = zkClient.createEphemeralSequential(addressPath,serviceAddress);System.out.println(">>> create address node:" + addressNode);}}

服务发现实现:

package com.fish.learn.zookeeper.service.discovery;/*** @Description:* @Author devin.jiang* @CreateDate 2019/4/30 21:01*/
public interface ServiceDiscovery {/*** 服务发现* @param name* @return*/String discover(String name);}
package com.fish.learn.zookeeper.service.discovery.impl;import com.fish.learn.zookeeper.service.constant.Constant;
import com.fish.learn.zookeeper.service.discovery.ServiceDiscovery;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.util.CollectionUtils;import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadLocalRandom;/*** @Description:* @Author devin.jiang* @CreateDate 2019/4/30 21:02*/
public class ZkServiceDiscovery implements ServiceDiscovery {private String zkAddress = "localhost";private final List<String> addressCache = new CopyOnWriteArrayList<>();private ZkClient zkClient;public void init() {zkClient = new ZkClient(zkAddress,Constant.ZK_SESSION_TIMEOUT,Constant.ZK_CONNECTION_TIMEOUT);System.out.println(">>> connect to zookeeper");}@Overridepublic String discover(String name) {try {String servicePath = Constant.ZK_REGISTRY + "/" + name;//获取服务节点if (!zkClient.exists(servicePath)) {throw new RuntimeException(String.format(">>>can't find any service node on path {}",servicePath));}//从本地缓存获取某个服务地址String address;int addressCacheSize = addressCache.size();if (addressCacheSize > 0) {if (addressCacheSize == 1) {address = addressCache.get(0);} else {address = addressCache.get(ThreadLocalRandom.current().nextInt(addressCacheSize));}System.out.println(">>>get only address node:" + address);//从zk服务注册中心获取某个服务地址} else {List<String> addressList = zkClient.getChildren(servicePath);addressCache.addAll(addressList);//监听servicePath下的子文件是否发生变化zkClient.subscribeChildChanges(servicePath,(parentPath,currentChilds)->{System.out.println(">>>servicePath is changed:" + parentPath);addressCache.clear();addressCache.addAll(currentChilds);});if (CollectionUtils.isEmpty(addressList)) {throw new RuntimeException(String.format(">>>can't find any address node on path {}", servicePath));}int nodeSize = addressList.size();if (nodeSize == 1) {address = addressList.get(0);} else {//如果多个,则随机取一个address = addressList.get(ThreadLocalRandom.current().nextInt(nodeSize));}System.out.println(">>>get address node:" + address);}//获取IP和端口号String addressPath = servicePath + "/" + address;String hostAndPort = zkClient.readData(addressPath);return hostAndPort;} catch (Exception e) {System.out.println(">>> service discovery exception: " + e.getMessage());zkClient.close();}return null;}}

运行测试用例:

package com.fish.learn.zookeeper;import com.fish.learn.zookeeper.service.discovery.impl.ZkServiceDiscovery;
import com.fish.learn.zookeeper.service.registry.impl.ZkServiceRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ZookeeperApplication {private static final String SERVICE_NAME = "fish.com";private static final String SERVER_ADDRESS = "localhost:2181";public static void main(String[] args) {SpringApplication.run(ZookeeperApplication.class, args);ZkServiceRegistry registry = new ZkServiceRegistry();registry.init();registry.registry(SERVICE_NAME,SERVER_ADDRESS);ZkServiceDiscovery discovery = new ZkServiceDiscovery();discovery.init();discovery.discover(SERVICE_NAME);while (true){}}}

先启动zookeeper服务,再执行测试用例。我们分别启动三个测试用例,以模拟多个客户端同时进行服务注册场景,程序执行后,观察控制台的输出信息。

idea多实例启动项目:

第一个测试用例输出如下:

第二个测试用例输出如下:

第三个测试用例输出如下:

从上面例子运行的结果可以看出,第一个测试用例先运行,而其他服务还没有注册,所以在获取可用服务的时候获取了自己。第二个和第三个测试用例运行后,可用的服务实例就有多个,所以在获取服务时,有可能获取自己,也可能获取其他服务。当有新的服务进行注册时,所有服务实例都能感知到新服务的加入。

zookeeper实现服务注册与发现相关推荐

  1. Web Api 基于Zookeeper的服务注册与发现

    差异 基于Nginx的服务提供和消费 基于zookeeper的服务注册和发现 zk的负载均衡是可以调控,nginx只是能调权重,其他需要可控的都需要自己写插件:但是nginx的吞吐量比zk大很多,可以 ...

  2. 8、Zookeeper服务注册与发现原理浅析

    了解Zookeeper的我们都知道,Zookeeper是一种分布式协调服务,在分布式应用中,主要用来实现分布式服务的注册与发现以及分布式锁,本文我们简单介绍一下Zookeeper是如何实现服务的注册与 ...

  3. Zookeeper服务注册与发现

    Zookeeper作为服务注册与发现的解决方案,它有如下优点: 1. 它提供的简单API 2. 已有互联网公司(例如:Pinterest,Airbnb)使用它来进行服务注册与发现 3. 支持多语言的客 ...

  4. Zookeeper实现服务注册发现

    服务注册中心 ​ 之所以需要访问注册和服务发现是因为分布式系统中,服务之间需要相互调用,但若每个服务自己维护一份依赖的服务信息的话,就显得很麻烦,且自身维护的数据无法保证其实时性,当依赖的服务信息发生 ...

  5. SpringBoot系列:9. 分布式系统,Dubbo,Zookeeper服务注册与发现

    前言 本章主要对分布式系统,RPC的实现方式和Zookeeper实现做一个详细的概述并通过实战代码加深对他们的了解. 1. 分布式 什么是分布式系统? :"分布式系统是若干独立计算机的集合, ...

  6. Eureka的初理解【服务注册与发现、高可用集群、自我保护机制、与Zookeeper的比较】

    Eureka的初理解 什么是Eureka? Eureka[读音要知道怎么读] Netflix 在设计 Eureka 时,遵循的就是AP原则(CAP文章下面有介绍). Eureka是Netflix的一个 ...

  7. zookeeper与grpc集成实现服务注册与发现

    Zookeeper介绍 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一 ...

  8. Dubbo学习笔记001---分布式服务调用_Dubbo简介_依赖zookeeper做为注册中心进行服务注册与发现

    JAVA技术交流QQ群:170933152 Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员 ...

  9. 聊聊微服务的服务注册与发现

    聊起微服务的服务注册与发现,很多人立马就会脱口而出 zk.etcd.consul.eureka 这些组件,进而聊到 CAP 如何取舍,性能如何,高可用和容灾是怎么实现的. 引言 聊起微服务的服务注册与 ...

最新文章

  1. YYHS-魏传之长坂逆袭(梦回三国系列T1)
  2. RDIFramework.NET V2.9版本 WinFom部分新增与修正的功能
  3. Spring 4 + Reactor Integration Example--转
  4. 1X1 convolution layers
  5. 用 Arthas “庖丁解牛”
  6. 通过反射写一个通用的设置某个对象的某个属性为指定的值
  7. cnn stride and padding_Pytorch实现神经网络CNN案例
  8. coposer 安装 laravel
  9. mysql 常用日期,时间函数
  10. centos7永久修改主机名
  11. Java实现面向对象编程
  12. Geoserver+postSQL+openlayer实现路径规划
  13. C语言知识点——函数参数
  14. 2.自动加载(phalapi框架总结)
  15. adm怎么下bt连接_【使用教程】序列模式——福禄克BT系列电池测试仪
  16. c++内存分区、创建变量开辟内存
  17. revit二开之关联族参数的实现
  18. RxJava操作符(四)Combining
  19. Web API-添加Swagger,SQL Server,记录并导出到Excel
  20. Java实现的信号灯

热门文章

  1. Lucene原理剖析
  2. android安全测试工具----busybox的下载和安装
  3. 时序图,程序员的保命技能
  4. 由浅入深讲解显示存储计算机基础原理
  5. ChatGLM LoRA微调实战方案
  6. Python基础教程-第6章-函数
  7. 经典面试题-线程池七大参数
  8. Python自动化测试面试题及答案(持续更新中)
  9. Javascript数据类型强制转换
  10. chrome谷歌浏览器如何让网站可以自动播放音乐