dubbo
分布式系统中的相关概念
B站视频链接:【黑马程序员Dubbo快速入门,Java分布式框架dubbo教程】https://www.bilibili.com/video/BV1VE411q7dX?p=9&vd_source=18ef385bcfaefef9c4320bc519a9144f
黑马资料链接:https://pan.baidu.com/s/136WmZXSNacZMcKIgf-3sHA?pwd=1234
笔记网盘链接:通过网盘分享的文件:dubbo.md
链接: https://pan.baidu.com/s/1mmRwSgsrYwDD2Arpd5Nrrg?pwd=2f3d 提取码: 2f3d
–来自百度网盘超级会员v4的分享
大型互联网项目架构目标
互联网项目特点:
- 用户多
- 流量大,并发高
- 海量数据
- 易受攻击
- 功能繁琐
- 变更快
目标:
-
高性能:提供快速的访问体验

-
高可用:网站服务一直可以正常访问
-
可伸缩:通过硬件增加/减少,提高/降低处理能力
-
高可扩展:系统间耦合低,方便通过新增/移除方式,增加/减少新的功能/模块
-
安全性:提供网站安全访问和数据加密,安全存储等策略
-
敏捷性:随需应变,快速响应
集群和分布式
-
集群:很多人一起,干一样的事
- 一个业务模块,部署在多台服务器上。
-
分布式:很多“人”一起,干不一样的事。这些不一样的事,合起来是一件大事。
- 一个大的业务系统,拆分为小的业务模块,分别部署在不同的机器上。
架构演进



- 对外 http/https,对内 rpc

- ESB 类似于注册中心


Duubo 概述
Dubbo 架构

Dubbo 快速入门
环境准备
你需要启动一个 nacos 配置中心,或者启动 zookeeper 配置中心
Zookeeper 和 Nacos 作为独立的服务端软件,通常不需要专门为了 Dubbo 去修改它们自己的配置文件。
绝大多数情况下,你只需要在 Spring Boot 的 application.yml(或 .properties)中配置即可。
你可以把 Zookeeper 或 Nacos 想象成 “数据库”(比如 MySQL)。
- 当你写一个 Java 应用去连 MySQL 时,你需要改 MySQL 的配置文件让它专门支持你的这个 Java 应用吗?不需要。MySQL 只要启动了,监听在
3306端口,谁来连都可以。- Zookeeper/Nacos 同理:它们是通用的中间件。
- Zookeeper:它只负责存树状节点数据。Dubbo 连上来存什么数据(接口名、IP地址),Zookeeper 根本不关心,它只负责存储。
- Nacos:它只负责维护服务列表。Dubbo 告诉它“我是
UserService,IP 是192.168.x.x”,Nacos 就把它记下来。所以,你下载好 Zookeeper 或 Nacos 后,直接默认配置启动,它们就已经准备好接受 Dubbo 的连接了。
dubbo 和 zookeeper,可以理解成 java 项目和 数据库的关系,数据库不做额外配置,java项目需要配置。而 dubbo 的配置,一般都是在 springboot 的 yml 文件中,我们指定配置中心,都是看 yml 文件里面的内容
代码实现
- 实现思路


简单来说:dubbo 原理是通过 service 注解和 ref 注解来实现 dubbo 的服务注册和服务调用
以下内容来自于 dubbo 官方文档,快速入门:
提示
本项目源码在 Dubbo Github 示例仓库中维护 https://github.com/apache/dubbo-samples
项目结构
项目结构如下:
quickstart
├── quickstart-api // 公共接口模块(提供者和消费者共用)
—— DemoService
├── quickstart-provider // 服务提供者(核心:@DubboService配置)
—— dubbo
—— consumer // 示例项目中的consumer确实是在这里,但是实际上的项目,consumer肯定是在别的模块里面的
—— DemoServiceImpl
—— QuickStartApplication
—— application.yml
└── quickstart-consumer // 服务消费者,这才是 consumer的合理位置,但是官方的示例代码并没有将 consumer 放在这个位置

