Zookeeper实现注册中心

1 Zookeeper实现注册中心

1.1 项目准备

创建一个父工程,名称为handwritten-zookeeper-discovery,并在父工程下创建两个Spring Boot项目,分别为order-service和user-service,并在order-service中准备一个OrderController。

1
2
3
4
5
6
7
8
9
@RestController
@RequestMapping("/order")
public class OrderController{
@RequestMapping("/query")
public String query(){
System.out.printLn("query...");
return "query...";
}
}

1.2 实现服务注册

以order-service项目为例,实现服务注册的功能

1.2.1 事件监听机制扩展Spring Boot源码

1
2
3
4
5
6
public class JackApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("事件监听机制的回调...");
}
}

Spring SPI: MATA-INF/spring.factories

1
org.springframework.context.ApplicationListener=com.jack.zkorderservice.initializer.JackApplicationListener

1.2.2 定义服务注册接口和实现类

1
2
3
4
5
6
7
8
9
10
public interface ServiceRegistry{
void register();
}

public class ZookeeperServiceRegistry implements ServiceRegistry{
@Override
public void register(){

}
}

1.2.3 构造函数初始化curatorFramework

(1)引入curator依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.1</version>
</dependency>

(2)构造函数初始化curator

1
2
3
4
5
6
7
8
9
10
11
private CuratorFramework curatorFramework;

public ZookeeperServiceRegistry(String zkServer){
this.curatorFramework = CUratorFrameworkFactory
.build()
.connectionTimeoutMs(20000)
.connectString(zkServer)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
curatorFramework.start();
}

1.2.4 配置application.properties

1
2
3
4
server.port=9091
zk.service-name=order-service
zk.server=192.168.0.8:2181
zk.ip=127.0.0.1

1.2.5 完善监听器回调逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class JackApplicationListener implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent event){
System.out.printLn("事件监听机制得回调。。。");
// 获取app.properties配置属性
Environment environment = event.getApplicationContext().getEnvironment();
String serviceName = environment.getProperty("zk.service-name");
String ip = environment.getProperty("zk.ip");
String port = environment.getProperty("server.port");
String zkServer = environment.getProperty("zk.server");
// 服务注册
ServiceRegistry zookeeperServiceRegistry = new ZookeeperServiceRegistry(zkServer);
zookeeperServiceRegistry.register()
}
}

1.2.6 完善ZookeeperRegistry构造函数

1
2
// 服务注册
ServiceRegistry zookeeperServiceRegistry = new ZookeeperServiceRegistry(serviceName,ip,port,zkServer);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ZookeeperServiceRegistry implements ServiceRegistry{
private CuratorFramework curatorFramework;
private final String ip;
private final String port;
private final String serviceName;
private final String basePath="/jack-registry";

public ZookeeperServiceRegistry(String serviceName, String ip, String port, String zkServer) {
this.serviceName=serviceName;
this.ip=ip;
this.port=port;
this.curatorFramework = CuratorFrameworkFactory
.builder()
.connectionTimeoutMs(20000)
.connectString(zkServer)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
curatorFramework.start();
}
}

1.2.7 完善ZookeeperServiceRegistry#register()方法

1
2
3
4
5
6
7
8
9
10
11
12
public void register() {
String serviceNamePath=basePath+"/"+serviceName;
try {
if(curatorFramework.checkExists().forPath(serviceNamePath)==null) {
this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(serviceNamePath);
}
String urlNode = curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath(serviceNamePath + "/" + ip +":"+ port);
System.out.println("服务 "+urlNode+" 注册成功...");
} catch (Exception e) {
e.printStackTrace();
}
}

1.3 注册多个服务实例

(1)修改application.properties文件

(2)允许多个实例的方式进行注册

(3)观察order-service节点下的实例

1.4 手写服务发现

1.4.1 定义服务发现接口和实现类

1
2
3
4
public interface ServiceDiscovery {
List<String> discovery(String serviceName);
void registerWatch(String serviceNamePath);
}
1
2
3
4
5
6
7
8
9
public class ServiceDiscoveryImpl implements ServiceDiscovery{
@Override
public List<String> discovery(String serviceName) {
return null;
}
@Override
public void registerWatch(String serviceNamePath) {
}
}

1.4.2 定义配置信息

1
2
server.port=6666
zk.server=192.168.0.8:2181

1.4.3 完善ServiceDiscoveryImpl构造函数

