Dubbo
基础概念
什么是Dubbo?
答案: Dubbo是阿里巴巴开源的高性能RPC框架,提供服务注册发现、负载均衡、容错、监控等功能。
核心特性:
- 面向接口的远程方法调用
- 智能容错和负载均衡
- 服务自动注册和发现
- 高度可扩展
- 运行期流量调度
- 可视化的服务治理
Dubbo的架构?
答案:
核心角色:
Provider(服务提供者)
↓ 注册
Registry(注册中心)
↓ 订阅
Consumer(服务消费者)
↓ 调用
Provider
↓ 监控
Monitor(监控中心)调用流程:
1. Provider启动,向Registry注册服务
2. Consumer启动,向Registry订阅服务
3. Registry返回Provider列表给Consumer
4. Consumer根据负载均衡策略选择Provider
5. Consumer调用Provider
6. Consumer和Provider定时向Monitor发送统计数据Dubbo和Spring Cloud的区别?
答案:
| 特性 | Dubbo | Spring Cloud |
|---|---|---|
| 通信协议 | RPC(Dubbo协议) | HTTP(REST) |
| 性能 | 高 | 相对较低 |
| 服务治理 | 完善 | 完善 |
| 社区 | 阿里 | Spring |
| 学习成本 | 较低 | 较高 |
| 生态 | 专注RPC | 全家桶 |
服务注册与发现
Dubbo支持哪些注册中心?
答案:
- Zookeeper(推荐)
- Nacos
- Redis
- Multicast
- Simple
Zookeeper注册中心:
xml
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>yaml
dubbo:
application:
name: dubbo-provider
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: dubbo
port: 20880服务提供者和消费者如何配置?
答案:
服务提供者:
java
// 1. 定义接口
public interface UserService {
User getUser(Long id);
}
// 2. 实现接口
@DubboService(version = "1.0.0", timeout = 3000)
public class UserServiceImpl implements UserService {
@Override
public User getUser(Long id) {
return new User(id, "张三");
}
}
// 3. 启动类
@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}服务消费者:
java
@RestController
public class UserController {
@DubboReference(version = "1.0.0", timeout = 3000)
private UserService userService;
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id);
}
}通信协议
Dubbo支持哪些协议?
答案:
| 协议 | 特点 | 适用场景 |
|---|---|---|
| dubbo | 单一长连接,NIO异步通信 | 小数据量大并发 |
| rmi | JD | 常规远程调用 |
| hessian | HTTP短连接,传输Hessian二进制 | 跨语言调用 |
| http | HTTP短连接,传输JSON | 数据包大小混合 |
| webservice | SOAP协议 | 系统集成 |
| thrift | 跨语言 | 跨语言调用 |
| grpc | HTTP/2,Protobuf | 高性能跨语言 |
Dubbo协议(默认):
yaml
dubbo:
protocol:
name: dubbo
port: 20880
threads: 200 # 业务线程池大小
payload: 8388608 # 最大消息长度8M特点:
- 单一长连接
- NIO异步传输
- 适合小数据量大并发
- 不适合传输大文件
如何配置多协议?
答案:
yaml
dubbo:
protocols:
- id: dubbo
name: dubbo
port: 20880
- id: rest
name: rest
port: 8080java
// 指定协议
@DubboService(protocol = "dubbo")
public class UserServiceImpl implements UserService {
}
@DubboService(protocol = "rest")
public class OrderServiceImpl implements OrderService {
}负载均衡
Dubbo的负载均衡策略?
答案:
| 策略 | 说明 |
|---|---|
| Random(默认) | 随机,按权重设置随机概率 |
| RoundRobin | 轮询,按权重设置轮询比率 |
| LeastActive | 最少活跃调用数 |
| ConsistentHash | 一致性Hash,相同参数请求总是发到同一提供者 |
配置方式:
1. 服务端配置:
java
@DubboService(loadbalance = "random", weight = 100)
public class UserServiceImpl implements UserService {
}2. 客户端配置:
java
@DubboReference(loadbalance = "roundrobin")
private UserService userService;3. 方法级配置:
java
@DubboService
public class UserServiceImpl implements UserService {
@Method(loadbalance = "leastactive")
public User getUser(Long id) {
return new User(id, "张三");
}
}一致性Hash负载均衡的应用?
答案:
适用于有状态服务,保证相同参数的请求总是发到同一台机器。
java
@DubboReference(
loadbalance = "consistenthash",
parameters = {"hash.arguments", "0"} // 根据第一个参数hash
)
private UserService userService;应用场景:
- 缓存服务(避免缓存失效)
- 会话保持
- 分片存储
容错机制
Dubbo的容错策略?
答案:
| 策略 | 说明 |
|---|---|
| Failover(默认) | 失败自动切换,重试其他服务器 |
| Failfast | 快速失败,只发起一次调用 |
| Failsafe | 失败安全,出现异常直接忽略 |
| Failback | 失败自动恢复,后台记录失败请求,定时重发 |
| Forking | 并行调用多个服务器,只要一个成功即返回 |
| Broadcast | 广播调用所有提供者,任意一个报错则报错 |
配置示例:
java
// Failover - 失败重试
@DubboReference(
cluster = "failover",
retries = 2 // 重试2次,总共调用3次
)
private UserService userService;
// Failfast - 快速失败(适合写操作)
@DubboReference(cluster = "failfast")
private OrderService orderService;
// Forking - 并行调用
@DubboReference(
cluster = "forking",
parameters = {"forks", "2"} // 并行调用2个
)
private ProductService productService;如何实现服务降级?
答案:
1. Mock降级:
java
@DubboReference(mock = "return null") // 返回null
private UserService userService;
@DubboReference(mock = "return {\"id\":0,\"name\":\"默认用户\"}") // 返回JSON
private UserService userService;
@DubboReference(mock = "com.example.UserServiceMock") // 自定义Mock类
private UserService userService;2. 自定义Mock类:
java
public class UserServiceMock implements UserService {
@Override
public User getUser(Long id) {
return new User(0L, "降级用户");
}
}3. 动态降级:
java
// 屏蔽服务
RegistryFactory registryFactory = ExtensionLoader
.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://localhost:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.example.UserService?category=configurators&dynamic=false&enabled=true&mock=force:return+null"));服务治理
Dubbo的超时和重试?
答案:
超时配置:
java
// 全局超时
dubbo.consumer.timeout=3000
// 服务级超时
@DubboReference(timeout = 5000)
private UserService userService;
// 方法级超时
@DubboService
public class UserServiceImpl implements UserService {
@Method(timeout = 2000)
public User getUser(Long id) {
return new User(id, "张三");
}
}优先级:方法级 > 服务级 > 全局
重试配置:
java
@DubboReference(
timeout = 3000,
retries = 2 // 重试2次
)
private UserService userService;注意:
- 幂等操作(查询、删除)可以重试
- 非幂等操作(新增)不要重试
Dubbo的服务限流?
答案:
1. 连接数限制:
java
// 服务端限制
@DubboService(connections = 10) // 最多10个连接
public class UserServiceImpl implements UserService {
}
// 客户端限制
@DubboReference(connections = 5)
private UserService userService;2. 并发数限制:
java
// 服务端限制
@DubboService(executes = 10) // 最多10个并发
public class UserServiceImpl implements UserService {
}
// 客户端限制
@DubboReference(actives = 5) // 最多5个并发
private UserService userService;3. TPS限流:
java
@DubboService(
filter = "tps",
parameters = {"tps", "100"} // 每秒100次
)
public class UserServiceImpl implements UserService {
}Dubbo的服务分组和版本?
答案:
版本控制:
java
// 提供者
@DubboService(version = "1.0.0")
public class UserServiceImplV1 implements UserService {
}
@DubboService(version = "2.0.0")
public class UserServiceImplV2 implements UserService {
}
// 消费者
@DubboReference(version = "1.0.0") // 调用1.0版本
private UserService userService;
@DubboReference(version = "*") // 随机调用任意版本
private UserService userService;分组:
java
// 提供者
@DubboService(group = "groupA")
public class UserServiceImplA implements UserService {
}
@DubboService(group = "groupB")
public class UserServiceImplB implements UserService {
}
// 消费者
@DubboReference(group = "groupA")
private UserService userService;
@DubboReference(group = "*") // 调用所有分组并合并结果
private UserService userService;高级特性
Dubbo的异步调用?
答案:
1. CompletableFuture异步调用:
java
// 接口定义
public interface UserService {
CompletableFuture<User> getUserAsync(Long id);
}
// 实现
@DubboService
public class UserServiceImpl implements UserService {
@Override
public CompletableFuture<User> getUserAsync(Long id) {
return CompletableFuture.supplyAsync(() -> {
return new User(id, "张三");
});
}
}
// 调用
@DubboReference
private UserService userService;
public void test() {
CompletableFuture<User> future = userService.getUserAsync(1L);
future.thenAccept(user -> {
System.out.println(user.getName());
});
}2. 异步调用同步接口:
java
@DubboReference(async = true)
private UserService userService;
public void test() {
User user = userService.getUser(1L); // 立即返回null
CompletableFuture<User> future = RpcContext.getContext().getCompletableFuture();
future.thenAccept(u -> {
System.out.println(u.getName());
});
}Dubbo的泛化调用?
答案:
不需要服务接口,直接通过GenericService调用。
java
@DubboReference(
interfaceName = "com.example.UserService",
generic = true
)
private GenericService genericService;
public void test() {
Object result = genericService.$invoke(
"getUser", // 方法名
new String[]{"java.lang.Long"}, // 参数类型
new Object[]{1L} // 参数值
);
}应用场景:
- 网关服务
- 测试平台
- 服务Mock
Dubbo的SPI机制?
答案:
Dubbo的SPI(Service Provider Interface)是对JDK SPI的增强。
特点:
- 支持按需加载
- 支持AOP和IOC
- 支持自适应扩展
使用示例:
java
// 1. 定义接口
@SPI("dubbo") // 默认实现
public interface Protocol {
<T> Exporter<T> export(Invoker<T> invoker);
}
// 2. 实现类
public class DubboProtocol implements Protocol {
@Override
public <T> Exporter<T> export(Invoker<T> invoker) {
// 实现
}
}
// 3. 配置文件 META-INF/dubbo/com.example.Protocol
dubbo=com.example.DubboProtocol
http=com.example.HttpProtocol
// 4. 使用
Protocol protocol = ExtensionLoader
.getExtensionLoader(Protocol.class)
.getExtension("dubbo");练习题
- Dubbo如何实现服务的优雅上下线?
- Dubbo的线程模型是怎样的?
- 如何排查Dubbo服务调用超时问题?
- Dubbo如何实现灰度发布?
- Dubbo 3.0的主要新特性有哪些?