Maven 依赖(服务提供者、消费者模块)
公共接口模块,即 quickstart-api,仅需基础依赖,这里可以参考官方示例项目的依赖。
下面的 pom 是服务提供者和消费者模块的依赖,提供者和消费者所需的依赖类似,基本都是下面这些。
在demo中的消费者和服务提供者在一个模块下,自然是共用一个 pom 文件的。
打开 pom.xml,可以看到示例项目中 Dubbo 相关核心依赖如下:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>3.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- Dubbo Nacos注册中心 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
</dependency>
<!-- 其他依赖见下-->
<!-- Spring Boot核心 -->
<!-- 引入公共API模块 -->
</dependencies>
其中,dubbo-spring-boot-starter、dubbo-nacos-spring-boot-starter 分别为我们引入了 Dubbo 内核框架与 Nacos 客户端相关的依赖组件,更多内容可以查看 Dubbo 支持的 Spring Boot Starter 清单 。
公共接口模块:服务定义(api)
以下是基于 Java Interface 的标准 Dubbo 服务定义。
public interface DemoService {
String sayHello(String name);
}
在 DemoService 中,定义了 sayHello 这个方法。后续服务端发布的服务,消费端订阅的服务都是围绕着 DemoService 接口展开的。
基础模块的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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.apache.dubbo</groupId>
<artifactId>quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>quickstart-api</artifactId>
<name>quickstart-api</name>
<description>The Dubbo service API definitions defined in the project.</description>
</project>
服务实现(provider)
- 服务提供者
要将 service 提供的服务对外发布,将 ip、端口、访问路径 告诉 dubbo,dubbo会自动记录到 zookeeper 中
定义了服务接口之后,可以在服务端这一侧定义对应的业务逻辑实现。
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
在DemoServiceImpl 类中添加了 @DubboService 注解,通过这个配置可以基于 Spring Boot 去发布 Dubbo 服务。
应用入口与配置文件
由于我们创建的是一个 Spring Boot 应用,Dubbo 相关配置信息都存放在 application.yml 配置文件中。基于以下配置,Dubbo 进程将在 50051 端口监听 triple 协议请求,同时,实例的 ip:port 信息将会被注册到 Nacos server。
# application.yml
dubbo:
# 注册中心配置(服务注册/发现)
registry:
address: nacos://${nacos.address:127.0.0.1}:8848?username=nacos&password=nacos
# This will enable application-level service discovery only (the recommended service discovery method for Dubbo3).
# For users upgrading from Dubbo2.x, please set the value to 'all' for smooth migration.
register-mode: instance
# 3. 协议配置(服务暴露的IP/端口)
protocol:
name: tri
port: 50051
name: dubbo
port: 20880
# 应用基本信息(必填)
application:
# 应用名称(必填,消费者通过此定位服务)
name: QuickStartApplication
logger: slf4j
以下是整个应用的启动入口,@EnableDubbo 注解用来加载和启动 Dubbo 相关组件。
如果在启动类上添加了 @EnableDubbo 注解,且没有指定参数,它默认会扫描 启动类所在的包及其子包。
@SpringBootApplication
@EnableDubbo
public class QuickStartApplication {
public static void main(String[] args) {
SpringApplication.run(QuickStartApplication.class, args);
}
}
发起服务调用(consumer)
依赖见上,和服务提供者类似
application.yml 配置文件:
server:
port: 8082 # 消费者端口(和提供者区分)
dubbo:
# 应用名称
application:
name: dubbo-demo-consumer
# 注册中心配置(和提供者一致)
registry:
address: nacos://127.0.0.1:8848
调用远程服务
创建一个 Controller,使用 @DubboReference 注入远程服务代理。
package com.example.demo.consumer.controller;
import com.example.demo.api.HelloService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
// @DubboReference 会自动从 Zookeeper 发现服务并生成代理对象
/**
1. 从 zookeeper 注册中心获取 userService 的访问 URL
2. 进行远程调用 RPC
3. 将结果封装为一个代理对象,给变量赋值
*/
@DubboReference // 类似依赖注入
private HelloService helloService;
@GetMapping("/hello")
public String sayHello(@RequestParam String name) {
// 像调用本地方法一样调用远程接口
return helloService.sayHello(name);
}
}
启动类
同样需要 @EnableDubbo。
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
上面的 consumer 代码是我自己写的,下面的是官方示例代码的实现
示例应用中有一个 consumer 包,用于模拟发起对 provider 服务的远程调用。
@Component public class Consumer implements CommandLineRunner { @DubboReference private DemoService demoService; @Override public void run(String... args) throws Exception { String result = demoService.sayHello("world"); System.out.println("Receive result ======> " + result); } }在
Task类中,通过@DubboReference从 Dubbo 获取了一个 RPC 订阅代理,这个demoService代理可以像本地调用一样直接调用:demoService.sayHello("world")。提示
通常远程调用是跨进程的,示例项目为了方便开发,直接内置了一个
@DubboReference调用。如果您想学习如何开发一个独立的 Consumer(客户端)进程,以便发起对 Dubbo 服务的远程调用,我们有一个 包含独立 consumer、provider 模块的示例项目 可供参考。
发布服务定义到远端仓库
应用开发完成后,我们需要将服务定义(在此示例中是 DemoService 接口定义)发布到外部公开的或组织内部的 maven 仓库,以便调用这些服务的应用能够加载并使用这些服务定义。
如之前我们看到的,示例项目包含 api、service 两个模块,切换项目到 api 目录,以下命令即可完成发布动作:
mvn clean deploy
Dubbo 高级特性
Dubbo-admin

