跳到主要内容

Dubbo 集成

Apache Dubbo 是一款高性能 Java RPC 框架,Nacos 作为 Dubbo 生态的重要注册中心实现,提供了服务发现和配置管理能力。本章介绍 Nacos 与 Dubbo 的集成方式。

概述

为什么选择 Nacos + Dubbo

Nacos 作为 Dubbo 注册中心具有以下优势:

特性说明
一站式服务同时提供注册中心和配置中心功能
动态配置支持 Dubbo 配置的动态更新
控制台管理提供可视化服务管理界面
高可用支持集群部署,保证服务稳定性
生态完善与 Spring Cloud Alibaba 生态无缝集成

版本兼容性

Dubbo 与 Nacos 的版本对应关系:

Dubbo 版本推荐 Nacos 版本Nacos 兼容范围JDK 要求
3.3.03.2.02.x / 3.xJDK 17+(Nacos 3.x)
3.2.x2.3.0 / 3.x2.x / 3.xJDK 8+ / 17+
3.1.x2.1.02.xJDK 8+
3.0.x2.0.92.xJDK 8+
2.7.x1.x 最新版1.xJDK 8+
2.6.x1.x 最新版1.xJDK 8+
版本注意
  1. Dubbo 3.0.0+ 需要 Nacos 2.0.0+ 版本
  2. Nacos 3.x 需要 JDK 17+ 运行环境
  3. 请确保版本兼容,避免出现连接问题
  4. 使用 Nacos 3.x 时,Dubbo 版本建议使用 3.2.0+

快速开始

环境准备

确保 Nacos 服务已启动,可参考安装与配置章节。

添加依赖

Spring Boot 应用

<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>

<!-- Dubbo Nacos Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>

非 Spring Boot 应用

<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.3.0</version>
</dependency>

<!-- Nacos Client -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.3.0</version>
</dependency>

定义服务接口

首先定义服务接口,服务提供者和消费者都需要依赖此接口:

package com.example.dubbo.api;

/**
* 用户服务接口
*/
public interface UserService {

/**
* 根据用户ID获取用户名
* @param userId 用户ID
* @return 用户名
*/
String getUserName(Long userId);

/**
* 创建用户
* @param userId 用户ID
* @param name 用户名
* @return 是否成功
*/
boolean createUser(Long userId, String name);
}

服务提供者

配置文件

# application.yml
spring:
application:
name: user-service-provider

dubbo:
application:
name: user-service-provider
logger: slf4j
# 注册中心配置
registry:
address: nacos://127.0.0.1:8848
username: nacos
password: nacos
# 协议配置
protocol:
name: dubbo
port: 20880
# 服务扫描包
scan:
base-packages: com.example.dubbo.provider

服务实现

package com.example.dubbo.provider;

import com.example.dubbo.api.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* 用户服务实现
*
* @DubboService 注解将服务暴露为 Dubbo 服务
* - version: 服务版本,用于灰度发布
* - group: 服务分组,用于服务隔离
* - timeout: 超时时间(毫秒)
* - retries: 重试次数
*/
@DubboService(
version = "1.0.0",
group = "user-group",
timeout = 5000,
retries = 2
)
public class UserServiceImpl implements UserService {

private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

// 模拟数据存储
private final Map<Long, String> userStore = new ConcurrentHashMap<>();

@Override
public String getUserName(Long userId) {
logger.info("获取用户名,userId: {}", userId);
return userStore.getOrDefault(userId, "Unknown");
}

@Override
public boolean createUser(Long userId, String name) {
logger.info("创建用户,userId: {}, name: {}", userId, name);
userStore.put(userId, name);
return true;
}
}

启动类

package com.example.dubbo.provider;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* 服务提供者启动类
*
* @EnableDubbo 启用 Dubbo 注解驱动
* - scanBasePackages: 指定 Dubbo 服务扫描包路径
*/
@EnableDubbo(scanBasePackages = "com.example.dubbo.provider")
@SpringBootApplication
public class ProviderApplication {

public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
System.out.println("用户服务提供者启动成功!");
}
}

服务消费者

配置文件

# application.yml
spring:
application:
name: user-service-consumer

dubbo:
application:
name: user-service-consumer
logger: slf4j
# 注册中心配置
registry:
address: nacos://127.0.0.1:8848
username: nacos
password: nacos
# 消费者默认配置
consumer:
timeout: 5000
retries: 2
check: false # 启动时不检查服务是否存在

服务消费

package com.example.dubbo.consumer;

