一次RPC调用
1. 创建Invoker
- 配置覆盖策略
- -D传递给JVM参数优先级最高
- 代码或XML配置优先级次高
- 配置文件优先级最低
- consumer配置会覆盖provider配置
- JdkProxyFactory:该模式是我们常见的用法,通过反射获取真实对象的方法,然后调用即可。
- JavassistProxyFactory:创建Wrapper子类,在子类中实现invokeMethod方法,方法体内会为每个ref方法都做方法名和方法参数的 匹配校验,如果匹配则直接调用即可,相比JdkProxyFactory省去了反射调用的开销。
2. dubbo Cluster
- Failover:循环重试; Failfast:直接抛出异常; Failsafe:返回空结果 ;Failback:定时重试; Avaliable:遍历可用重试 ;Broadcast:广播调用 ;Forking:并行调用
- 下图为 循环重试 和 MOCK执行
Mock实现
- (建议)声明业务接口的mock实现:xxxxMock
- consumer直接指定mock接口:
@Reference(version = "1.0.0", mock = "return null")
private IDubboApi dubboApi;
3. 路由选择
条件路由
- 应用粒度
# app1的消费者只能消费所有端口为20880的服务实例
# app2的消费者只能消费所有端口为20881的服务实例
---
scope: application
force: true
runtime: true
enabled: true
key: governance-conditionrouter-consumer
conditions:
- application=app1 => address=*:20880
- application=app2 => address=*:20881
...
- 服务粒度
# DemoService的sayHello方法只能消费所有端口为20880的服务实例
# DemoService的sayHi方法只能消费所有端口为20881的服务实例
---
scope: service
force: true
runtime: true
enabled: true
key: org.apache.dubbo.samples.governance.api.DemoService
conditions:
- method=sayHello => address=*:20880
- method=sayHi => address=*:20881
...
- 参数说明
参数名称 | 含义 |
scope | 表示路由规则的作用粒度,scope的取值会决定key的取值。必填。 |
force | 当路由结果为空时,是否强制执行,如果不强制执行,则路由结果为空的路由规则将自动失效,选填,默认为false |
enabled | 当前路由规则是否生效,可不填,缺省生效。 |
key | 明确规则体作用在哪个服务或应用。必填。 |
runtime | 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 true,需要注意设置会影响调用的性能,可不填,缺省为 false |
priority | 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 0。 |
conditions | 定义具体的路由规则内容。必填。 |
标签路由
- dubbo框架提供了根据tag对流量进行划分的特性。
4. 负载均衡
一致性hash
- 公共的特性 :1.粘滞连接;2.可用检测 ;3.避免重复调用
Invoker的选择
5. 过滤器
- 自定义dubboFilter,实现只要将数据data设置一次到RpcContext.Attachment中的,就可以在多次dubbo调用中传递
@Activate(
group = {"consumer"}
)
public class DubboInvokeFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(DubboInvokeFilter.class);
public DubboInvokeFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String data = ThreadContext.getData();
if (StringUtils.isNotEmpty(data)) {
RpcContext.getContext().setAttachment("data", data);
}
return invoker.invoke(invocation);
}
}
6. 数据传输
编码/解码
报文格式
偏移字节 | 0 | 1 | 2 | 3 | |||||||||||||||||||||||||||||
偏移比特位 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | |
0 | 0 | 魔法数高位 | 魔法数低位 | 请求响应 | 调用类型 | 事件标识 | 序列化器编号 | 状态 | |||||||||||||||||||||||||
4 | 32 | RPC请求id | |||||||||||||||||||||||||||||||
8 | 64 | ||||||||||||||||||||||||||||||||
12 | 96 | 消息体数据长度 | |||||||||||||||||||||||||||||||
16 | 126 | dubbo version、service name、service version、method name、parameter types、arguments、attachments |
7. 线程池
- I/O线程池:主要处理读写、序列化和 反序列化等逻辑。
- Dubbo业务线程池:主要处理具体业务逻辑,反序列化逻辑也可由业务线程处理。
8. 服务暴露/注册