Zookeeper+Dubbo入门案例(服务注册与发现)
一、Zookeeper
ZooKeeper是一个开源的分布式协调服务,用于管理和协调分布式系统中的各种配置、状态和元数据。
ZooKeeper通过提供一个可靠的、层级的命名空间来存储和管理数据,这个命名空间类似于一个标准的文件系统。在ZooKeeper中,数据被组织成一个树形结构,每个节点都可以存储少量的数据。
ZooKeeper的主要特性包括:
分布式协调: ZooKeeper可以协调和同步分布式系统中各个节点之间的操作,提供一致性和顺序性保证。
数据发布/订阅: 节点可以订阅其他节点的变化,并在数据发生变化时得到通知。
高可用性: ZooKeeper通过使用多个服务器来提供高可用性,如果有服务器失效,其他服务器可以接管其工作。
临时节点: 可以创建临时节点,当客户端与ZooKeeper断开连接时,这些临时节点会自动删除。
Watcher机制: 客户端可以注册Watcher来监听节点的变化,当节点发生变化时会触发相应的操作。
ZooKeeper常用于构建分布式系统和协调分布式应用程序。例如,它可以被用作配置管理、服务发现、分布式锁、分布式队列等。
一、安装
1、下载(docker)
docker pull zookeeper # 拉取最新版
2、运行
先创建数据卷挂载
/usr/local/zookeeper/data 数据存放
/usr/local/zookeeper/conf 配置文件存放
/usr/local/zookeeper/logs 日志存放
启动命令:
docker run -d --name zookeeper --privileged=true --restart=always -p 2181:2181 -v /usr/local/zookeeper/data:/data -v /usr/local/zookeeper/conf:/conf -v /usr/local/zookeeper/logs:/datalog zookeeper:latest
3、配置文件(/usr/local/zookeeper/conf 会得到挂载的容器内部的那份配置文件)如下:
可视情况修改
dataDir=/data # 存储数据文件的目录
dataLogDir=/datalog # 存储事务日志文件的目录
tickTime=2000 # 基本时间单元,影响各种超时设置
initLimit=5 # 启动时等待客户端连接的最长时间
syncLimit=2 # leader 等待 follower 的最长时间
autopurge.snapRetainCount=3 # 数据快照文件保留个数
autopurge.purgeInterval=0 # 自动清理数据快照和事务日志的时间间隔
maxClientCnxns=60 # 单个客户端与服务器之间的最大连接数
standaloneEnabled=true # 启用单机模式
admin.enableServer=true # 启用 admin 服务器
server.1=localhost:2888:3888;2181 # 集群中的节点列表
二、Zookeeper常见的基本命令(增删改查节点)
使用docker exec -it zookeeper zkCli.sh运行zookeeper客户端练习命令
ls / #查看根节点的所有节点 ,‘/’为根,可以使用起亚path
ls -s nodePath
create nodePath data # 创建节点并存入元数据
delete nodePath # 删除指定路径的节点
get nodePath # 获取指定路径的节点
set nodePath newData # 更新节点元数据
getChildren nodePath:# 这个命令用于获取指定节点路径下的所有子节点的列表。你需要将nodePath替换为要获取子节点列表的节点路径。
exists nodePath:# 这个命令用于检查指定路径的节点是否存在。你需要将nodePath替换为要检查的节点路径。
setData nodePath newData:# 这个命令用于设置节点的数据,如果节点不存在则会抛出异常。你需要将nodePath替换为要设置数据的节点路径,newData替换为要设置的新数据。
create -e nodePath data:# 这个命令用于创建一个临时节点,当客户端与ZooKeeper断开连接后,该节点将被自动删除。你需要将nodePath替换为节点的路径,data替换为要存储的数据。
[zk: localhost:2181(CONNECTED) 2] ls -s /dubbo
[com.example.consumer.service.ConsumerService, com.example.provider.api.ProviderService, config, mapping, metadata, org.apache.dubbo.metadata.MetadataService, org.apache.dubbo.mock.api.MockService]
cZxid = 0x2
ctime = Wed Jun 28 08:07:17 UTC 2023
mZxid = 0x2
mtime = Wed Jun 28 08:07:17 UTC 2023
pZxid = 0x90
cversion = 7
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 11
numChildren = 7
[zk: localhost:2181(CONNECTED) 8] create /test wlh #创建
Created /test
[zk: localhost:2181(CONNECTED) 9] get /test # 查看/test的节点信息
wlh
[zk: localhost:2181(CONNECTED) 10] delete /test # 删除/test 节点,包括数据
[zk: localhost:2181(CONNECTED) 11] ls /
[dubbo, services, zookeeper]
[zk: localhost:2181(CONNECTED) 12] create /test {name:'wlh',age:18}
Created /test
[zk: localhost:2181(CONNECTED) 13] get /test
{name:'wlh',age:18}
[zk: localhost:2181(CONNECTED) 14] set /test {name:'newName'} # 更新节点
[zk: localhost:2181(CONNECTED) 15] get /test
{name:'newName'}
三、Dubbo
Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。
安装运行dubbo-admin
Dubbo-Admin提供了一个基于Web的界面,用于管理和监控Dubbo服务。
Dubbo-Admin提供了以下主要功能:
- 服务治理:Dubbo-Admin可以用于注册和管理Dubbo服务。它支持服务的发布、订阅和监控,可以查看和管理注册中心中的服务信息、提供者和消费者列表等。
- 服务监控:Dubbo-Admin可以提供Dubbo服务的健康状况、性能指标和调用日志等监控信息。它可以显示服务的调用次数、响应时间、错误率等指标,帮助开发人员和运维人员监控服务的运行情况。
- 服务测试:Dubbo-Admin提供了服务测试的功能,可以通过界面进行服务的测试和调试,方便开发人员进行接口的开发和调试工作。
- 配置管理:Dubbo-Admin可以用于管理Dubbo的配置信息,包括协议配置、注册中心配置、服务提供者和消费者的配置等。
Dubbo-Admin提供了一个友好的用户界面,使得开发人员和运维人员可以通过浏览器轻松地进行Dubbo服务的管理和监控。它可以帮助提高开发效率,简化服务治理的工作,并提供对Dubbo服务的实时监控和故障诊断能力。
本来打算采用docker的形式,但是我自己搞了一下午没弄好,因此采用zookeeper启动在虚拟机上,然后Dubbo-Admin启动在我自己电脑上,反正是一个可视化界面。
步骤:
1、去GitHub拉取项目(apache/dubbo-admin)
这是前后端分离项目,前端采用的是vue需要搭建环境node.js,可参考网上教程(非常简单)
2、使用idea打开刚刚的项目,这也是个spring boot项目,修改里面的配置文件(zookeeper的地址)
如果你的zookeeper也是启动在本地的话就不需要修改,里面的默认配置是本机的127.0.0.1:2181
3、上面需要等待后端的service下载依赖(等个5-10分钟)之后启动后端
4、进入前端的项目路径安装依赖并启动
pnpm dev
npm dev # 都是启动的命令
因为我的已经启动过了,没有下载的过程,下面是前后端启动完成的界面:
可以看到
可视化界面到此结束
三、Spring Boot+Zookeeper+Dubbo集成
零、项目工程规划
因为zookeeper+dubbo是分布式方案,因此呢,采用两个spring boot微服务远程过程调用方法
一、引入依赖
服务者:
provider
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>provider</name>
<description>provider</description>
<modules>
<module>provider-server</module>
<module>application</module>
<module>api</module>
</modules>
<properties>
<java.version>8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
api:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>api</name>
<description>api</description>
<properties>
<java.version>8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>application</name>
<description>application</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>provider-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
service:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>provider-server</artifactId>
<packaging>jar</packaging>
<name>provider-server</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<!-- 移除旧版的zookeeper-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
<version>3.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.1</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.slf4j</groupId>-->
<!-- <artifactId>slf4j-log4j12</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>log4j</groupId>-->
<!-- <artifactId>log4j</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<!-- Curator库提供的服务发现模块-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 分布式的一些高级功能的支持:分布式锁、分布式计数器、分布式队列、分布式选举等-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
消费者:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<description>consumer</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<!-- 移除旧版的zookeeper-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
<version>3.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.1</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.slf4j</groupId>-->
<!-- <artifactId>slf4j-log4j12</artifactId>-->
<!-- </exclusion>-->
<!-- <exclusion>-->
<!-- <groupId>log4j</groupId>-->
<!-- <artifactId>log4j</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<!-- Curator库提供的服务发现模块-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 不使用这些功能可以不引入-分布式的一些高级功能的支持:分布式锁、分布式计数器、分布式队列、分布式选举等-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.1.0</version>
</dependency>
<!--服务者接口api-->
<dependency>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、配置文件修改
服务提供者:
server:
port: 8081
dubbo:
application:
name: provider
registry:
# zookeeper
address: zookeeper://192.168.19.129:2181
# 采用dubbo协议
protocol: dubbo
scan:
base-packages: com.example.provider
# 修改协议服务监听的端口(因为dubbo-admin也是一个服务提供者,默认的是20880,因此需要修改)
protocol:
port: 20881
消费者:
server:
port: 8082
dubbo:
application:
name: consumer-1
registry:
address: zookeeper://192.168.19.129:2181
protocol: dubbo
scan:
base-packages: com.example.service
三、编写测试代码
service:
package com.example.provider.api;
/**
* @Classname Provider
* @Description TODO
* @Version 1.0.0
* @Date 2023/6/28 15:27
* @Created by wlh12
*/
public interface ProviderService {
String hello(String name);
}
serviceImpl:
package com.example.provider.serviceImpl;
import com.example.provider.api.ProviderService;
import org.apache.dubbo.config.annotation.DubboService;
/**
* @Classname ProviderServiceImpl
* @Description TODO
* @Version 1.0.0
* @Date 2023/6/28 15:47
* @Created by wlh12
*/
@DubboService
public class ProviderServiceImpl implements ProviderService {
@Override
public String hello(String name) {
return "hello!"+name+"!";
}
}
消费者写一个controller来测试
package com.example.consumer.controller;
import com.example.provider.api.ProviderService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Classname ConsumerController
* @Description TODO
* @Version 1.0.0
* @Date 2023/6/28 15:29
* @Created by wlh12
*/
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@DubboReference(check = false)
private ProviderService providerService;
@GetMapping("/test")
public String test(String name){
return providerService.hello(name);
}
}
四、运行测试
启动之后可以看到服务提供者(消费者不会在这展示)
服务关系里面看得到消费者
发送请求进行测试,get请求就难得去启动postman了,直接网页!
和预期的结果是一样的