Dubbo学习笔记

关于 Dubbo 以前也用过几次,都是浅度学习,也没做笔记,今天看了下官网竟然改版了,手册更新了,借这个契机来复习下,并且做下笔记,内容大部分来自官方手册。
官网:https://dubbo.incubator.apache.org
旧版的用户使用手册:https://www.gitbook.com/book/dubbo/dubbo-user-book
官方文档开始的背景介绍写的挺不错的,可以去参考下,曾经的 ORM、MVC,到现在的分布式 RPC 和 SOA。

架构

个人感觉 Dubbo 的架构设计是很不错的,官网的文档也解释的很详细:dubbo-architucture

节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器

调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
我认为 Dubbo 适用于比较大、复杂的服务调用需求的系统,一般的中小型使用通过配置服务的 URL 地址进行调用,通过 F5 等硬件进行负载均衡(或者通过 RMI 或 Hessian 等工具,简单的暴露和引用远程服务 )这样就足够了。

连通性

  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
  • 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
  • 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
  • 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者

健壮性

  • 监控中心宕掉不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

伸缩性

  • 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
  • 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者

快速入门

仿照官方文档,最简单的代码示例放在了我 Github 上的 Java_lean 仓库里,自取…..配置了 xml 版和注解版(推荐),Dubbo 采用全 Spring 配置方式,能基于 Spring 的 Schema 扩展进行加载,Dubbo 宣称能与 Spring(SpringBoot) 无缝整合,不能浪费。
就是添加了 Dubbo 的依赖,根据传递性,就自动导入了 Spring 相关依赖,所以测试的话只需要一个 Dubbo、zookeeper 、zkclient 和你定义的接口就可以了!
另外就是 Dubbo 底层用的是 netty 做通讯,所以效率会较高。
在搭建测试的时候终究还是踩了不少坑,记录在这里附上了解决方案。在使用注解方式时,尤其注意 <dubbo:annotation> 在 2.5.8 之后的版本不再支持了!请使用 @Configuration 大法解决。


XML配置

关于 XML 的基本配置,主要是服务的提供方和消费方,配置非常类似:
服务提供方(remote-provider.xml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息(当前应用名称),用于计算依赖关系 -->
<dubbo:application name="dubbo-provider"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 使用 dubbo 协议,在 20880 端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/>

<!-- 配置需要提供远程服务的对象 -->
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<!-- 增加暴露远程服务配置 -->
<dubbo:service interface=“com.xxx.XxxService” ref=“xxxService” />
</beans>

服务消费方(remote-consumer.xml):

1
2
3
4
5
6
7
8
9
10
11
<!-- 不是匹配条件,不要与提供方一样 -->
<dubbo:application name="dubbo-consumer"/>
<!-- 使用zookeeper广播注册中心暴露发现服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />

<!-- 增加引用远程服务配置 -->
<dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” />
<!-- 和本地服务一样使用远程服务 -->
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>

以上就是最简单的纯 XML 方式使用 Dubbo,用的不多了吧,毕竟 XML 太繁琐了。
另外就是所有标签都支持自定义参数(通过子标签 <dubbo:parameter key="queue" value="your_queue" />),用于不同扩展点实现的特殊配置 。
引用缺省是延迟初始化的,只有引用被注入到其它 Bean,或被 getBean() 获取,才会初始化,如需立即实例化,可配置:<dubbo:reference ... init="true" />
对于相同的属性,例如 timeout 查找(优先级)顺序是: referenceMethod --> serviceMethod --> reference --> service --> consumer --> provider


注解配置

需要 2.5.7 及以上版本支持,使用注解的方式配置:
使用 javaconfig 形式配置公共模块:

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
@Configuration
public class DubboConfiguration {
@Bean
public ApplicationConfig applicationConfig() {
// 相当于 <dubbo:application>
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("provider-test");
return applicationConfig;
}

@Bean
public RegistryConfig registryConfig() {
// 相当于 <dubbo:registry>
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
registryConfig.setClient("curator");
return registryConfig;
}

// 对于消费方,还可以配一个 consumerConfig
@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setTimeout(3000);
return consumerConfig;
}
}

