目录
默认维护单一长连接客户端
(31条消息) dubbo虽然Protocol的@SPI指定了‘dubbo’却执行先RegistryProtocol后DubboProtocol_noob_can的博客-优快云博客https://blog.youkuaiyun.com/noob_can/article/details/125180669provider侧:默认开启20880端口,启动一个NettyServer。
consumer侧: 在@Reference侧可设置'connections',默认是0。 只有当connections == 0时,才一个服务对应一个共享的连接客户端; 否则每个service会创建connections个客户端, 在调用时维护一个累加计数来轮询。 这里的客户端会设置keepAlive。
配置的优先级
属性配置 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/configuration/properties/
自动加载 classpath 根目录下的 dubbo.properties,可以使用 JVM 参数来指定路径:
-Ddubbo.properties.file=xxx.properties
优先级从高到低:
- java -D 参数:当部署或者启动应用时,它可以轻易地重写配置,eg. 改变 dubbo 协议端口;
- xml:xml中的配置;
- properties:默认配置,仅仅作用于以上两者没有配置时。
如果在 classpath 下有多个 dubbo.properties 文件(eg. 两个 jar 包都各自包含了 dubbo.properties),dubbo 将随机选择一个加载,并且打印错误日志。
不同粒度配置的覆盖关系
XML 配置 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/configuration/xml/
以 timeout 为例,下图显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似:
- 方法级优先,接口级次之。
- 如果级别一样,则消费方优先,提供方次之;
- 最后是全局配置。
其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。
建议在Provider端尽量多配置Consumer端属性
推荐用法 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/recommend/Provider 端尽量多配置 Consumer 端的属性,让 Provider 的实现者一开始就思考 Provider 端的服务特点和质量等问题:
- 作为服务的提供方,比服务消费方更清楚服务的性能参数,如调用的超时时间、合理的重试次数等
- 在 Provider 端配置后,Consumer 端不配置则会使用 Provider 端的配置。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 是不可控的,并且往往是不合理的。
建议在 Provider配置的 Consumer属性
timeout
:方法调用的超时时间retries
:失败重试次数,缺省是 2 。加上第一次调用,会调用 3 次loadbalance
:负载均衡算法,缺省是随机random
。还可以配置轮询roundrobin
、最不活跃优先leastactive
和一致性哈希consistenthash
等actives
:消费者端的最大并发调用限制,即当 Consumer 对一个服务的并发调用到上限后,新调用会阻塞直到超时。在方法上配置dubbo:method
则针对该方法进行并发限制,在接口上配置dubbo:service
,则针对该服务进行并发限制
建议在 Provider配置的 Provider属性
threads
:服务线程池大小executes
:一个服务提供者并行执行请求上限,即当 Provider 对一个服务的并发调用达到上限后,新调用会阻塞,此时 Consumer 可能会超时。在方法上配置dubbo:method
则针对该方法进行并发限制,在接口上配置dubbo:service
,则针对该服务进行并发限制
配置 Dubbo 缓存文件
该文件会缓存注册中心列表和服务提供者列表。配置缓存文件后,应用重启过程中,若注册中心不可用,应用会从该缓存文件读取服务提供者列表:
<dubbo:registry file=”${user.home}/output/dubbo.cache” />
消费者启动时,没有提供者是否抛异常取决于 ‘check’
<dubbo:reference interface="com.alibaba.xxx.XxxService" check="false" />
直连提供者 @Reference指定url
直连提供者 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/examples/explicit-target/
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。
2.0
以上版本自动加载 ${user.home}/dubbo-resolve.properties文件,不需要配置 。也可以用 -Ddubbo.resolve.file
指定映射文件路径:
java -Ddubbo.resolve.file=xxx.properties
json泛化调用
json泛化调用 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-invoke-with-json/使用泛化调用 | Apache Dubbo
https://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-reference/泛化接口调用方式主要用于客户端没有api接口及DTO结构的情况,参数及返回值中的所有对象均用
Map
表示,通常用于框架集成。
@Reference 申明订阅接口时,指定generic="true";使用'$invoke'方法指定远程方法和参数。
GenericService genericService = (GenericService) applicationContext.getBean("barService");
// 基本类型以及Date,List,Map等不需要转换,直接调用
Object result = genericService.$invoke("sayHello", new String[] {"java.lang.String"}, new Object[] {"world"});
// 用Map表示POJO参数,如果返回值为POJO也将自动转成Map
Map<String, Object> person = new HashMap<String, Object>();
person.put("name", "xxx");
person.put("password", "yyy");
// 如果返回POJO将自动转成Map
Object result = genericService.$invoke("findPerson", new String[] {"com.xxx.Person"}, new Object[]{person});
利用mock实现服务降级
本地伪装 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/examples/local-mock/Mock 是 Stub 的一个子集,便于服务提供方在客户端执行容错逻辑,因经常需要在出现 RpcException (比如网络失败,超时等)时进行容错,而在出现业务异常(比如登录用户名密码错误)时不需要容错,如果用 Stub,可能就需要捕获并依赖 RpcException 类,而用 Mock 就可以不依赖 RpcException,因为它的约定就是只有出现 RpcException 时才执行。
当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。
在 spring 配置文件中按以下方式配置:
<dubbo:reference interface="com.foo.BarService" mock="true" />
<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
如果指定降级的是类,则需要在mock类里实现相同方法返回伪造数据。
在 2.0.11
以上版本可用return 语法来指定返回内。eg. null 、true|false、json...
<dubbo:reference interface="com.foo.BarService" mock="return null" />
在 2.6.6
以上的版本,可以开始在 Spring XML 配置文件中使用 fail:
和 force:
。force:
代表强制使用 Mock 行为,在这种情况下不会走远程调用。fail:
与默认行为一致,只有当远程调用发生错误时才使用 Mock 行为。force:
和 fail:
都支持与 throw
或者 return
组合使用。
强制返回指定值:
<dubbo:reference interface="com.foo.BarService" mock="force:return fake" />
强制抛出指定异常:
<dubbo:reference interface="com.foo.BarService" mock="force:throw com.foo.MockException" />
在方法级别配置 Mock
假定 com.foo.BarService
上有好几个方法,可以单独为 sayHello()
方法指定 Mock 行为。
具体配置如下所示,在本例中,只要 sayHello()
被调用到时,强制返回 “fake”:
<dubbo:reference id="demoService" check="false" interface="com.foo.BarService">
<dubbo:parameter key="sayHello.mock" value="force:return fake"/>
</dubbo:reference>
Stub 本地存根
通常客户端通常只剩下接口引用,远程调用服务端的具体实现。但Consumer若想在客户端也执行部分逻辑,那么就在Consumer端提供一个Stub类。
当Consumer调用provider方提供的dubbo服务时,客户端生成 Proxy 实例,这个Proxy实例就是正常调用dubbo远程服务要生成的代理实例,然后消费者这方会把 Proxy 通过构造函数传给Stub ,然后把 Stub 暴露出来,Stub 可以决定要不要去调 Proxy。通过代理类去完成这个调用,这样在Stub类中,就可以做一些额外的事,来对服务的调用过程进行优化或者容错的处理。附图:
(本地存根的工作方式与 AOP 的 around advice 类似,而本地伪装的工作方式等同于 AOP 中的 after-throwing advice,也就是说,只有当远程调用发生 exception 的时候才会执行本地伪装。)
<dubbo:reference id="userService" interface="org.huxin.dubbo.test.user.service.UserInterface"
stub="org.huxin.dubbo.test.UserServiceStub" protocol="dubbo"/>
默认暴露并优先引用 本地调用injvm协议
本地调用 | Apache Dubbohttps://dubbo.apache.org/zh/docs/v2.7/user/examples/local-call/该协议不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链!
Dubbo 从 2.2.0
每个服务默认都会在本地暴露,无需进行任何配置即可默认优先引用本地服务,如果不希望服务进行远程暴露,只需要在 provider 将 protocol 设置成 injvm 即可。如果希望引用远程服务可以使用一下配置强制引用远程服务。
<dubbo:reference ... scope="remote" />
延迟暴露 Dubbo 服务
无损上线: 如果服务需要预热时间,比如初始化缓存,等待相关资源就位等,可以使用 delay 进行延迟暴露, 这样就不会导致消费端在高并发情况下负载到这台服务器导致接口异常!
com.alibaba.dubbo.config.annotation.Service : delay 默认是0 ,不延时。
延迟到 Spring 初始化完成后,再暴露服务
<dubbo:service delay="-1" />
ServiceBean 实现了接口 InitializingBean、ApplicationContextAware、ApplicationListener<ContextRefreshedEvent>。
那执行的先后顺序如下:
- 先 InitializingBean#afterPropertiesSet: 判定是否立刻执行#export发布过程
- 后 ApplicationListener#onApplicationEvent: 捕获当Spring容器初始化完成之后抛出的全局事件ContextRefreshedEvent。判定是否还需要执行#export
在#afterPropertiesSet方法逻辑的末尾:判定没有延时才会执行#export发布过程
当Spring容器初始化完成后判定: “delay == null || -1” 则执行#export。
指定延迟 5 秒暴露服务
<dubbo:service delay="5000" />
是在 ServiceBean的父类ServiceConfig#export里判定 “delay > 0” 就使用ScheduledExecutorService来延迟执行发布的整个过程。