import com.example.dubbo.api.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
* 服务消费者
*
* @DubboReference 注解用于引用远程服务
* - version: 服务版本,需要与提供者一致
* - group: 服务分组,需要与提供者一致
* - timeout: 调用超时时间
* - retries: 重试次数
* - loadbalance: 负载均衡策略
*/
@Component
public class UserConsumer implements CommandLineRunner {

private static final Logger logger = LoggerFactory.getLogger(UserConsumer.class);

@DubboReference(
version = "1.0.0",
group = "user-group",
timeout = 5000,
retries = 2,
loadbalance = "roundrobin"
)
private UserService userService;

@Override
public void run(String... args) {
// 测试服务调用
testUserService();
}

private void testUserService() {
// 创建用户
boolean created = userService.createUser(1L, "张三");
logger.info("创建用户结果: {}", created);

// 获取用户名
String userName = userService.getUserName(1L);
logger.info("获取用户名: {}", userName);

// 批量测试
for (int i = 1; i <= 10; i++) {
Long userId = (long) i;
String name = userService.getUserName(userId);
logger.info("第{}次调用,用户名: {}", i, name);
}
}
}

启动类

package com.example.dubbo.consumer;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class ConsumerApplication {

public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}

验证注册结果

启动服务后,在 Nacos 控制台查看服务注册情况:

  1. 访问 http://localhost:8848/nacos
  2. 进入「服务管理」->「服务列表」
  3. 可以看到服务名格式为:providers:com.example.dubbo.api.UserService:1.0.0:user-group

高级配置

命名空间配置

使用命名空间隔离不同环境的服务:

dubbo:
registry:
address: nacos://127.0.0.1:8848
parameters:
namespace: 5cbb70a5-xxx-xxx-xxx-d43479ae0932

或者直接在地址中指定:

dubbo:
registry:
address: nacos://127.0.0.1:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932

分组配置

使用分组隔离同一环境下的不同服务组:

dubbo:
registry:
address: nacos://127.0.0.1:8848
group: dubbo
分组与命名空间的区别

命名空间用于隔离不同用户或环境,分组用于在同一环境中进一步分类数据。通常建议:

  • 使用命名空间隔离开发、测试、生产环境
  • 使用分组隔离不同业务模块

认证配置

配置 Nacos 认证信息:

dubbo:
registry:
address: nacos://127.0.0.1:8848?username=nacos&password=nacos

或者使用以下格式:

dubbo:
registry:
address: nacos://nacos:[email protected]:8848

注册消费者

Dubbo 3.0+ 支持注册消费者信息:

dubbo:
registry:
address: nacos://127.0.0.1:8848
parameters:
register-consumer-url: true

开启后,消费者信息也会注册到 Nacos,方便服务治理和监控。

完整配置参数

参数说明默认值
usernameNacos 用户名nacos
passwordNacos 密码nacos
backup备用地址
namespace命名空间 IDpublic
group分组名DEFAULT_GROUP
register-consumer-url是否注册消费者false
namingLoadCacheAtStart启动时优先读取本地缓存true
namingClientBeatThreadCount心跳线程池大小CPU 核数的一半
namingPollingThreadCount轮询线程池大小CPU 核数的一半

心跳与超时配置

通过元数据控制实例的心跳行为:

dubbo:
registry:
address: nacos://127.0.0.1:8848
parameters:
# 心跳间隔(毫秒)
preserved.heart.beat.interval: 5000
# 心跳超时时间(毫秒)
preserved.heart.beat.timeout: 15000
# 实例删除超时时间(毫秒)
preserved.ip.delete.timeout: 30000

Spring XML 配置

如果使用传统的 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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<!-- 应用信息 -->
<dubbo:application name="user-service-provider"/>

<!-- 注册中心配置 -->
<dubbo:registry address="nacos://127.0.0.1:8848"
username="nacos"
password="nacos"/>

<!-- 协议配置 -->
<dubbo:protocol name="dubbo" port="20880"/>

<!-- 服务暴露 -->
<dubbo:service interface="com.example.dubbo.api.UserService"
ref="userService"
version="1.0.0"
timeout="5000"/>

<!-- 服务实现 -->
<bean id="userService" class="com.example.dubbo.provider.UserServiceImpl"/>

</beans>

消费者 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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<!-- 应用信息 -->
<dubbo:application name="user-service-consumer"/>

<!-- 注册中心配置 -->
<dubbo:registry address="nacos://127.0.0.1:8848"/>

<!-- 服务引用 -->
<dubbo:reference id="userService"
interface="com.example.dubbo.api.UserService"
version="1.0.0"
timeout="5000"/>

</beans>

Dubbo 3.x 新特性

应用级服务发现

Dubbo 3.x 引入了应用级服务发现,相比接口级服务发现更加轻量:

接口级服务发现(Dubbo 2.x):
服务名:providers:com.example.UserService:1.0.0
注册内容:接口名、版本、分组、地址列表

应用级服务发现(Dubbo 3.x):
服务名:user-service-provider
注册内容:应用名、地址列表
接口映射:接口到应用的映射关系

双注册模式

Dubbo 3.x 默认采用双注册模式,同时注册应用级和接口级服务:

# 控制注册模式
dubbo:
registry:
register-mode: all # all(双注册)/instance(应用级)/interface(接口级)

在 Nacos 控制台中可以看到两种形式的注册信息。

配置中心集成

除了作为注册中心,Nacos 还可以作为 Dubbo 的配置中心。

