Skip to content

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的区别?

答案:

特性DubboSpring 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异步通信小数据量大并发
rmiJD常规远程调用
hessianHTTP短连接,传输Hessian二进制跨语言调用
httpHTTP短连接,传输JSON数据包大小混合
webserviceSOAP协议系统集成
thrift跨语言跨语言调用
grpcHTTP/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: 8080
java
// 指定协议
@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");

练习题

  1. Dubbo如何实现服务的优雅上下线?
  2. Dubbo的线程模型是怎样的?
  3. 如何排查Dubbo服务调用超时问题?
  4. Dubbo如何实现灰度发布?
  5. Dubbo 3.0的主要新特性有哪些?

Released under the MIT License.