安装与使用查看黑马程序员的资料即可
dubbo 常用高级配置
1. 序列化

实际使用上,由于dubbo的封装,我们对序列化是无感知的
我们要做的是把公共的对象抽出来,形成一个 pojo 模块,并确保这些对象实现了 serilizable 接口
2. 地址缓存

3. 超时重试
- 背景

- dubbo 的解决方案
- 超时

- 重试(超时了之后就重试)

重试两次,默认一共会发三次请求
- 服务方代码可以设置超时时间(超时时间建议配置在服务的提供者上)
// timeout = 3000: 设置服务超时时间为 3 秒,默认值 1 秒
// retries = 0: 设置重试次数为 0 (不重试)
// @Service: 将该类的对象创建出来,放到 Spring 的 IOC 容器中 beanName
// 将这个类提供的方法(服务)对外发布。将访问的地址 ip,端口,路径注册到注册中心中
@DubboService(timeout = 3000, retries = 0) // 当前服务三秒超时
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello dubbo hello!~";
}
@Override
public User findUserById(int id) {
// 模拟创建 User 对象
User user = new User(1, "zhangsan", "123");
// 模拟数据库查询很慢,查了 5 秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
}
- 调用方代码也可以设置超时时间(在调用方和服务方斗配置了超时时间时,调用方的配置会覆盖服务提供方的配置,就近原则,只要消费者配置了就以消费者为准)
@DubboReference(timeout = 1000) // 远程注入,1 秒超时
private UserService userService;
4. 多版本

- 代码
- provider(这里的service改成dubboService,就是2026年版本的dubbo用法了)


- consumer 自行选择用老版本还是新版本(把注解改成@DubboReference)

5. 负载均衡

