Dubbo:Docker部署Zookeeper、Dubbo Admin的详细教程和SpringBoot整合Dubbo的实战与演练
🪁🍁 希望本文能给您带来帮助,如果有任何问题,欢迎批评指正!🐅🐾🍁🐥
文章目录
- 一、背景
- 二、Dubbo概述
- 三、Dubbo与SpringCloud的关系
- 四、Dubbo技术架构
- 五、Docker安装Zookeeper
- 六、Docker安装Dubbo Admin
- 七、SpringBoot项目整合Dubbo
- 7.1 创建生产者服务
- 7.1.1 项目路径总览
- 7.1.2 pom.xml依赖引入
- 7.1.2.1 生产者父pom依赖
- 7.1.2.2 api 模块pom依赖
- 7.1.2.3 center 模块pom依赖
- 7.1.3 不同配置实现方式
- 7.1.3.1 xml配置
- 7.1.3.2 注解配置
- 7.2 创建消费者服务
- 7.2.1 项目路径总览
- 7.2.2 pom.xml依赖引入
- 7.2.3 不同配置实现方式
- 7.2.3.1 xml配置
- 7.2.3.2 注解配置
- 7.3 测试验证
- 7.3.1 云服务器中zookeeper客户端验证
- 7.3.2 Dubbo Admin控制台验证
- 八、其他高级特性
- 8.1 启动时检查
- 8.2 集群容错
- 8.3 负载均衡
- 8.4 直连提供者
- 8.5 多协议机制
- 8.5.1 多端口多协议
- 8.5.2 单端口多协议
- 8.6 多注册中心
- 8.7 多版本
- 8.8 日志管理
- 九、总结
一、背景
Dubbo作为阿里巴巴开源的微服务框架,提供了高性能的RPC调用。同时因为有阿里的背书,在国内市场得到了广泛应用,Dubbo的开源工作在2018年2月阿里将项目捐献给apache基金会后,得到了更加广大的发展。而最近因为在实际工作中有需要使用到Dubbo,故而专门开一篇专栏去记录并总结一下Dubbo相关的知识,在此,希望专栏里的内容能够帮到您。
二、Dubbo概述
Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。
按照微服务架构的定义,采用它的组织能够很好的提高业务迭代效率与系统稳定性,但前提是要先能保证微服务按照期望的方式运行,要做到这一点需要解决服务拆分与定义、数据通信、地址发现、流量管理、数据一致性、系统容错能力等一系列问题。
Dubbo 可以帮助解决如下微服务实践问题:
微服务编程范式和工具
Dubbo 支持基于 IDL 或语言特定方式的服务定义,提供多种形式的服务调用形式(如同步、异步、流式等)
高性能的 RPC 通信
Dubbo 帮助解决微服务组件之间的通信问题,提供了基于 HTTP、HTTP/2、TCP 等的多种高性能通信协议实现,并支持序列化协议扩展,在实现上解决网络连接管理、数据传输等基础问题。
微服务监控与治理
Dubbo 官方提供的服务发现、动态配置、负载均衡、流量路由等基础组件可以很好的帮助解决微服务基础实践的问题。除此之外,您还可以用 Admin 控制台监控微服务状态,通过周边生态完成限流降级、数据一致性、链路追踪等能力。
部署在多种环境
Dubbo 服务可以直接部署在容器、Kubernetes、Service Mesh等多种架构下。
三、Dubbo与SpringCloud的关系
Dubbo 和 Spring Cloud 有很多相似之处,它们都在整个架构图的相同位置并提供一些相似的功能。
相同点:
- Dubbo 和 Spring Cloud 都侧重在对分布式系统中常见问题模式的抽象(如服务发现、负载均衡、动态配置等),同时对每一个问题都提供了配套组件实现,形成了一套微服务整体解决方案,让使用 Dubbo 及 Spring Cloud 的用户在开发微服务应用时可以专注在业务逻辑开发上。
- Dubbo 和 Spring Cloud 都完全兼容 Spring 体系的应用开发模式,Dubbo 对 Spring 应用开发框架、Spring Boot 微服务框架都做了很好的适配,由于 Spring Cloud 出自 Spring 体系,在这一点上自然更不必多说。
不同点:
Dubbo
使用的是RPC
通信( 支持HTTP、HTTP/2(Triple、gRPC)、TCP 多种协议),而Spring Cloud
使用的是HTTP RESTFul
方式。
四、Dubbo技术架构
第一节已经介绍了Dubbo的功能非常强大,但是本文主要介绍Dubbo的两大主要核心特性:服务发现
与远程调用
, 而从上图架构图能发现其实现原理非常明了,它其实很像生产者-消费者模型。只是在这种模型上,加上了注册中心和监控中心,用于管理提供方提供的url,以及管理整个过程。我们一起来看一下Dubbo官网提供的架构图:
节点角色说明
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器,负责启动、加载、运行服务提供者 |
调用关系说明
1、服务容器负责启动,加载,运行服务提供者。
2、服务提供者在启动时,向注册中心注册自己提供的服务。
3、服务消费者在启动时,向注册中心订阅自己所需的服务。
4、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
5、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
6、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
五、Docker安装Zookeeper
在本地测试时,我们可以在代码中使用ip直连来进行Dubbo接口的调用,但在工作中,实际微服务开发时,我们更多的是会使用注册中心来进行Dubbo接口的调用,而注册中心有多种选择:Nacos、Zookeeper等,本文选择的是Dubbo+zookeeper
的组合。而为了方便使用,本文选择使用Dokcer来部署运行Zookeeper,下文就是使用Docker安装Zookeeper的具体细节步骤。
- 查看本地镜像和检索拉取Zookeeper 镜像
# 查看本地镜像
docker images
# 检索ZooKeeper 镜像
docker search zookeeper
# 拉取ZooKeeper镜像最新版本
docker pull zookeeper:latest
# 我使用的版本
docker pull zookeeper:3.5.7
- 启动ZooKeeper容器
docker run -d --name mynewzookeeper --privileged=true -p 2181:2181 -v /mydata/zookeeper/data:/data -v /mydata/zookeeper/conf:/conf -v /mydata/zookeeper/logs:/datalog zookeeper:3.5.7
运行MySQL时参数说明:
docker run:
在docker中启动一个容器实例。
-d:
该容器在后台运行。
--name mynewzookeeper:
给容器指定一个名字叫做 mynewzookeeper。这可以帮助你更容易地识别和管理这个容器。
-p 2181:2181:
这是一个端口映射选项,它将宿主机的 2181 端口映射到容器内的 2181 端口。这意味着在宿主机上,你可以通过访问 localhost:2181 来连接到运行在容器内的 ZooKeeper 服务。
-v /mydata/zookeeper/data:/data:
将容器/data目录下的数据,备份到主机的/mydata/zookeeper/data目录下。
-v /mydata/zookeeper/conf:/conf:
将容器/conf目录下的数据,备份到主机的 /mydata/zookeeper/conf目录下。
-v /mydata/zookeeper/logs:/datalog:
将容器/datalog目录下的数据,备份到主机的 /mydata/zookeeper/logs目录下。
zookeeper:3.5.7:
需要运行的容器名称以及版本号。
- 验证 Zookeeper 是否启动成功
docker ps
- 添加ZooKeeper配置文件,在挂载配置文件目录(/mydata/zookeeper/conf)下,新增zoo.cfg 配置文件,配置内容如下:
dataDir=/data # 保存zookeeper中的数据
clientPort=2181 # 客户端连接端口,通常不做修改
dataLogDir=/datalog
tickTime=2000 # 通信心跳时间
initLimit=5 # LF(leader - follower)初始通信时限
syncLimit=2 # LF 同步通信时限
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
admin.enableServer=true
server.1=localhost:2888:3888;2181
- 进入容器内部,验证容器状态
# 方式一:这样的话,直接登录到容器时,进入到 zkCli中
docker run -it --rm --link zookeeper:zookeeper zookeeper zkCli.sh -server zookeeper# 方式二:先进入容器,再进入到 zkCli中
docker exec -it zookeeper bash // 只登录容器,不登录 zkCli
./bin/zkCli.sh // 执行脚本新建一个Client,即进入容器
六、Docker安装Dubbo Admin
我们在搭建Dubbo框架时,需要安装一个可视化工具——Dubbo Admin来管理服务。Dubbo Admin 管理平台,是一个前后端分离的项目,前端技术使用vue,后端技术使用springboot。Dubbo Admin会从注册中心中获取到所有的提供者 / 消费者进行配置管理,它具有路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能。
- 首先到dockerhub上搜索dubbo-admin的镜像
2. 可以看到两个引用较高的镜像源,第一个是apache官方的,我们知道Dubbo是阿里开发的,但是现在已经捐献给apache,第二个镜像源就是Dubbo阿里原作者提供的,这里因为第一个更新更及时,我们选择第一个镜像源。
# 拉取dubbo-admin的镜像
docker pull apache/dubbo-admin
- 因为dubbo-admin要连接zookeeper,这里我两者都是使用docker安装的,为了保证他们能够通过名字久能正常通信,要将其连接到同一个网络下
首先建立一个桥接网络zk
docker network create -d bridge zk
- 因为上一节已经运行了zookeeper容器,这里直接将zookeeper加入到网络为zk中
# 将容器加入到网络中
docker network connect [网络] [容器]
- 查看zookeeper容器ip
docker network inspect zk
- 创建dubbo-admin容器,指定网络为zk,并设置zookeeper为上述查询出来的地址
# 运行dubbo-admin容器
docker run -d --name dubbo-admin --network zk -p 8083:38080 -e admin.registry.address=zookeeper://172.18.0.2:2181 -e admin.config-center=zookeeper://172.18.0.2:2181 -e admin.metadata-report.address=zookeeper://172.18.0.2:2181 apache/dubbo-admin# 验证容器是否正常运行
dokcer ps
- 因为我已经把端口映射为8083了,所以直接访问ip+port,输入账号密码登录即可,初始密码默认为root/root。
登陆跳转这个页面,说明安装成功。
在安装过程中,我们很有可能会遇到各种问题,这里作者总结几点安装过程中踩坑的点,大家需要注意一下。
注意1:
大家拉取不同的镜像时,docker运行dubbo-admin容器情况是不一样的,建议直接拉取apache的,以免容器运行后直接退出,不方便排查问题.。
注意2:
若容器正常运行,建议利用docker logs 容器id命令去看一下日志,确认一下这个dubbo-admin里的tomcat容器监听的端口号。
注意3:
使用浏览器访问时,若访问不通,请确认防火墙中对应端口是否放开,请确认云服务器控制台中的安全组里的端口是否放开。
七、SpringBoot项目整合Dubbo
7.1 创建生产者服务
dubbo-provider代表服务生产者,首先,我们先把服务端的接口写好,因为其实dubbo的作用简单来说就是给消费端提供接口。
7.1.1 项目路径总览
项目结构:
- api 模块——接口、实体等定义
- center 模块——真正的服务提供者
注意:
api模块和center模块是最基本的模块,api模块就是服务暴露出去的dubbo接口的契约jar包,就是一个SDK包,它通常由接口定义和相应的实体类组成;而center模块是api模块中定义的接口的真正的实现逻辑,除此之外,我们在实际开发中可能还有其他模块,比如common模块用来提供公共的通用的类,比如web模块用来提供前端可以调用的restful接口。
7.1.2 pom.xml依赖引入
7.1.2.1 生产者父pom依赖
<?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><groupId>com.wasteland.blogsourcecode</groupId><artifactId>dubbo-provider</artifactId><version>0.0.1-SNAPSHOT</version><name>dubbo-provider</name><description>dubbo-provider</description><!--打包方式:pom--><packaging>pom</packaging><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.4.2</spring-boot.version></properties><!--子模块引用--><modules><module>dubbo-provider-api</module><module>dubbo-provider-center</module></modules><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.wasteland.blogsourcecode.DubboProviderApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
7.1.2.2 api 模块pom依赖
<?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><groupId>com.wasteland.blogsourcecode</groupId><artifactId>dubbo-provider-api</artifactId><version>0.0.1-SNAPSHOT</version><name>dubbo-provider-api</name><description>dubbo-provider-api</description><!--打包方式:jar--><packaging>jar</packaging><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.4.2</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version></plugin></plugins></build></project>
7.1.2.3 center 模块pom依赖
<?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><groupId>com.wasteland.blogsourcecode</groupId><artifactId>dubbo-provider-center</artifactId><version>0.0.1-SNAPSHOT</version><name>dubbo-provider-center</name><description>dubbo-provider-center</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.4.2</spring-boot.version></properties><dependencies><!-- dubbo provider 启动不成功的主要问题在这里,没有添加 spring-boot-starter-web 依赖,所以启动日志里一直没有显示“o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8087 (http)” 这行日志输出 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 这个是定义的接口包,在 provider 和 consumer 都需要引用的 --><dependency><groupId>com.wasteland.blogsourcecode</groupId><artifactId>dubbo-provider-api</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-dependencies-zookeeper</artifactId><version>2.7.4.1</version><type>pom</type><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><!-- dubbo 2.7.x引入--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.4.1</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.wasteland.blogsourcecode.DubboProviderCenterApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
7.1.3 不同配置实现方式
我们在把Dubbo接口注册到注册中心时,有很多种不同的使用方式,这里就只介绍两种常用的方式:xml配置
和注解配置
两种。而在使用不同的配置进行Dubbo接口注册时,服务定义阶段(即定义SDK包)都是一样的,api模块是通用的,它不仅会被自己服务所使用,它也会被外部依赖方所使用。因此,在编写完api模块后,需要使用mvn install
命令去把api模块的jar包发布到仓库里(自己本地测试就是本地中心仓库,在公司里实战开发时,会需要将其发布到公司的中央仓库里)。
服务定义: 定义一个名为 UserService的标准 Java 接口作为 Dubbo 服务。
创建UserService接口,并创建sayHello方法
package com.wasteland.blogsourcecode.service;/*** @author wasteland* @create 2025-05-06*/
public interface UserService {public String sayHello();
}
7.1.3.1 xml配置
@ImportResource注解和XML配置文件暴露服务: 使用@ImportResource注解去加载定义在类路径下的xml文件。
服务实现: 定义了服务接口之后,可以在服务端这一侧定义对应的业务逻辑实现,这里实现 UserService 接口。
创建UserServiceImpl实现类,并实现sayHello方法
package com.wasteland.blogsourcecode.dubboprovider.impl;import com.wasteland.blogsourcecode.dubboprovider.UserService;
import org.apache.dubbo.config.annotation.Service;/*** @author wasteland* @create 2025-05-06*/
public class UserServiceImpl implements UserService {@Overridepublic String sayHello() {return "Hello Wasteland!";}
}
package com.wasteland.blogsourcecode;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;@SpringBootApplication
@ImportResource("classpath:/provider.xml")
public class DubboProviderCenterApplication {public static void main(String[] args) {SpringApplication.run(DubboProviderCenterApplication.class, args);}}
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="dubbo-zookeeper-producer1" owner="wasteland"></dubbo:application><dubbo:monitor protocol="registry"/><!--dubbo这个服务所要暴露的服务地址所对应的注册中心--><!--<dubbo:registry address="N/A"/>--><dubbo:registry address="zookeeper://zookeeper的ip:2181" check="false"/><!--当前服务发布所依赖的协议;webservice、Thrift、Hessain、http--><dubbo:protocol name="dubbo" port="-1"/><!--服务发布的配置,需要暴露的服务接口--><dubbo:serviceinterface="com.wasteland.blogsourcecode.service.UserService"ref="providerService"/><!--Bean bean定义--><bean id="providerService" class="com.wasteland.blogsourcecode.provider.UserServiceImpl"/></beans>
说明:
- 上面的文件其实就是类似 spring 的配置文件,而且,dubbo 底层就是 spring。
- 节点:
dubbo:application
就是整个项目在分布式架构中的唯一名称,可以在name属性中配置,另外还可以配置owner字段,表示属于谁。
下面的参数是可以不配置的,这里配置是因为出现了端口的冲突,所以配置。 - 节点:
dubbo:monitor
监控中心配置, 用于配置连接监控中心相关信息,可以不配置,不是必须的参数。 - 节点:
dubbo:registry
配置注册中心的信息,比如,这里我们可以配置 zookeeper 作为我们的注册中心。address 是注册中心的地址,这里我们配置的是 N/A 表示由 dubbo 自动分配地址。或者说是一种直连的方式,不通过注册中心。 - 节点:
dubbo:protocol
服务发布的时候 dubbo 依赖什么协议,可以配置 dubbo、webservice、http等协议。 - 节点:
dubbo:service
这个节点就是我们的重点了,当我们服务发布的时候,我们就是通过这个配置将我们的服务发布出去的。interface 是接口的包路径,ref 是第 ⑦ 点配置的接口的 bean。 - 最后,我们需要像配置spring的接口一样,配置接口的 bean。
7.1.3.2 注解配置
@EnableDubbo 注解和YML配置文件暴露服务: @EnableDubbo 注解必须配置,否则将无法加载 Dubbo 注解定义的服务。
服务实现: 定义了服务接口之后,可以在服务端这一侧定义对应的业务逻辑实现,这里实现 UserService 接口。
创建UserServiceImpl实现类,并实现sayHello方法
package com.wasteland.blogsourcecode.dubboprovider.impl;import com.wasteland.blogsourcecode.dubboprovider.UserService;
import org.apache.dubbo.config.annotation.Service;/*** 导入dubbo的service注解,将这个类提供的方法对外发布,注册到注册中心中* @author wasteland* @create 2025-05-06*/
@Service
public class UserServiceImpl implements UserService {@Overridepublic String sayHello() {return "Hello Wasteland!";}
}
package com.wasteland.blogsourcecode;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubbo
public class DubboProviderApplication {public static void main(String[] args) {SpringApplication.run(DubboProviderApplication.class, args);}
}
注意:
Dubbo3.x之前是使用的@Service,注意这个@Service注解是dubbo包下的,不是spring包下的,而在Dubbo3.x之后为作区分,注解被更改为@DubboService,下面消费者中使用的@Reference和@Reference也同样如此。Spring Boot 注解默认只会扫描 main 类所在的 package,如果服务定义在其它 package 中,需要增加配置 EnableDubbo(scanBasePackages = {“org.apache.dubbo.springboot.demo.provider”})。
yml文件配置:
dubbo:registry:address: zookeeper://zookeeper的ip:2181 #自己的zookeeper服务器的IP:默认端口号application:name: dubbo-zookeeper-producer1 #注册进去的名字protocol:name: dubbo #设置类型port: -1 #因为dubbo的服务器端口号是不能唯一的,所以,设置为-1会帮我们自动改变端口号config-center:timeout: 120000 #超时时间 (毫秒)server:port: 9001
7.2 创建消费者服务
7.2.1 项目路径总览
在公司实战开发中,因为消费者服务同样也有可能是生产者服务,能够提供dubbo接口给外部调用,因此完整版模块组成和前面的生产者模块是一样的,而这里只是为了测试简单,就只写了一个模块。
7.2.2 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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.wasteland.blogsourcecode</groupId><artifactId>dubbo-consumer</artifactId><version>0.0.1-SNAPSHOT</version><name>dubbo-consumer</name><description>dubbo-consumer</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.4.2</spring-boot.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</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 这个是定义的接口包,在 provider 和 consumer 都需要引用的 --><dependency><groupId>com.wasteland.blogsourcecode</groupId><artifactId>dubbo-provider-api</artifactId><version>0.0.1-SNAPSHOT</version><scope>compile</scope></dependency><!-- dubbo-zookeeper--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-dependencies-zookeeper</artifactId><version>2.7.4.1</version><type>pom</type><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><!-- dubbo 2.7.x引入--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.4.1</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.wasteland.blogsourcecode.DubboConsumerApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
7.2.3 不同配置实现方式
7.2.3.1 xml配置
@ImportResource注解和XML配置文件引用远程服务: 使用@ImportResource注解去加载定义在类路径下的xml文件。
服务调用: 由于引入了dubbo接口的SDK包,现在就可以进行远程调用了。
创建UserController控制器类,直接调用UserService里的方法。
package com.wasteland.blogsourcecode.dubboconsumer;import com.wasteland.blogsourcecode.service.UserService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** @author wasteland* @create 2025-05-06*/
@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@RequestMapping("/sayHello")public String sayHello() {return userService.sayHello();}
}
package com.wasteland.blogsourcecode;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;@SpringBootApplication
@ImportResource("classpath:/consumer.xml")
public class DubboConsumerApplication {public static void main(String[] args) {SpringApplication.run(DubboConsumerApplication.class, args);}}
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="dubbo-zookeeper-consumer1" owner="wasteland"/><!--dubbo这个服务所要暴露的服务地址所对应的注册中心--><dubbo:registry address="zookeeper://118.145.205.205:2181" check="false"/><!--生成一个远程服务的调用代理--><dubbo:reference id="providerService"interface="com.wasteland.blogsourcecode.service.UserService"check="false"/>
</beans>
7.2.3.2 注解配置
@EnableDubbo 注解和YML配置文件引用远程服务:@EnableDubbo 注解必须配置,否则将无法加载 Dubbo 注解定义的服务。
服务调用: 由于引入了dubbo接口的SDK包,现在就可以进行远程调用了。
创建UserController控制器类,直接调用UserService里的方法。
package com.wasteland.blogsourcecode.dubboconsumer;import com.wasteland.blogsourcecode.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author wasteland* @create 2025-05-06*/
@RestController
@RequestMapping("/user")
public class UserController {@Referenceprivate UserService userService;@RequestMapping("/sayHello")public String sayHello() {return userService.sayHello();}}
package com.wasteland.blogsourcecode;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubbo
public class DubboProviderApplication {public static void main(String[] args) {SpringApplication.run(DubboProviderApplication.class, args);}
}
yml文件配置:
dubbo:registry:address: zookeeper://zookeeper的ip:2181 #自己的zookeeper服务器的IP:默认端口号application:name: dubbo-zookeeper-consumer1 #注册进去的名字protocol:name: dubbo #设置类型port: -1 #因为dubbo的服务器端口号是不能唯一的,所以,设置为-1会帮我们自动改变端口号config-center:timeout: 120000 #超时时间 (毫秒)server:port: 8083
7.3 测试验证
- 先启动zookeeper,因为前面是使用的Docker部署的,直接运行Docker容器即可
- 再启动服务生产者
- 再启动服务消费者
- 最后访问http://localhost:8083/user/sayHello查看效果
7.3.1 云服务器中zookeeper客户端验证
我们可以连接到云服务器进入到zookeeper容器内部中进行验证,命令如下:
# 1.进入容器内部
docker exec -it zookeeper bash // 只登录容器,不登录 zkCli# 2.连接客户端
./bin/zkCli.sh # 3.用以下命令来查询Dubbo服务
ls /dubbo# 4.查看特定服务的消费者
ls /dubbo/<服务名>/consumers# 5.查看特定服务的生产者
ls /dubbo/<服务名>/providers
这里有意思的是它暴露的url
,我们可以来分析一下。因为暴露出的是已经经过URL编码后的,不好分析,我们对其进行一个解码,解码后如下:
Dubbo 暴露的 URL
dubbo://192.168.1.3:20880/com.wasteland.blogsourcecode.service.UserService?anyhost=true&application=dubbo-zookeeper-producer1&bean.name=com.wasteland.blogsourcecode.service.UserService&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.wasteland.blogsourcecode.service.UserService&methods=sayHello&owner=wasteland&pid=10392&release=2.7.4.1&side=provider×tamp=1747064723475
分析如下:
- 首先,在形式上我们发现,其实这么牛逼的
dubbo
也是用类似于http
的协议发布自己的服务的,只是这里我们用的是dubbo协议。 dubbo://192.168.1.3:20880/com.wasteland.blogsourcecode.service.UserService
上面这段链接就是 ? 之前的链接,构成:协议://ip:端口/接口,发现是不是也没有什么神秘的。anyhost=true&application=dubbo-zookeeper-producer1&bean.name=com.wasteland.blogsourcecode.service.UserService&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.wasteland.blogsourcecode.service.UserService&methods=sayHello&owner=wasteland&pid=10392&release=2.7.4.1&side=provider×tamp=1747064723475
? 之后的字符串,分析后你发现,这些都是在前文provider.xml中配置的字段,然后通过 & 拼接而成的,闻到了 http 的香味了吗?
Dubbo 数据在Zookeeper中的组织形式
Dubbo 使用 Zookeeper 用于服务的注册发现和配置管理,在 Zookeeper 中数据的组织由下图所示:
首先,所有 Dubbo 相关的数据都组织在 /dubbo 的根节点下。
二级目录是服务名,如 com.wasteland.blogsourcecode.service.UserService。
三级目录有两个子节点,分别是 providers 和 consumers,表示该服务的提供者和消费者。
四级目录记录了与该服务相关的每一个应用实例的 URL 信息,在 providers 下的表示该服务的所有提供者,而在 consumers 下的表示该服务的所有消费者。举例说明,com.wasteland.blogsourcecode.service.UserService 的服务提供者在启动时将自己的 URL 信息注册到 /dubbo/com.wasteland.blogsourcecode.service.UserService/providers 下;同样的,服务消费者将自己的信息注册到相应的 consumers 下,同时,服务消费者会订阅其所对应的 providers 节点,以便能够感知到服务提供方地址列表的变化。
7.3.2 Dubbo Admin控制台验证
因为前文中已经在云服务器上利用Docker安装了Dubbo Admin,这里直接进入到Dubbo Admin管理页面上确认对应dubbo接口是否注册成功。
八、其他高级特性
8.1 启动时检查
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check=“true”。但是,有的时候,我们并不是都需要启动时就检查的,比如测试的时候,我们是需要更快速的启动,所以,这种场景的时候,我们是需要关闭这个功能的。下面,我们看看如何使用这个功能。
在服务端注册的时候(客户端注册时同样适用);
<dubbo:registry protocol="zookeeper" address="localhost:2181,localhost:2182,localhost:2183" check="false"/>
在客户端引用服务端服务的时候;
<dubbo:reference check="false" id="providerService"interface="com.wasteland.blogsourcecode.service.UserService"/>
8.2 集群容错
dubbo 也是支持集群容错的,同时也有很多可选的方案,其中,默认的方案是 failover,也就是重试机制。
首先,我们先把所有的容错机制都整理一遍,然后再看看使用。
集群模式 | 说明 | 使用方法 |
---|---|---|
Failover Cluster | 失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。 | cluster=“xxx” xxx:集群模式名称 ,例如cluster=“failover” |
Failfast Cluster | 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。 | |
Failsafe Cluster | 失败安全,出现异常时,直接忽略。 | |
Failback Cluster | 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。 | |
Forking Cluster | 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。 | |
Broadcast Cluster | 广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。 |
使用实例
在发布服务或者引用服务的时候设置
<!--服务发布的配置,需要暴露的服务接口-->
<dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService"/>
<dubbo:reference cluster="failover" retries="2" check="false" id="providerService"interface="com.wasteland.blogsourcecode.service.UserService"/>
8.3 负载均衡
dubbo调用是支持负载均衡的,这里总结一下dubbo支持的负载均衡的一些方案及使用方法。
负载均衡模式 | 说明 | 使用方法 |
---|---|---|
Random LoadBalance | 随机 按权重设置随机概率 | <dubbo:service loadbalance="xxx"/> xxx:负载均衡方法 |
RoundRobin LoadBalance | 轮询 按公约后的权重设置轮询比率。 | |
LeastActive LoadBalance | 最少活跃调用数 相同活跃数的随机,活跃数指调用前后计数差。 | |
ConsistentHash LoadBalance | 一致性 Hash 相同参数的请求总是发到同一提供者。 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 |
8.4 直连提供者
在开发和测试时,我们可以绕过注册中心,直接指定服务提供者,所以这种情况下,我们需要直接连接服务端的地址。
<dubbo:reference id="providerService"interface="com.wasteland.blogsourcecode.service.UserService"url="dubbo://服务端ip:20880/com.wasteland.blogsourcecode.service.UserService"/>
说明:可以看到,只要在消费端在dubbo:reference
节点使用url给出服务端的方法即可。
8.5 多协议机制
在前面我们使用的协议都是 dubbo
协议,但是 dubbo 除了支持这种协议外还支持其他的协议,比如,rmi
、hessian
、triple
等,另外,而且还可以用多种协议同时暴露一种服务。
8.5.1 多端口多协议
先声明多种协议
<!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http--><dubbo:protocol name="dubbo" port="20880"/><dubbo:protocol name="rmi" port="1099" />
然后在发布接口的时候使用具体协议
<!--服务发布的配置,需要暴露的服务接口--><dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" protocol="dubbo"/><dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" protocol="rmi"/>
对于消费端而言,如果用户没有明确配置,默认情况下框架会自动选择 dubbo 协议调用。
8.5.2 单端口多协议
声明协议和上面的方式一样,在发布接口的时候有一点不一样。
<dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" protocol="rmi,dubbo"/>
说明:protocol
属性,可以用,
隔开,使用多种协议。
8.6 多注册中心
Dubbo 支持同一服务向多注册中心同时注册,或者不同服务分别注册到不同的注册中心上去,甚至可以同时引用注册在不同注册中心上的同名服务。
服务端多注册中心发布服务
一个服务可以在不同的注册中心注册,当一个注册中心出现问题时,可以用其他的注册中心。
注册
<!--多注册中心-->
<dubbo:registry protocol="zookeeper" id="reg1" timeout="10000" address="localhost:2181"/>
<dubbo:registry protocol="zookeeper" id="reg2" timeout="10000" address="localhost:2182"/>
<dubbo:registry protocol="zookeeper" id="reg3" timeout="10000" address="localhost:2183"/>
发布服务
<!--服务发布的配置,需要暴露的服务接口-->
<dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" registry="reg1"/>
<dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" protocol="rmi" registry="reg2"/>
说明:使用registry="reg2"
指定该接口使用的注册中心,同时也可以使用多个,
隔开,例如registry="reg1,,reg2"
。
消费端多注册中心引用服务
首先,先向不同注册中心注册;
<!--多注册中心-->
<dubbo:registry protocol="zookeeper" id="reg1" timeout="10000" address="localhost:2181"/>
<dubbo:registry protocol="zookeeper" id="reg2" timeout="10000" address="localhost:2182"/>
<dubbo:registry protocol="zookeeper" id="reg3" timeout="10000" address="localhost:2183"/>
其次,不同的消费端服务引用使用不同的注册中心;
<!--不同的服务使用不同的注册中心-->
<dubbo:reference cluster="failover" retries="2" check="false" id="providerService"interface="com.wasteland.blogsourcecode.service.UserService" registry="reg1"/>
<dubbo:reference cluster="failover" retries="2" check="false" id="providerService2"interface="com.wasteland.blogsourcecode.service.UserService" registry="reg2"/>
说明:上面分别使用注册中心1和注册中心2。
8.7 多版本
不同的服务是有版本不同的,版本可以更新并且升级,同时,不同的版本之间是不可以调用的。
<!--服务发布的配置,需要暴露的服务接口--><dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" registry="reg1" version="1.0.0"/><dubbo:service cluster="failover" retries="2"interface="com.wasteland.blogsourcecode.service.UserService"ref="providerService" protocol="rmi" registry="reg2" version="1.0.0"/>
8.8 日志管理
dubbo
也可以将日志信息记录或者保存到文件中的。
1、使用accesslog
输出到log4j
<dubbo:protocol accesslog="true" name="dubbo" port="20880"/><dubbo:protocol accesslog="true" name="rmi" port="1099" />
2、输出到文件
<dubbo:protocol accesslog="http://localhost/log.txt" name="dubbo" port="20880"/><dubbo:protocol accesslog="http://localhost/log2.txt" name="rmi" port="1099" />
九、总结
本文介绍了Dubbo的基本概念、Dubbo与Spring Cloud的关系及SpringBoot结合Dubbo的实战演练。除此之外,因为本文中选择的是
Dubbo与Zookeeper相结合来实现服务发现的功能,本文中还介绍了如何使用Docker部署Zookeeper容器。相信本篇文章已经能够让你对Dubbo有基本的了解与使用,在后面的文章中会详细分析Dubbo实现远程调用的原理。
相关文章:
Dubbo:Docker部署Zookeeper、Dubbo Admin的详细教程和SpringBoot整合Dubbo的实战与演练
🪁🍁 希望本文能给您带来帮助,如果有任何问题,欢迎批评指正!🐅🐾🍁🐥 文章目录 一、背景二、Dubbo概述三、Dubbo与SpringCloud的关系四、Dubbo技术架构五、Docker安装Zoo…...
Windows 上安装下载并配置 Apache Maven
1. 下载 Maven 访问官网: 打开 Apache Maven 下载页面。 选择版本: 下载最新的 Binary zip archive(例如 apache-maven-3.9.9-bin.zip)。 注意:不要下载 -src 版本(那是源码包)。 2. 解压 Mave…...
Unbuntu 命令
Ubuntu 命令速查表 分类命令功能描述示例/常用选项文件与目录ls列出目录内容ls -a(显示隐藏文件); ls -lh(详细列表易读大小) cd切换目录cd ~(主目录); cd ..(上级…...
机器学习-人与机器生数据的区分模型测试-数据处理1
附件为训练数据,总体的流程可以作为参考。 导入依赖 import pandas as pd import os import numpy as np from sklearn.model_selection import train_test_split,GridSearchCV from sklearn.ensemble import RandomForestClassifier,VotingClassifier from skle…...
【Linux】进程间通信(一):认识管道
📝前言: 这篇文章我们来讲讲进程间通信——认识管道 🎬个人简介:努力学习ing 📋个人专栏:Linux 🎀CSDN主页 愚润求学 🌄其他专栏:C学习笔记,C语言入门基础&a…...
AMD Vivado™ 设计套件生成加密比特流和加密密钥
概括 重要提示:有关使用AMD Vivado™ Design Suite 2016.4 及更早版本进行 eFUSE 编程的重要更新,请参阅AMD设计咨询 68832 。 本应用说明介绍了使用AMD Vivado™ 设计套件生成加密比特流和加密密钥(高级加密标准伽罗瓦/计数器模式 (AES-GCM)…...
第三十四节:特征检测与描述-SIFT/SURF 特征 (专利算法)
一、特征检测:计算机视觉的基石 在计算机视觉领域中,特征检测与描述是实现图像理解的核心技术。就像人类通过识别物体边缘、角点等特征来认知世界,算法通过检测图像中的关键特征点来实现: 图像匹配与拼接 物体识别与跟踪 三维重建 运动分析 其中,SIFT(Scale-Invariant F…...
【AI】SpringAI 第二弹:基于多模型实现流式输出
目录 一、基于多模型实现流式输出 1.1 什么是流式输出 1.2 多模型引入 1.3 代码实现 1.3.1 流式输出的API介绍 1.3.2 Flux 源码分析 二、了解 Reactor 模型 三、SSE 协议 一、基于多模型实现流式输出 1.1 什么是流式输出 流式输出(Streaming Output)是指数据在生成过程…...
SQL语句执行问题
执行顺序 select [all|distinct] <目标列的表达式1> AS [别名], <目标列的表达式2> AS [别名]... from <表名1或视图名1> [别名],<表名2或视图名2> [别名]... [where <条件表达式>] [group by <列名>] [having <条件表达式>] [ord…...
模型量化AWQ和GPTQ哪种效果好?
环境: AWQ GPTQ 问题描述: 模型量化AWQ和GPTQ哪种效果好? 解决方案: 关于AWQ(Adaptive Weight Quantization)和GPTQ(Generative Pre-trained Transformer Quantization)这两种量化方法的…...
Github 2025-05-17 Rust开源项目日报 Top10
根据Github Trendings的统计,今日(2025-05-17统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General Public Li…...
借助 CodeBuddy 打造我的图标预览平台 —— IconWiz 开发实录
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 想做一款自己的图标预览平台 这段时间我在做前端 UI 设计时,常常需要到处找图标素材,复…...
KL散度 (Kullback-Leibler Divergence)
KL散度,也称为相对熵 (Relative Entropy),是信息论中一个核心概念,用于衡量两个概率分布之间的差异。给定两个概率分布 P ( x ) P(x) P(x) 和 Q ( x ) Q(x) Q(x)(对于离散随机变量)或 p ( x ) p(x) p(x) 和 q ( x …...
【Linux网络】NAT和代理服务
NAT 之前我们讨论了,IPv4协议中,IP地址数量不充足的问题。 原始报文途径路由器WAN口时,对报文中的源IP进行替换的过程,叫做NAT。 NAT技术当前解决IP地址不够用的主要手段,是路由器的一个重要功能: NAT能…...
DeepSeek赋能电商,智能客服机器人破解大型活动人力困境
1. DeepSeek 与电商客服结合的背景 1.1 电商行业客服需求特点 电商行业具有独特的客服需求特点,这些特点决定了智能客服机器人在该行业的必要性和重要性。 高并发性:电商平台的用户数量庞大,尤其是在促销活动期间,用户咨询量会…...
Unity序列化字段、单例模式(Singleton Pattern)
一、序列化字段 在Unity中,序列化字段是一个非常重要的概念,主要用于在Unity编辑器中显示和编辑类的成员变量,或者在运行时将对象的状态保存到文件或网络中。 1.Unity序列化字段的作用 在编辑器中显示和编辑字段:默认情况下&…...
一个可拖拉实现列表排序的WPF开源控件
从零学习构建一个完整的系统 推荐一个可通过拖拉,来实现列表元素的排序的WPF控件。 项目简介 gong-wpf-dragdrop是一个开源的.NET项目,用于在WPF应用程序中实现拖放功能,可以让开发人员快速、简单的实现拖放的操作功能。 可以在同一控件内…...
hadoop.proxyuser.代理用户.授信域 用来干什么的
在Hadoop的core-site.xml文件中存在三个可选配置,如下 <property><name>hadoop.proxyuser.root.hosts</name><value>*</value> </property> <property><name>hadoop.proxyuser.root.groups</name><value…...
python 自动化教程
文章目录 前言整数变量字符串变量列表变量算术操作比较操作逻辑操作if语句for循环遍历列表while循环定义函数调用函数导入模块使用模块中的函数启动Chrome浏览器打开网页定位元素并输入内容提交表单关闭浏览器发送GET请求获取网页内容使…...
C++学习:六个月从基础到就业——C++11/14:列表初始化
C学习:六个月从基础到就业——C11/14:列表初始化 本文是我C学习之旅系列的第四十三篇技术文章,也是第三阶段"现代C特性"的第五篇,主要介绍C11/14中的列表初始化特性。查看完整系列目录了解更多内容。 引言 在C11之前&a…...
城市静音革命:当垃圾桶遇上缓冲器
缓冲垃圾桶的核心原理是通过机械或液压装置实现垃圾桶盖的缓慢闭合,包含以下技术要点:能量吸收机制液压式:通过活塞挤压油液产生阻尼力,将动能转化为热能耗散弹簧式:利用弹性变形储存和释放能量,配合摩…...
数据库的规范化设计方法---3种范式
第一范式(1NF):确保表中的每个字段都是不可分割的基本数据项。 第二范式(2NF):在满足1NF的基础上,确保非主属性完全依赖于主键。 第三范式(3NF):在满足2NF的基…...
p024基于Django的网上购物系统的设计与实现
开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 商品类型管理 商品信息管理 系统管理 订单管理…...
C++跨平台开发:挑战与应对策略
C跨平台开发:挑战与应对策略 在如今设备多样、操作系统碎片化的开发环境中,跨平台能力已成为衡量软件生命力与团队工程效率的重要指标。C 作为高性能系统级语言,在游戏引擎、嵌入式系统、实时渲染等领域依旧坚挺。然而,实现“一次…...
Kotlin 作用域函数(let、run、with、apply、also)对比
Kotlin 的 作用域函数(Scope Functions) 是简化代码逻辑的重要工具,它们通过临时作用域为对象提供更简洁的操作方式。以下是 let、run、with、apply、also 的对比分析: 一、核心区别对比表 函数上下文对象引用返回值是否扩展函数…...
JavaScript性能优化实战(11):前沿技术在性能优化中的应用
引言 随着Web应用复杂度和性能需求不断提高,传统的JavaScript优化技术已经无法满足某些高性能计算场景的需求。本文将深入探讨前沿Web技术如何突破JavaScript的性能瓶颈,为Web应用提供接近原生应用的性能体验。从底层计算到图形渲染,从并发处理到动画优化,我们将通过实际案…...
数据结构【AVL树】
AVL树 1.AVL树1.AVL的概念2.平衡因子 2.AVl树的实现2.1AVL树的结构2.2AVL树的插入2.3 旋转2.3.1 旋转的原则 1.AVL树 1.AVL的概念 AVL树可以是一个空树。 它的左右子树都是AVL树,且左右子树的高度差的绝对值不超过1。AVL树是一颗高度平衡搜索二叉树,通…...
电动调节V型球阀:行业应用与材质选择全解析
电动调节V型球阀:行业应用与材质选择全解析 作为工业自动化控制中的关键设备,电动调节V型球阀凭借其独特的结构设计与高性能调节能力,在石油、化工、造纸等高要求领域广泛应用。本文将从核心功能、行业应用场景、材质选择要点等方面深入解析…...
页面上如何显示特殊字符、Unicode字符?
在前端开发中,显示特殊字符通常涉及到HTML实体(HTML Entities)或 Unicode 字符的使用。以下是一些常见的方法来处理特殊字符的显示: 1、HTML实体: HTML为一些常见的特殊字符提供了预定义的实体。例如,要显…...
桌面端进程通信
以下是关于 Electron 桌面端进程通信的基本知识点总结: 一、Electron 进程模型基础 1. 进程类型与职责 进程类型职责权限主进程(Main)创建窗口、系统级操作、IPC中枢完全Node.js访问权限渲染进程(Renderer)展示Web内容、UI交互默认受限(可配置开启Node.js)预加载脚本(Prelo…...
vue2 切换主题色以及单页面好使方法
今天要新增一个页面要根据不同公司切换不同页面主题色,一点一点来,怎么快速更改 el-pagination 分页组件主题色。 <el-pagination :page-size"pageSize" :pager-count"pageCount"layout"sizes, prev, pager, next, jumper,…...
三层固定实体架构:高效实现图上的检索增强生成(RAG)
知识图谱正在成为跨各个领域组织和检索信息的强大工具。它们越来越多地与机器学习和自然语言处理技术相结合,以增强信息检索和推理能力。在本文中,我介绍了一种用于构建知识图谱的三层架构,结合了固定本体实体、文档片段和提取的命名实体。通过利用嵌入和余弦相似度,这种方…...
pnpm 与 npm 的核心区别
以下是 pnpm 与 npm 的核心区别总结,涵盖依赖管理、性能、安全性等关键维度: 1. 依赖存储机制 • npm: 每个项目的依赖独立存储于 node_modules,即使多个项目使用相同版本的包,也会重复下载和存储。例如,1…...
NVMe简介6之PCIe事务层
PCIe的事务层连接了PCIe设备核心与PCIe链路,这里主要基于PCIe事务层进行分析。事务层采用TLP传输事务,完整的TLP由TLPPrefix、TLP头、Payload和TLP Digest组成。TLP头是TLP中最关键的部分,一般由三个或四个双字的长度,其格式定义如…...
【C++详解】string各种接口如何使用保姆级攻略
文章目录 一、string介绍二、string使用构造函数析构函数赋值运算符重载string的遍历修改方法1、下标[]2、迭代器3、范围for 迭代器使用详解const迭代器反向迭代器(reverse) Capacity(容量相关)size/lengthmax_sizecapacityclear/emptyshrink_to_fit(缩容)reserve(扩…...
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
requestIdleCallback 核心作用 requestIdleCallback 是浏览器提供的 API,用于将非关键任务延迟到浏览器空闲时段执行,避免阻塞用户交互、动画等关键任务,从而提升页面性能体验。 基本语法 const handle window.requestIdleCallback(callb…...
QML鼠标事件和按键事件
1 鼠标事件 1.1 MouseArea组件 在QML中,鼠标事件主要通过MouseArea元素处理,它是用于检测和响应鼠标交互的核心组件。常用属性 cursorShape: 光标形状acceptedButtons: 设置响应鼠标的哪些按键事件,默认为鼠标左键 Qt.LeftButton࿱…...
Animaster:一次由 CodeBuddy 主导的 CSS 动画编辑器诞生记
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 起心动念:我想要一个动画编辑器 那天我突然想到,如果能有一个简单好用的 CSS 动画编辑…...
Git 版本控制系统入门指南
Git 版本控制系统入门指南 一、Git 基础概念 1. 什么是 Git? Git 是一个分布式版本控制系统,它可以: 跟踪文件变化协调多人协作管理代码版本支持离线工作保证数据完整性 2. Git 的特点 分布式架构快速分支操作完整历史记录数据完整性保…...
GitHub 趋势日报 (2025年05月16日)
本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1TapXWorld/ChinaTextbookPDF教材。⭐ 4792⭐ 19814Roff2xming521/WeClone&…...
C/C++之内存管理
1. 内存分布 我们定义的变量对于电脑来说也叫数据,同时电脑也会把这些数据分为不同的类型,分别是局部数据,静态数据,全局数据,常量数据和动态申请数据。 在 C 中,各类数据存储位置如下: • 局…...
GitHub文档加载器设计与实现
文章结构: 目录 GitHub文档加载器设计与实现 引言 架构设计 主要组件 核心功能 文档加载流程 加载单个文件 加载目录内容 错误处理与健壮性 分支回退策略 文件类型和大小限制 安全性考虑 SSL证书验证 使用示例 基本使用 测试环境配置 最佳实践 结…...
历史数据分析——中证白酒
简介 中证白酒指数选取涉及白酒生产业务相关上市公司证券作为指数样本,为投资者提供更多样化的投资标的。 估值 中证白酒总体的PB是5.26,在过去十年间位于23.76%,属于较低的水平。 中证白酒总体的PE是20.13,在过去十年间,位于14.24%,属于较低的水平。 从估值的角度似…...
PHP8.0版本导出excel失败
环境:fastadmin框架,不是原版接手的项目。PHP8.0,mysql5.7. code // 创建一个新的 Spreadsheet 对象 $spreadsheet new Spreadsheet(); $worksheet $spreadsheet->getActiveSheet();// 设置表头 $worksheet->setCellValue(A1, ID); $worksheet…...
Seata源码—5.全局事务的创建与返回处理二
大纲 1.Seata开启分布式事务的流程总结 2.Seata生成全局事务ID的雪花算法源码 3.生成xid以及对全局事务会话进行持久化的源码 4.全局事务会话数据持久化的实现源码 5.Seata Server创建全局事务与返回xid的源码 6.Client获取Server的响应与处理的源码 7.Seata与Dubbo整合…...
mac-M系列芯片安装软件报错:***已损坏,无法打开。推出磁盘问题
因为你安装的软件在Intel 或arm芯片的mac上没有签名导致。 首先打开任何来源操作 在系统设置中配置,如下图: 2. 然后打开终端,输入: sudo spctl --master-disable然后输入电脑锁屏密码 打开了任何来源,还遇到已损坏…...
端到端自动驾驶系统实战指南:从Comma.ai架构到PyTorch部署
引言:端到端自动驾驶的技术革命 在自动驾驶技术演进历程中,端到端(End-to-End)架构正引领新一轮技术革命。不同于传统分模块处理感知、规划、控制的方案,端到端系统通过深度神经网络直接建立传感器原始数据到车辆控制…...
MoveIt Setup Assistant 在导入urdf文件的时候报错
在使用MoveIt Setup Assistant导入urdf文件的时候(load a urdf or collada robot model),找到urdf文件后MoveIt Setup Assistant闪退并报错: Warning: Ignoring XDG_SESSION_TYPEwayland on Gnome. Use QT_QPA_PLATFORMwayland to run on Wayland anyway…...
uniapp +vue +springboot多商家订餐系统
uniapp vue springboot多商家订餐系统,这个系统我整理调试的多商家,多用户的,多端小程序订餐系统,主要包含了uniapp小程序端,管理后台页面vue端,后台功能接口Springboot端,源码齐全,…...
docker迅雷自定义端口号、登录用户名密码
在NAS上部署迅雷,确实会带来很大的方便。但是目前很多教程都是讲怎么部署docker迅雷,鲜有将自定义配置的方法。这里讲一下怎么部署,并重点讲一下支持的自定义参数。 一、部署docker 在其他教程中,都是介绍的如下命令,…...