Dubbo
Dubbo
#resource / java
#type / concept
#status / growing
Dubbo
基础概念
什么是 Dubbo
Apache Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
核心架构
┌─────────────┐ ┌─────────────┐
│ Consumer │─────▶│ Registry │
│ (服务消费者) │ │ (注册中心) │
└─────────────┘ └─────────────┘
│ │
│ invoke │ register
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Provider │◀─────│ Monitor │
│ (服务提供者) │ │ (监控中心) │
└─────────────┘ └─────────────┘
核心组件
- Provider:服务提供者,暴露服务的服务方
- Consumer:服务消费者,调用远程服务的服务方
- Registry:注册中心,用于服务发现和配置管理
- Monitor:监控中心,统计服务的调用次数和调用时间
- Container:服务运行容器
核心特性
- 透明化的远程方法调用:像调用本地方法一样调用远程方法
- 软负载均衡:支持多种负载均衡策略
- 容错机制:提供多种容错策略
- 自动服务注册与发现:支持多种注册中心
- 高度可扩展:微内核设计,所有功能都是插件
- 运行时流量调度:内置多种路由规则
使用指南
环境准备
Maven 依赖:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.2.5</version>
</dependency>
<!-- 注册中心依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.2.5</version>
</dependency>
<!-- 序列化依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>3.2.5</version>
</dependency>
Spring Boot Starter:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.5</version>
</dependency>
定义服务接口
package com.example.service;
/**
* 用户服务接口
*/
public interface UserService {
/**
* 根据ID获取用户信息
*/
User getUserById(Long id);
/**
* 创建用户
*/
User createUser(User user);
/**
* 更新用户信息
*/
boolean updateUser(User user);
/**
* 删除用户
*/
boolean deleteUser(Long id);
/**
* 分页查询用户
*/
PageResult<User> getUsers(PageRequest pageRequest);
}
用户实体类:
package com.example.model;
import java.io.Serializable;
import java.time.LocalDateTime;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String email;
private String phone;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
// 构造函数、getter、setter 省略
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
", status=" + status +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}
服务提供者实现
服务实现类:
package com.example.service.impl;
import org.apache.dubbo.config.annotation.DubboService;
import com.example.service.UserService;
import com.example.model.User;
import org.springframework.stereotype.Service;
@DubboService(version = "1.0.0", timeout = 5000)
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Long id) {
// 模拟数据库查询
if (id == null || id <= 0) {
throw new IllegalArgumentException("User ID must be positive");
}
User user = new User();
user.setId(id);
user.setUsername("user_" + id);
user.setEmail("user" + id + "@example.com");
user.setPhone("1388888" + String.format("%04d", id));
user.setStatus(1);
user.setCreateTime(LocalDateTime.now().minusDays(id));
user.setUpdateTime(LocalDateTime.now());
return user;
}
@Override
public User createUser(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
// 模拟数据库插入
user.setId(System.currentTimeMillis() % 10000);
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
user.setStatus(1);
System.out.println("Created user: " + user);
return user;
}
@Override
public boolean updateUser(User user) {
if (user == null || user.getId() == null) {
return false;
}
// 模拟数据库更新
user.setUpdateTime(LocalDateTime.now());
System.out.println("Updated user: " + user);
return true;
}
@Override
public boolean deleteUser(Long id) {
if (id == null || id <= 0) {
return false;
}
// 模拟数据库删除
System.out.println("Deleted user with id: " + id);
return true;
}
@Override
public PageResult<User> getUsers(PageRequest pageRequest) {
List<User> users = new ArrayList<>();
int pageSize = pageRequest.getPageSize();
int pageNum = pageRequest.getPageNum();
// 模拟分页数据
for (int i = 1; i <= pageSize; i++) {
User user = getUserById((long) ((pageNum - 1) * pageSize + i));
users.add(user);
}
return new PageResult<>(users, pageNum, pageSize, 1000L);
}
}
Provider 配置(application.yml):
# Dubbo 配置
dubbo:
application:
name: user-service-provider
version: 1.0.0
registry:
address: nacos://127.0.0.1:8848
parameters:
namespace: dubbo
protocol:
name: dubbo
port: 20880
provider:
timeout: 5000
retries: 2
loadbalance: roundrobin
metadata-report:
address: nacos://127.0.0.1:8848
# Spring 配置
spring:
application:
name: user-service-provider
server:
port: 8081
# 日志配置
logging:
level:
com.example: DEBUG
org.apache.dubbo: INFO
Provider 启动类:
package com.example.provider;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo(scanBasePackages = "com.example.service.impl")
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
System.out.println("User service provider started successfully!");
}
}
服务消费者实现
Consumer 配置(application.yml):
# Dubbo 配置
dubbo:
application:
name: user-service-consumer
version: 1.0.0
registry:
address: nacos://127.0.0.1:8848
parameters:
namespace: dubbo
consumer:
timeout: 5000
retries: 2
check: false
# Spring 配置
spring:
application:
name: user-service-consumer
server:
port: 8080
logging:
level:
com.example: DEBUG
org.apache.dubbo: INFO
Consumer 服务调用:
package com.example.consumer.controller;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.*;
import com.example.service.UserService;
import com.example.model.User;
@RestController
@RequestMapping("/api/users")
public class UserController {
@DubboReference(version = "1.0.0", timeout = 5000)
private UserService userService;
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@PutMapping("/{id}")
public boolean updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.updateUser(user);
}
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
return userService.deleteUser(id);
}
@GetMapping
public PageResult<User> getUsers(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
PageRequest pageRequest = new PageRequest(pageNum, pageSize);
return userService.getUsers(pageRequest);
}
}
Consumer 启动类:
package com.example.consumer;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
System.out.println("User service consumer started successfully!");
}
}
实战经验
高级配置
多注册中心配置:
dubbo:
registries:
nacos1:
address: nacos://192.168.1.100:8848
parameters:
namespace: production
nacos2:
address: nacos://192.168.1.101:8848
parameters:
namespace: production
zookeeper:
address: zookeeper://192.168.1.102:2181
多协议配置:
dubbo:
protocols:
dubbo:
name: dubbo
port: 20880
rest:
name: rest
port: 8080
http:
name: http
port: 8081
负载均衡策略
// 在服务消费者端配置负载均衡
@DubboReference(
version = "1.0.0",
loadbalance = "roundrobin" // 轮询
// loadbalance = "random" // 随机
// loadbalance = "leastactive" // 最少活跃调用数
// loadbalance = "consistenthash" // 一致性哈希
)
private UserService userService;
容错策略
// 配置容错策略
@DubboReference(
version = "1.0.0",
cluster = "failover", // 失败自动切换(默认)
retries = 2 // 重试次数
// cluster = "failfast" // 快速失败
// cluster = "failsafe" // 失败安全
// cluster = "failback" // 失败自动恢复
// cluster = "forking" // 并行调用
)
private UserService userService;
服务分组和版本
// Provider 端
@DubboService(
group = "default",
version = "1.0.0"
)
public class UserServiceImpl implements UserService {
// 实现
}
// Consumer 端
@DubboReference(
group = "default",
version = "1.0.0"
)
private UserService userService;
异步调用
// Provider 端
@DubboService
public class AsyncUserServiceImpl implements UserService {
public CompletableFuture<User> getUserByIdAsync(Long id) {
return CompletableFuture.supplyAsync(() -> {
// 异步处理逻辑
return getUserById(id);
});
}
}
// Consumer 端
@DubboReference
private UserService userService;
public void asyncCall() {
// 异步调用
CompletableFuture<User> future = RpcContext.getContext()
.asyncCall(() -> userService.getUserById(1L));
future.whenComplete((user, throwable) -> {
if (throwable == null) {
System.out.println("Async result: " + user);
} else {
System.err.println("Async error: " + throwable.getMessage());
}
});
}
过滤器(Filter)
// 自定义过滤器
@Activate(group = {PROVIDER, CONSUMER})
public class LoggingFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation)
throws RpcException {
long startTime = System.currentTimeMillis();
try {
Result result = invoker.invoke(invocation);
long duration = System.currentTimeMillis() - startTime;
System.out.printf("Method [%s] executed in %d ms%n",
invocation.getMethodName(), duration);
return result;
} catch (Exception e) {
long duration = System.currentTimeMillis() - startTime;
System.err.printf("Method [%s] failed after %d ms: %s%n",
invocation.getMethodName(), duration, e.getMessage());
throw e;
}
}
}
参数验证
// 使用 JSR-303 验证
@DubboService(validation = "true")
public class UserServiceImpl implements UserService {
@Override
public User createUser(@Valid User user) {
// 实现逻辑
return user;
}
}
// 实体类验证注解
public class User implements Serializable {
@NotNull(message = "用户名不能为空")
@Size(min = 2, max = 50, message = "用户名长度必须在2-50之间")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
}
泛化调用
// 不依赖接口的服务调用
@DubboReference(
interfaceName = "com.example.service.UserService",
version = "1.0.0",
generic = true
)
private GenericService genericService;
public void genericCall() {
// 泛化调用
Object result = genericService.$invoke(
"getUserById",
new String[]{"java.lang.Long"},
new Object[]{1L}
);
System.out.println("Generic call result: " + result);
}
经验总结
优势
- 高性能:基于 NIO 的高性能网络框架
- 透明化调用:像调用本地方法一样调用远程服务
- 负载均衡:内置多种负载均衡算法
- 容错机制:提供多种容错策略
- 服务治理:完善的服务注册发现机制
- 可扩展性:微内核设计,易于扩展
适用场景
适合使用 Dubbo:
- 大型分布式系统
- 微服务架构
- 高并发场景
- 需要服务治理的系统
- Java 技术栈项目
不适合使用 Dubbo:
- 小型项目
- 跨语言通信(建议使用 gRPC)
- 简单的 HTTP API
- 对性能要求不高的场景
最佳实践
-
接口设计
- 保持接口简洁,避免过多参数
- 使用包装对象传递复杂参数
- 合理设计返回值类型
-
服务分组和版本管理
- 使用语义化版本号
- 合理使用服务分组
- 做好版本兼容性
-
性能优化
- 合理设置超时时间
- 选择合适的序列化协议
- 合理配置连接池参数
-
监控和运维
- 配置监控中心
- 设置合理的日志级别
- 使用服务治理平台
常见问题
-
服务无法发现
- 检查注册中心配置
- 确认网络连通性
- 验证服务注册状态
-
调用超时
- 调整超时配置
- 检查网络延迟
- 优化服务实现
-
序列化异常
- 确保实体类实现 Serializable
- 检查版本兼容性
- 统一序列化协议
信息参考
- Apache Dubbo 官网
- Dubbo 官方文档
- Dubbo GitHub 仓库
- Dubbo Spring Boot Starter
- Dubbo Admin 管理控制台
- Dubbo 用户指南
- Dubbo 开发者指南
- Dubbo 最佳实践
- Dubbo 生态系统