负载均衡策略的配置:
-
配置遵循 “消费者优先,方法优先” 的原则。
-
方式 A:服务提供者端配置 (Provider - 推荐)
思路:作为服务开发方,我最清楚我的服务适合什么策略(比如我的服务是计算密集型,我建议用 LeastActive)。
// 【推荐】在这里配置默认策略 // 意味着:所有调用这个服务的消费者,默认都使用 "roundrobin" (轮询) @DubboService(loadbalance = "roundrobin", weight = 100) public class UserServiceImpl implements UserService { // ... } -
方式 B:服务消费者端配置 (Consumer - 霸道覆盖)
思路:消费者觉得提供者的策略不合理,强行覆盖。优先级高于 Provider 的配置。
@RestController public class UserController { // 【覆盖】虽然 Provider 建议用轮询,但我这里强制使用 "random" (随机) @DubboReference(loadbalance = "random") private UserService userService; // ... } -
方式 C:方法级精细化配置 (Method Level)
思路:同一个 Service 里,有的方法快,有的方法慢,需要不同的策略。
Provider 端写法(XML 或 Java Config 较多,注解版较少用): 这通常需要配合 XML 或 Properties 配置,注解版目前对方法级支持不如 XML 直观。如果非要用注解,通常是在 Interface 上无法区分的,建议拆分成两个 Service。
dubbo: reference: com.example.api.UserService: # 接口名 methods: - name: sayHello loadbalance: random # sayHello 用随机 - name: findUserById loadbalance: leastactive # findUserById 用最少活跃数 -
配置优先级(优先级从高到低,Consumer > Provider,Method > Interface > Global)
-
Consumer Method (消费者端的 application.yml 方法级配置)
-
Provider Method (提供者端的 application.yml 方法级配置)
-
Consumer Interface (
@DubboReference(loadbalance="...")) -
Provider Interface (
@DubboService(loadbalance="...")) -
Global (全局配置 dubbo.consumer.loadbalance)
-
-
实践建议
首选 Provider 端配置:建议在
@DubboService上配置好默认策略。因为服务提供者最了解自己的服务特性(是否有状态、是否计算密集)。不确定的选 Random:默认的 Random 在高并发下效果非常好,因为大数定律会保证流量均匀。
慢服务选 LeastActive:如果你的服务处理时间波动很大(有时候 10ms,有时候 1s),一定要用
leastactive,防止慢的机器被压垮。
6. 集群容错
Dubbo 的集群容错(Cluster)是指:当消费者调用提供者失败时,Dubbo 应该采取什么策略。

- 配置方法
依旧是配置在注解上
//服务提供者端配置
@DubboService(cluster = "failfast")
//服务消费者端配置
@DubboReference(cluster = "failsafe")
7. 服务降级

可以通过服务降级功能临时拼比某个出错的非关键服务,并定义降级后的返回策略
- 简单配置:依旧是在注解当中配置,如
@Reference(mock = "force:return null") - 复杂配置:需要写一个专门的 Mock 类
第一步:在 Consumer 端开启 Mock
@DubboReference(mock = "true") // 告诉 Dubbo 去找对应的 Mock 类
private UserService userService;
第二步:创建 Mock 类 Dubbo 有个命名约定:必须在接口包名下创建一个类,类名必须是 接口名 + Mock。
假设接口是 com.example.api.UserService,你需要创建: com.example.api.UserServiceMock
package com.example.api; // 包名必须和接口一致
public class UserServiceMock implements UserService {
@Override
public String sayHello(String name) {
// 这里写复杂的降级逻辑
return "系统繁忙,请稍后再试 (这是来自 Mock 的兜底回复)";
}
@Override
public User findUserById(int id) {
// 比如:远程挂了,查本地缓存
return new User(0, "本地缓存用户", "");
}
}
- 动态配置
在实际工作中,我们很少在代码里硬编码 mock=...,因为一旦写死,想改还得重新发版。
通常是结合 Dubbo Admin (管理控制台) 进行动态降级:
- 代码里正常写
@DubboReference(不配 mock)。 - 服务出问题时,运维人员登录 Dubbo Admin 控制台。
- 找到对应的服务,创建一个动态配置规则,设置
mock=force:return null。 - 该配置会通过注册中心(Zookeeper/Nacos)实时推送到所有消费者,立马生效。
Dubbo 的
mock主要是**“静态”或“手动”**的降级。如果需要根据系统负载(如 CPU 使用率、QPS 阈值)自动触发熔断降级,建议集成 Sentinel 或 Resilience4j,它们比 Dubbo 自带的 mock 强大得多。
更多推荐



所有评论(0)