指定 Dubbo 的扫描路径,就是自动扫描,提供方和消费方都是一样的配置:

1
2
3
4
5
@SpringBootApplication
@DubboComponentScan(basePackages = "com.alibaba.dubbo.test.service.impl")
public class ProviderTestApp {
// ...
}

再次强调,2.5.8 之后 <dubbo:annotation> 不再可用!
服务提供方:

1
2
3
4
@Service(timeout = 5000)
public class AnnotateServiceImpl implements AnnotateService {
// ...
}

相当于 XML 中的 <dubbo:service /> 用来暴露服务。
服务消费方:

1
2
3
4
5
public class AnnotationConsumeService {
// 就是自动注入了
@Reference
public AnnotateService annotateService;
}

properties配置

在比较简单的情况下,例如没有多注册中心,多协议等情况,或者想多个 Spring 容器想共享配置,Dubbo 将自动加载 classpath 根目录下的 dubbo.properties,可以通过 JVM 启动参数 -Ddubbo.properties.file=xxx.properties 改变缺省配置位置。
将 XML 配置的标签名,加属性名,用点分隔,多个属性拆成多行:

  • 比如:dubbo.application.name=foo等价于<dubbo:application name="foo" />
  • 比如:dubbo.registry.address=10.20.153.10:9090等价于<dubbo:registry address="10.20.153.10:9090" />

如果 XML 有多行同名标签配置,可用 id 号区分,如果没有 id 号将对所有同名标签生效:

  • 比如:dubbo.protocol.rmi.port=1234等价于<dubbo:protocol id="rmi" name="rmi" port="1099" />
  • 比如:dubbo.registry.china.address=10.20.153.10:9090等价于<dubbo:registry id="china" address="10.20.153.10:9090" />

下面是 dubbo.properties 的一个典型配置:

1
2
3
dubbo.application.name=foo
dubbo.application.owner=bar
dubbo.registry.address=10.20.153.10:9090

关于优先级,JVM 启动参数 -D 最优先,其次是 XML 的配置,最后是 properties 文件。

启动时检查

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成 ,默认 check="true"。 所以说,启动是有顺序的,默认下必须要服务方先启动。
check 属性可以加在 dubbo:reference 、dubbo:consumer 、dubbo:registry 标签中,分别控制的是:
某个服务的启动时检查(没有提供者时报错 )、所有服务的启动时检查、注册中心启动时检查(注册订阅失败时报错)。
优先级是 reference > consumer ,还可以设置全局参数,例如:dubbo.reference.check=falsedubbo.consumer.check=false

集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。

cluster

根据上面的架构图,理下各节点关系:

  • 这里的 InvokerProvider(服务提供方) 的一个可调用 Service 的抽象,Invoker 封装了 Provider 地址及 Service 接口信息。
  • Directory 代表多个 Invoker,可以把它看成 List<Invoker> ,但与 List 不同的是,它的值可能是动态变化的,比如注册中心推送变更。
  • Cluster(集群)Directory 中的多个 Invoker 伪装成一个 Invoker对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个。
  • Router 负责从多个 Invoker 中按路由规则选出子集,比如读写分离,应用隔离等。
  • LoadBalance 负责从多个 Invoker选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选。

容错模式

Dubbo 提供的容错模式有:

  • Failover Cluster
    默认的故障转移模式,就是失败自动切换,当出现失败,重试其它服务器 。通常用于读操作,但重试会带来更长延迟。
    可通过 retries 属性来指定重试的次数(不含第一次)
  • Failfast Cluster
    快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
  • Failsafe Cluster
    失败安全(指不会抛出异常),出现异常时,直接忽略。通常用于写入审计日志等操作。
  • Failback Cluster
    失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
  • Forking Cluster
    并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
  • Broadcast Cluster
    广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

集群配置模式(以 XML 为例):

1
2
3
4
<!-- 服务提供方 -->
<dubbo:service cluster="failsafe" />
<!-- 服务消费方 -->
<dubbo:reference cluster="failsafe" />

负载均衡

在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用。可以自行扩展负载均衡策略。