配置外部化

将 Dubbo 配置托管到 Nacos:

dubbo:
config-center:
address: nacos://127.0.0.1:8848
namespace: dubbo-config
group: dubbo

在 Nacos 中创建配置:

  • Data ID:dubbo.properties
  • Group:dubbo
  • 内容:
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.provider.timeout=5000

动态配置

支持动态修改配置,实时生效:

dubbo:
config-center:
address: nacos://127.0.0.1:8848
highest-priority: true # 配置中心优先级最高

负载均衡

Dubbo 支持多种负载均衡策略,配合 Nacos 的权重配置实现精细化流量控制。

负载均衡策略

策略说明
random随机,按权重随机(默认)
roundrobin轮询,按权重轮询
leastactive最少活跃调用数,自动感知后端压力
consistenthash一致性哈希,相同参数请求发到同一提供者

配置负载均衡

@DubboReference(loadbalance = "roundrobin")
private UserService userService;

动态权重配置

通过 Nacos 控制台动态调整服务权重:

  1. 进入「服务管理」->「服务列表」
  2. 点击服务进入详情
  3. 修改实例权重

权重越大,被选中的概率越高。可用于灰度发布场景。

服务治理

服务分组

通过分组实现服务隔离:

// 提供者
@DubboService(group = "v1")
public class UserServiceV1Impl implements UserService { }

@DubboService(group = "v2")
public class UserServiceV2Impl implements UserService { }

// 消费者
@DubboReference(group = "v1")
private UserService userServiceV1;

@DubboReference(group = "v2")
private UserService userServiceV2;

多版本

通过版本实现灰度发布:

// 提供者
@DubboService(version = "1.0.0")
public class UserServiceV1Impl implements UserService { }

@DubboService(version = "2.0.0")
public class UserServiceV2Impl implements UserService { }

// 消费者
@DubboReference(version = "1.0.0")
private UserService userService; // 使用 1.0.0 版本

@DubboReference(version = "*")
private UserService userService; // 随机选择版本

超时与重试

@DubboReference(
timeout = 3000, // 超时时间 3 秒
retries = 2, // 重试 2 次
loadbalance = "leastactive"
)
private UserService userService;

监控与运维

服务状态查看

在 Nacos 控制台可以查看:

  • 服务提供者列表和实例数
  • 服务消费者列表
  • 实例健康状态
  • 实例元数据

Dubbo Admin

结合 Dubbo Admin 进行更细粒度的服务治理:

  • 服务查询
  • 服务测试
  • 路由规则配置
  • 动态配置管理

常见问题

1. 服务注册失败

症状:服务启动后未在 Nacos 控制台看到注册信息

排查步骤

  1. 检查 Nacos 服务是否正常运行
  2. 检查网络连通性:telnet 127.0.0.1 8848
  3. 检查认证信息是否正确
  4. 检查应用日志是否有错误信息
  5. 确认 Dubbo 版本与 Nacos 版本兼容

2. 服务发现失败

症状:消费者启动报错,找不到服务提供者

排查步骤

  1. 确认提供者已成功注册
  2. 检查命名空间和分组配置是否一致
  3. 检查服务版本和分组是否匹配
  4. 设置 check=false 跳过启动检查
dubbo:
consumer:
check: false

3. 连接超时

症状:客户端报错 Connection is unregisteredClient not connected

解决方案

  1. 检查 gRPC 端口(9848)是否开放
  2. 检查防火墙配置
  3. 确认 Nginx/VIP 配置为 TCP 转发
# 测试 gRPC 端口连通性
telnet 127.0.0.1 9848

4. 频繁断线重连

症状:日志中出现频繁的连接断开和重连

排查方向

  1. 检查网络稳定性
  2. 调整心跳参数
  3. 检查 Nacos 服务端负载
dubbo:
registry:
parameters:
preserved.heart.beat.interval: 10000
preserved.heart.beat.timeout: 30000

最佳实践

1. 合理设置超时时间

根据业务特点设置合理的超时时间:

// 读操作可以设置较长超时
@DubboReference(timeout = 10000)
private UserService userService;

// 写操作设置较短超时
@DubboReference(timeout = 3000)
private OrderService orderService;

2. 使用异步调用

对于耗时操作,使用异步调用提高性能:

@DubboReference(async = true)
private UserService userService;

public void asyncCall() {
userService.getUserName(1L);
// 获取异步结果
CompletableFuture<String> future = RpcContext.getContext().getCompletableFuture();
future.thenAccept(name -> {
System.out.println("用户名: " + name);
});
}

3. 服务版本管理

建议为服务设置明确的版本号,便于灰度发布和回滚:

// 稳定版本
@DubboService(version = "1.0.0")

// 新版本(灰度)
@DubboService(version = "1.1.0")

4. 环境隔离

使用命名空间严格隔离不同环境:

dev 命名空间 -> 开发环境
test 命名空间 -> 测试环境
prod 命名空间 -> 生产环境

下一步