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.0 | 3.2.0 | 2.x / 3.x | JDK 17+(Nacos 3.x) |
| 3.2.x | 2.3.0 / 3.x | 2.x / 3.x | JDK 8+ / 17+ |
| 3.1.x | 2.1.0 | 2.x | JDK 8+ |
| 3.0.x | 2.0.9 | 2.x | JDK 8+ |
| 2.7.x | 1.x 最新版 | 1.x | JDK 8+ |
| 2.6.x | 1.x 最新版 | 1.x | JDK 8+ |
- Dubbo 3.0.0+ 需要 Nacos 2.0.0+ 版本
- Nacos 3.x 需要 JDK 17+ 运行环境
- 请确保版本兼容,避免出现连接问题
- 使用 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 控制台查看服务注册情况:
- 访问
http://localhost:8848/nacos - 进入「服务管理」->「服务列表」
- 可以看到服务名格式为:
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,方便服务治理和监控。
完整配置参数
| 参数 | 说明 | 默认值 |
|---|---|---|
username | Nacos 用户名 | nacos |
password | Nacos 密码 | nacos |
backup | 备用地址 | 空 |
namespace | 命名空间 ID | public |
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 控制台动态调整服务权重:
- 进入「服务管理」->「服务列表」
- 点击服务进入详情
- 修改实例权重
权重越大,被选中的概率越高。可用于灰度发布场景。
服务治理
服务分组
通过分组实现服务隔离:
// 提供者
@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 控制台看到注册信息
排查步骤:
- 检查 Nacos 服务是否正常运行
- 检查网络连通性:
telnet 127.0.0.1 8848 - 检查认证信息是否正确
- 检查应用日志是否有错误信息
- 确认 Dubbo 版本与 Nacos 版本兼容
2. 服务发现失败
症状:消费者启动报错,找不到服务提供者
排查步骤:
- 确认提供者已成功注册
- 检查命名空间和分组配置是否一致
- 检查服务版本和分组是否匹配
- 设置
check=false跳过启动检查
dubbo:
consumer:
check: false
3. 连接超时
症状:客户端报错 Connection is unregistered 或 Client not connected
解决方案:
- 检查 gRPC 端口(9848)是否开放
- 检查防火墙配置
- 确认 Nginx/VIP 配置为 TCP 转发
# 测试 gRPC 端口连通性
telnet 127.0.0.1 9848
4. 频繁断线重连
症状:日志中出现频繁的连接断开和重连
排查方向:
- 检查网络稳定性
- 调整心跳参数
- 检查 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 命名空间 -> 生产环境