目录
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 {@Overridepublic 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.xsdhttp://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临时结点很方便的表达了