负载均衡策略

  • Random LoadBalance
    随机,按权重设置随机概率。
    在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
  • RoundRobin LoadBalance
    轮循,按公约后的权重设置轮循比率。
    存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
  • LeastActive LoadBalance
    最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
    使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
  • ConsistentHash LoadBalance
    一致性 Hash相同参数的请求总是发到同一提供者。
    当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
    缺省只对第一个参数 Hash (由 hash.arguments 参数控制)。
    缺省用 160 份虚拟节点(由 hash.nodes 参数控制)。

配置

示例为基于 XML 的配置:

1
2
3
4
5
6
<!-- 服务端服务级别 -->
<dubbo:service interface="..." loadbalance="roundrobin" />
<!-- 客户端服务级别 -->
<dubbo:reference interface="..." loadbalance="roundrobin" />

<!-- 方法级别调用配在 <dubbo:method> 中 -->

直连提供者

在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。
通过 XML 来配置直接的提供者,在 <dubbo:reference> 中配置 url 指向提供者,将绕过注册中心,多个地址用分号隔开:<dubbo:reference id="xxxService" interface="com.alibaba.xxx.XxxService" url="dubbo://localhost:20890" />
除外,还可以通过 -D 参数来指定:java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890
配置的服务如果较多,可采用文件(properties)映射。

只订阅&注册

为方便开发测试,经常会在线下共用一个所有服务可用的注册中心,这时,如果一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。
可以让服务提供者开发方,只订阅服务(开发的服务可能依赖其它服务),而不注册正在开发的服务,通过直连测试正在开发的服务。
配置方式:

1
2
3
<dubbo:registry address="10.20.153.10:9090" register="false" />
<!-- 或者 -->
<dubbo:registry address="10.20.153.10:9090?register=false" />

对于只注册的情况,例如让服务提供者方只注册服务到某一注册中心,而消费方不从另外的注册中心订阅服务。

1
2
3
4
5
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" />
<dubbo:registry id="qdRegistry" address="10.20.141.150:9090" subscribe="false" />
<!-- 或者 -->
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" />
<dubbo:registry id="qdRegistry" address="10.20.141.150:9090?subscribe=false" />

多协议

Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。

不同服务不同协议

不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议

1
2
3
4
5
6
7
8
9
<dubbo:application name="world"  />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />
<!-- 使用dubbo协议暴露服务 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
<!-- 使用rmi协议暴露服务 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" />

多协议暴露服务

需要与 http 客户端互操作

1
2
3
4
5
6
7
<dubbo:application name="world"  />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="hessian" port="8080" />
<!-- 使用多个协议暴露服务 -->
<dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />

当然,Dubbo 也支持多注册中心。

Dubbo协议

默认协议,也是推荐的协议,这里就只说它,关于 dubbo:// 的基本介绍:

Dubbo 缺省协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。

特性:

  • 连接个数:单连接
  • 连接方式:长连接
  • 传输协议:TCP
  • 传输方式:NIO 异步传输
  • 序列化:Hessian 二进制序列化
  • 适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。
  • 适用场景:常规远程服务方法调用

接口增加方法,对客户端无影响,如果该方法不是客户端需要的,客户端不需要重新部署。输入参数和结果集中增加属性,对客户端无影响,如果客户端并不需要新属性,不用重新部署。
输入参数和结果集属性名变化,对客户端序列化无影响,但是如果客户端不重新部署,不管输入还是输出,属性名变化的属性值是获取不到的。
总结:服务器端和客户端对领域对象并不需要完全一致,而是按照最大匹配原则。

服务分组&多版本

当一个接口有多种实现时,可以用 group 区分。
XML 配置示例:

1
2
3
4
5
6
7
8
<!-- 服务 -->
<dubbo:service group="feedback" interface="com.xxx.IndexService" />
<dubbo:service group="member" interface="com.xxx.IndexService" />
<!-- 引用 -->
<dubbo:reference id="feedbackIndexService" group="feedback" interface="com.xxx.IndexService" />
<dubbo:reference id="memberIndexService" group="member" interface="com.xxx.IndexService" />
<!-- 任意组 -->
<dubbo:reference id="barService" interface="com.foo.BarService" group="*" />

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 XML 配置示例:

1
2
3
4
5
6
7
8
9
10
<!-- 服务提供者 -->
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
<dubbo:service interface="com.foo.BarService" version="2.0.0" />

<!-- 服务消费者 -->
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />

<!-- 如果不需要区分版本 -->
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

官方给的版本迁移建议:

  1. 在低压力时间段,先升级一半提供者为新版本
  2. 再将所有消费者升级为新版本
  3. 然后将剩下的一半提供者升级为新版本

结果缓存

用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量 。

缓存类型

  • lru
    基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。
  • threadlocal
    当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。
  • jcache
    JSR107 集成,可以桥接各种缓存实现。

XML 配置示例:

1
2
3
4
5
<dubbo:reference interface="com.foo.BarService" cache="lru" />
<!-- 或者 -->
<dubbo:reference interface="com.foo.BarService">
<dubbo:method name="findBar" cache="lru" />
</dubbo:reference>

异步调用

基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。
首先,在 XML 中开启异步支持:

1
2
3
4
5
6
<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService">
<dubbo:method name="findFoo" async="true" />
</dubbo:reference>
<dubbo:reference id="barService" interface="com.alibaba.bar.BarService">
<dubbo:method name="findBar" async="true" />
</dubbo:reference>

代码中进行异步调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 此调用会立即返回null
fooService.findFoo(fooId);
// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
Future<Foo> fooFuture = RpcContext.getContext().getFuture();

// 此调用会立即返回null
barService.findBar(barId);
// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
Future<Bar> barFuture = RpcContext.getContext().getFuture();

// 此时findFoo和findBar的请求同时在执行,客户端不需要启动多线程来支持并行,而是借助NIO的非阻塞完成

// 如果foo已返回,直接拿到返回值,否则线程wait住,等待foo返回后,线程会被notify唤醒
Foo foo = fooFuture.get();
// 同理等待bar返回
Bar bar = barFuture.get();

// 如果foo需要5秒返回,bar需要6秒返回,实际只需等6秒,即可获取到foo和bar,进行接下来的处理。

是否等待消息发出(配置在 dubbo:method 中即可):

  • sent="true" 等待消息发出,消息发送失败将抛出异常。
  • sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。

如果你只是想异步,完全忽略返回值,可以配置 return="false",以减少 Future 对象的创建和管理成本
其中,异步方式总是不等待返回

并发&连接控制

通过在 dubbo:service 标签中设置 executes 属性来控制服务器端并发执行(或占用线程池线程数)不能超过的个数。
通过设置 actives 属性(可在 dubbo:reference/service 中设置)来控制每客户端并发执行(或占用连接的请求数)不能超过的个数。
如果 <dubbo:service><dubbo:reference> 都配了actives,<dubbo:reference> 优先。

Load Balance 均衡

配置服务的客户端的 loadbalance 属性为 leastactive,此 Loadbalance 会调用并发数最小的 Provider(Consumer端并发数)。 可在 dubbo:reference/service 中设置。


连接控制分为服务端的连接控制和客户端的连接控制,XML 配置示例:

1
2
3
4
5
6
7
<!-- 限制服务器端接受的连接不能超过 10 个,两种方式 -->
<dubbo:provider protocol="dubbo" accepts="10" />
<dubbo:protocol name="dubbo" accepts="10" />

<!-- 限制客户端服务使用连接不能超过 10 个,两种方式 -->
<dubbo:reference interface="com.foo.BarService" connections="10" />
<dubbo:service interface="com.foo.BarService" connections="10" />

如果 <dubbo:service><dubbo:reference> 都配了 connections,<dubbo:reference> 优先.

其他

