上一编说到了springboot整合dubbo注解版搭建和最简单的RPC远程调用的基本使用,但是dubbo不仅仅是能进行RPC调用,它也是一个服务治理的框架,官网对dubbo的介绍
Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
现在我们来对dubbo的一些常用参数的作用进行研究
http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-service.html dubbo官网上有生产者与消息者的参数说明
接着上一编的demo作演示,我用的是注解形式。生产者的配置在@Service注解上,消费者的配置在@Reference上
1.check参数:用在@Reference的参数,启动时检查提供者是否存在,true报错,false忽略,默认为true,如果生产者不存在,消费者启动会报错
1.version参数:给服务设定版本
用法:生产者只要在暴露dubbo服务的api的实现类上加上
@Service(version="版本号")就行了
上面生产者启动时com.api.HelloFacade接口会注册两个不同版本的地址,查看一下zookeeper的节点/dubbo/com.api.HelloFacade/providers
[dubbo%3A%2F%2F172.16.19.186%3A20880%2Fcom.api.HelloFacad...version%3D2.0.0, dubbo%3A%2F%2F172.16.19.186%3A20880%2Fcom.api.HelloFacad...version%3D1.0.0]
发现上面有两个地址,用逗号分开,地址最后有version2.0.0和1.0.0。说明这个api服务注册了两个地址到注册中心
消费者调用时,注入服务接口时加上版本
@Reference(version = "1.0.0")
上面结果说明调的是Service(version="1.0.0")的服务实现
改成
@Reference(version = "2.0.0")看看结果
调的是Service(version="2.0.0")的服务实现
注意:如果生产者注册的服务设置了版本,消费者必须指定版本,如果生产没设置版本,消费者可以不指定版本。官方推荐做法是设置版本,版本两位数字如: 1.0
version参数使用场景:如果需要进行灰度发布,一半服务使用1.0.0版本的接口,一半使用2.0.0的接口,就需要用到version
通常在接口不兼容时版本号才需要升级version
2.group参数:服务分组,当一个接口有多个实现,可以用分组区分
上面设定版本号的demo,就是一个接口有多个实现的例子,只是版本号不同,如果版本号相同,服务注册到注册中心上只有一个地址,并且只代理其中一个实现类,现在两个实现类改成都是1.0.0版本,测试结果为是只会HelloFacade2Impl的实现方法,如果我们想要区分,必须加上group
启动生产者服务
[dubbo%3A%2F%2F172.16.19.186%3A20880%2Fcom.api.HelloFacade...group%3Dhello1...version%3D1.0.0, dubbo%3A%2F%2F172.16.19.186%3A20880%2Fcom.api.HelloFacade...group%3Dhello2...version%3D1.0.0]
注册中心节点上有两个相同版本不同group的地址
生产者设置了version和group,消费者调用时必须同时指定version和group
调用hello1组 @Reference(version = "1.0.0",group = "hello1")
结果,访问的就是@Service(version = "1.0.0",group = "hello1")的服务接口实现类
调用hello2组 @Reference(version = "1.0.0",group = "hello2")
结果,访问的就是@Service(version = "1.0.0",group = "hello2")的服务接口实现类
3.timeout参数(默认1000毫秒):远程服务调用超时时间(毫秒),超过时间接口没有响应返回值就会报com.alibaba.dubbo.rpc.RpcException: Invoke remote method timeout异常。
4.retries参数(默认2):远程服务调用重试次数,不包括第一次调用,不需要重试请设为0。
演示一下重试机制
生产者代码,客户端每调用一次都会打印 count
消费者设置timeout=1(1毫秒没有服务端响应就报异常)来模拟抛出异常
调用服务后看生产者的控制台
打印了3次,说明默认调用1次,重试了2次 这是默认的配置
现在修改retries=5,看执行结果
打印了6次,说明重试了5次。
下面说一下dubbo服务治理(限流、容错、服务降级、负载均衡等)的一些配置,都是dubbo集群操作
1.cluster参数:集群容错(最后解释这个名词的意思)
可选方式 failover/failfast/failsafe/failback/forking
失败自动切换,当出现失败,重试其它服务器 。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息
默认配置方式 cluster = "failover",启动两台生产者测试失败自动切换效果
第一台生产者服务,睡眠1.5,模拟超时
第二台生产者服务器返回结果
消费者调用服务时,默认是随机调用的(这个负载均衡策略下面讲到)。
设置调用超时为timeout = 1000 看看调用结果
生产者1的控制台调用了3次
但消费者打印的10次都是 我是生产者2号 (有报错日志,不好全部截图),
说明那3次调用超时后自动重试了生产者2的服务器。
注意:重试机制只会在非业务异常(比如超时,网络异常等)时生效,如果生产者执行过程中抛出异常,如int i =1/0,是不会重试的(重试机制不生效)
2.loadbalance参数:负载均衡策略,
可选值:random(默认值),roundrobin,leastactive,
分别表示:随机,轮询,最少活跃调用
启动两个生产者服务来测试
启动第一台服务返回值
修改dubbo端口,idea把Single...的勾去掉,设置可运行多次main方法
然后启动第二台服务返回值
消费者循环调用10次
看看结果
默认就是随机调用的,设置loadbalance = "roundrobin"看看是不是轮询
每台服务轮询访问,说明了配置生效
3.mock参数:服务降级,服务接口调用失败Mock实现类名,该Mock类必须有一个无参构造函数Mock只在出现非业务异常(比如超时,网络异常等)时执行
用法
创建一个服务降级后调用的类,并实现调用服务的接口
在消费者调用时,加上降级类的全路径,
mock = "com.HelloFacadeMock"
模拟超时场景
我在生产者设置了retries = 3,表示超时重试3次。从日志可以看出,调用了4次之前,还是超时,就会调用服务降级的方法。
结论:服务降级在重试机制执行完之后才会被执行
以上的参数配置,在生产者和消费者都能配置,那么同时配置优先级别是哪个?还有配置哪边比较合适?
优先级别
方法级优先,接口级次之,全局配置再次之。
如果级别一样,则消费方优先,提供方次之。
合理配置
建议在 Provider 端配置的 Consumer 端属性有:
timeout
:方法调用的超时时间
retries
:失败重试次数,缺省是 2
loadbalance
:负载均衡算法 [3],缺省是随机 random
。还可以配置轮询roundrobin
、最不活跃优先 [4] leastactive
和一致性哈希 consistenthash
等
actives
:消费者端的最大并发调用限制,即当 Consumer 对一个服务的并发调用到上限后,新调用会阻塞直到超时,在方法上配置 dubbo:method
则针对该方法进行并发限制,在接口上配置 dubbo:service
,则针对该服务进行并发限制
什么是容错机制?容错机制指的是某种系统控制在一定范围内的一种允许或包容犯错情况的发生,比如调用时某个节点突然挂掉了,会自动切换到另一个集群节点去访问。在分布式架构下,网络、应用都可能发生故障,由于各个服务之间可能存在依赖关系,如果一条链路中的其中一个节点出现故障,将会导致雪崩效应。为了减少某一个节点故障的影响范围,所以我们才需要去构建容错服务,来优雅的处理这种中断的响应结果
降级的目的是为了保证核心服务可用。
降级可以有几个层面的分类:自动降级和人工降级;
按照功能可以分为:读服务降级和写服务降级;
1. 对一些非核心服务进行人工降级,在大促之前通过降级开关关闭哪些推荐内容、评价等对主流程没有影响的功能
2. 故障降级,比如调用的远程服务挂了,网络故障、或者RPC服务返回异常。 那么可以直接降级,降级的方案比如设置默认值、采用兜底数据(系统推荐的行为广告挂了,可以提前准备静态页面做返回)等等
3. 限流降级,在秒杀这种流量比较集中并且流量特别大的情况下,因为突发访问量特别大可能会导致系统支撑不了。这个时候可以采用限流来限制访问量。当达到阀值时,后续的请求被降级,比如进入排队页面,比如跳转到错误页(活动太火爆,稍后重试等)