(1)引入curator依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.1</version>
</dependency>

(2)完善构造函数

1
2
3
4
5
6
7
8
9
10
11
private final CuratorFramework curatorFramework;
private final String basePath="/jack-registry";
public ServiceDiscoveryImpl(String zkServer) {
this.curatorFramework = CuratorFrameworkFactory
.builder()
.connectionTimeoutMs(20000)
.connectString(zkServer)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
curatorFramework.start();
}

1.4.4 完善ServiceDiscoveryImpl#discovery方法

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public List<String> discovery(String serviceName) {
String serviceNamePath=basePath + "/" + serviceName;
try {
if (this.curatorFramework.checkExists().forPath(serviceNamePath)!=null){
return this.curatorFramework.getChildren().forPath(serviceNamePath);
}
} catch (Exception e){
e.printStackTrace();
}
return null;
}

1.4.5 将ServiceDiscoveryImpl交给Spring IoC容器管理

(1)创建ZookeeperDiscoveryAutoConfiguration配置类

1
2
3
4
5
6
7
8
9
@Configuration
public class ZookeeperDiscoveryAutoConfiguration {
@Resource
private Environment environment;
@Bean
public ServiceDiscoveryImpl serviceDiscovery(){
return new ServiceDiscoveryImpl(environment.getProperty("zk.server"));
}
}

(2)通过spring spi机制管理配置类

1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.jack.zkuserservice.config.ZookeeperDiscoveryAutoConfiguration

1.4.6 负载均衡

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface LoadBalance {
String select(List<String> urls);
}

//-----------
public class RandomLoadBalance implements LoadBalance{
@Override
public String select(List<String> urls) {
int len=urls.size();
Random random=new Random();
return urls.get(random.nextInt(len));
}
}

1.4.7 ServiceDiscoveryTest测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@SpringBootTest
public class ServiceDiscoveryTest {
@Resource
private ServiceDiscovery serviceDiscovery;

private List<String> urls;

@Test
public void discovery() throws IOException {
urls = this.serviceDiscovery.discovery("order-service");
LoadBalance loadBalance=new RandomLoadBalance();
String url = loadBalance.select(urls);
System.out.println("目标url为: "+url);
String response = new RestTemplate().getForObject("http://" + url + "/order/query", String.class);
System.out.println("response: "+response);
// 添加对节点order-service的监听
this.serviceDiscovery.registerWatch("/jack-registry/order-service",urls);
System.in.read();
}
}

1.4.8 添加对节点的监听

监听order-service子节点的变化,完善ServiceDiscoveryImpl#registerWatch方法

1
2
3
4
5
6
7
8
9
10
11
12
public void registerWatch(String serviceNamePath) {
// 永久的监听
CuratorCache curatorCache = CuratorCache.build(curatorFramework, serviceNamePath);
CuratorCacheListener listener = CuratorCacheListener.builder().forPathChildrenCache(serviceNamePath, curatorFramework, new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
System.out.println("最新的urls为: "+curatorFramework.getChildren().forPath(serviceNamePath));
}
}).build();
curatorCache.listenable().addListener(listener);
curatorCache.start();
}

2 Spring Cloud Zookeeper实现注册中心

(1)创建spring-cloud-zookeeper的spring boot项目,Spring Boot版本为2.7.2

(2)定义Spring Cloud的版本管理

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--定义版本的管理-->
<dependencyManagement>
<dependencies>
<!--定义sc的版本-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.3</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

(3)引入spring cloud zookeeper注册中心的依赖

1
2
3
4
5
<!-- spring cloud zookeeper discovery 注册中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>

(4)写注册中心相关的配置

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
zookeeper:
connect-string: 192.168.0.8:2181
discovery:
root: /services/registries
application:
name: spring-cloud-zookeeper
server:
port: 9091

(5)启动Spring Boot项目,观察Zookeeper Server上的数据

(6)服务发现代码

1
2
3
4
5
6
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/sc-zk-discovery")
public List<ServiceInstance> serviceUrl() {
return discoveryClient.getInstances("spring-cloud-zookeeper");
}

(7)服务注册实现核心入口

AbstractAutoServiceRegistration#onApplicationEvent


Zookeeper实现注册中心
http://www.zivjie.cn/2023/03/25/中间件/zookeeper/Zookeeper实现注册中心/
作者
Francis
发布于
2023年3月25日
许可协议