目录
zookeeper_2">zookeeper为什么可作为注册中心
zookeeper_5">zookeeper注册中心优缺点
首先需要了解下zookeeper作为注册中心的优缺点
结论:尽管ZooKeeper在服务注册与发现、配置管理、分布式锁等场景中非常有用,但它并不适合所有的场景。在选择使用ZooKeeper时,需要根据具体的应用需求、性能要求以及系统的复杂性来综合考虑其优缺点。在一些情况下,可以考虑使用更轻量级的解决方案如Consul或Etcd,这些工具在某些方面可能更适合特定的需求。
zookeeper_13">启动zookeeper
随意启动即可
mubi@mubideMacBook-Pro zookeeper-3.4.12 $ ./bin/zkServer.sh start conf/zoo_local.cfg
ZooKeeper JMX enabled by default
Using config: conf/zoo_local.cfg
Starting zookeeper ... STARTED
dubbo_24">编写springboot项目提供dubbo服务
1. 服务接口
简单的测试服务接口
package com.example.demoapi.dubboprovider;
/**
* @Author mubi
* @Date 2025/2/21 21:46
*/
public interface TestService {
int add(int a, int b);
}
依赖
<dependency>
<groupId>com.dq</groupId>
<artifactId>spring-groovy-open-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
dubbo_53">2. Springboot引入dubbo实现服务接口
2.1 工程目录和依赖
依赖如下
- dubbo 2.7.8
- spring 4.3.18.RELEASE
- springboot 2.1.4.RELEASE
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-groovy-test</artifactId>
<groupId>com.dq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-api2</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.8</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.8.0</version>
</dependency>
<!--模块依赖-->
<dependency>
<groupId>com.dq</groupId>
<artifactId>spring-groovy-open-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<!-- junit依赖包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
2.2 启动程序和application.properties
package com.example.demoapi;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* @Author mubi
* @Date 2021/2/13 12:04
*/
@EnableDubbo
@SpringBootApplication
@ComponentScan("com.example")
public class DemoApiApplication2 {
public static void main(String[] args) {
SpringApplication.run(DemoApiApplication2.class, args);
}
}
- application.properties
#https
server.port=8089
# Dubbo 配置
dubbo.application.name=demoprovider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.scan.base-packages=com.example.demoapi.dubboprovider
dubbo.protocol.port=20881
2.3 @DubboService 实现服务接口
package com.example.demoapi.dubboprovider;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
@DubboService
@Service
public class TestServiceImpl implements TestService {
@Override
public int add(int a, int b) {
return a + b + 1;
}
}
2.4 测试api,用于测试启动
package com.example.demoapi.control;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author mubi
* @Date 2021/2/13 12:04
*/
@RestController
public class TestControl {
@GetMapping(value = "/test")
public String getTest() {
return "hello test2";
}
}
开启两个springboot应用
都提供同样的服务:com.example.demoapi.dubboprovider.TestService
,dubbo端口不同
dubbo.protocol.port=20880
dubbo.protocol.port=20881
为了方便测试,可以故意把实现写的不一样
一个是return a + b;
一个是return a + b + 1;
dubboAdmin_250">dubboAdmin配置随机策略
下载一个dubboAmdin.war 然后放到tomcat webapps下启动tomcat即可,如下图
打开dubbo-admin: http://localhost:8080/dubbo-admin-2.8.4/
配置一个随机策略,方便测试
客户端测试
随便起个maven项目
spring xml配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="dubbotest" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 向注册中心订阅服务 -->
<dubbo:reference id="testService" interface="com.example.demoapi.dubboprovider.TestService" />
</beans>
- pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-demo</artifactId>
<groupId>com.mubi.dubbo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbotest</artifactId>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- spring版本号 -->
<spring.version>4.3.18.RELEASE</spring.version>
<!-- log4j日志包版本号 -->
<slf4j.version>1.7.18</slf4j.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<!--模块依赖-->
<dependency>
<groupId>com.dq</groupId>
<artifactId>spring-groovy-open-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- spring begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring end -->
<!-- 注册中心zookeeper begin -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
<!-- 注册中心zookeeper end -->
<!-- 添加日志相关jar包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>
</project>
- 测试
有时候输出4, 有时候输出5,符合预期的负载均衡策略
zookeeper_430">zookeeper客户端查看服务信息
mac使用PrettyZoo可参考文档:https://blog.csdn.net/gitblog_06511/article/details/142393820
可以看到服务如下
zookeeper_node_metadata_439">zookeeper node metadata字段含义说明
在ZooKeeper中,节点(node)的元数据(metadata)包含了关于该节点的各种信息,这些信息通常通过ZooKeeper的Stat类表示。Stat类包含了多个字段,每个字段都提供了关于节点的不同方面信息。以下是一些常见的Stat类字段及其含义:
-
czxid - 创建节点的事务ID(Transaction ID)。这是创建该节点时ZooKeeper服务器分配的事务ID。
-
mzxid - 最后修改节点的事务ID。这是最后一次修改该节点内容或其子节点时ZooKeeper服务器分配的事务ID。
-
pzxid - 最后修改子节点的事务ID。这是最后一次修改该节点的子节点时ZooKeeper服务器分配的事务ID。
-
ctime - 创建时间。这是节点被创建的时间戳(以毫秒为单位)。
-
mtime - 最后修改时间。这是节点最后一次被修改的时间戳(以毫秒为单位),包括内容或子节点的修改。
-
version - 版本号。每次对节点数据进行修改,版本号会增加。
-
cversion - 子节点版本号。每次对节点的子节点进行增加、删除操作时,此版本号会增加。
-
aversion - ACL版本号。每次对节点的ACL(访问控制列表)进行修改时,此版本号会增加。
-
ephemeralOwner - 临时节点的所有者会话ID。如果是临时节点,则此字段包含创建该临时节点的会话ID;如果是持久节点,则此字段为0。
-
dataLength - 数据长度。这是存储在节点中的数据部分的长度(以字节为单位)。
-
numChildren - 子节点数量。这是直接子节点的数量。
-
pzxid - 最后子节点变更的事务ID(在某些实现中可能不直接暴露,但在某些情况下,特别是在使用某些特定命令或API时可以看到)。
服务提供者2个实例
如下,服务具体提供者(黄色框)是临时结点,其它是持久结点。
- 测试程序有2个服务提供者
测试输出和关闭
- 测试了三次,且没有关闭测试程序,可以看到三个服务消费者(也是临时结点)
可以看到有4的输出,也有5的输出
测试进程关闭后,consumer也就没有临时结点了
dubbo_491">dubbo客户端分析
注意到客户端一直能看到如下日志,即客户端与zookeeper保持了心跳连接
连接在则服务在,consumer临时结点在,否则临时结点消失
服务的调用当然是dubbo rpc机制。这里暂不具体分析rpc机制,重点看下zookeeper 客户端 SendThread线程(百度AI回答如下)
所以当我们设计一个客户端的时候,也要考虑心跳维持,队列缓存,异常处理等等问题
dubbo_503">dubbo服务端分析
通过dubbo-admin可以看到服务,并可进行简单的配置负载均衡策略
当关闭一个服务提供者之后,同客户端程序,临时结点也是没有了
所以服务的动态新增删除,用zookeeper临时结点很方便的表达了