列举下没用过,但是可能会用到的,所以这些并不全,最全的还要去官网的示例看:

  • 分组聚合
    接口一样,但有多种实现,用 group 区分,现在消费方需从每种 group 中调用一次返回结果,合并结果返回。
  • 回声测试
    回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。
    所有服务自动实现 EchoService 接口,只需将任意服务引用强制转型为 EchoService,即可调用 $echo("OK") 方法看看是否返回 OK
  • 上下文信息
    上下文中存放的是当前调用过程中所需的环境信息(获取提供方 IP、判断是否为消费端等)。所有配置信息都将转换为 URL 的参数;
    RpcContext 是一个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态都会变化。
  • 隐式参数
    通过 RpcContext 上的 setAttachmentgetAttachment 在服务消费方和提供方之间进行参数的隐式传递。
    例如:RpcContext.getContext().set/getAttachment()
  • 本地调用
    本地调用使用了 injvm 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。
  • 参数回调&事件通知
    参数回调方式与调用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可。Dubbo 将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。
    在调用之前、调用之后、出现异常时,会触发 oninvoke、onreturn、onthrow 三个事件,可以配置当事件发生时,通知哪个类的哪个方法。
  • 延迟连接
    延迟连接用于减少长连接数。当有调用发起时,再创建长连接。

推荐用法

在 Provider(提供方) 上尽量多配置 Consumer(消费方) 端属性:

  • 作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
  • 在 Provider 配置后,Consumer 不配置则会使用 Provider 的配置值,即 Provider 配置可以作为 Consumer 的缺省值。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 不可控的,并且往往是不合理的。
    覆盖规则:Consumer 端配置优于 Provider 配置,优于全局配置

这样可以让 Provider 实现者一开始就思考 Provider 服务特点、服务质量的问题。
常见的配置有:

  • timeout 方法调用超时
  • retries 失败重试次数,缺省是 2(会调用 3 次)
  • loadbalance 负载均衡算法,缺省是随机 random。还可以有轮询 roundrobin、最不活跃优先 leastactive
  • actives 消费者端,最大并发调用限制,即当 Consumer 对一个服务的并发调用到上限后,新调用会 Wait 直到超时 在方法上配置 dubbo:method 则并发限制针对方法,在接口上配置 dubbo:service,则并发限制针对服务

Provider 上可以配置的 Provider 端属性有:

  • threads 服务线程池大小
  • executes 一个服务提供者并行执行请求上限,即当 Provider 对一个服务的并发调用到上限后,新调用会 Wait,这个时候 Consumer可能会超时。在方法上配置 dubbo:method 则并发限制针对方法,在接口上配置 dubbo:service,则并发限制针对服务。

XML 配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
timeout="300" retry="2" loadbalance="random" actives="0"
/>

<dubbo:service interface="com.alibaba.hello.api.WorldService" version="1.0.0" ref="helloService"
timeout="300" retry="2" loadbalance="random" actives="0" >
<dubbo:method name="findAllPerson" timeout="10000" retries="9" loadbalance="leastactive" actives="5" />
<dubbo:service/>

<!-- Provider 上配置合理的 Provider 端属性 -->
<dubbo:protocol threads="200" />
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
executes="200" >
<dubbo:method name="findAllPerson" executes="50" />
</dubbo:service>

配置管理信息:
目前有负责人信息和组织信息用于区分站点。有问题时便于的找到服务的负责人,至少写两个人以便备份。负责人和组织的信息可以在注册中心的上看到,例如:

1
2
3
4
5
6
<!-- 应用配置负责人、组织 -->
<dubbo:application owner=”ding.lid,william.liangf” organization=”intl” />
<!-- service 配置负责人 -->
<dubbo:service owner=”ding.lid,william.liangf” />
<!-- reference 配置负责人 -->
<dubbo:reference owner=”ding.lid,william.liangf” />

配置 Dubbo 缓存文件(在提供者方设置列表缓存文件):

1
<dubbo:registry file=”${user.home}/output/dubbo.cache” />

文件的路径,应用可以根据需要调整,保证这个文件不会在发布过程中被清除。
如果有多个应用进程注意不要使用同一个文件,避免内容被覆盖。
这个文件会缓存注册中心的列表和服务提供者列表。


对于监控,推荐使用固定端口暴露服务,而不要使用随机端口,这样在注册中心推送有延迟的情况下,消费者通过缓存列表也能调用到原地址,保证调用成功。
最后就是不要使用 dubbo.properties 文件配置,推荐使用对应 XML 配置

喜欢就请我吃包辣条吧!

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~