特性

启动时检查

1、特性说明

(1)Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"

(2)可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动

(3)另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false",总是会返回引用,当服务恢复时,能自动连上

2、使用场景

(1)单向依赖:有依赖关系(建议默认设置)和无依赖关系(可以设置 check=false)

(2)相互依赖:即循环依赖(不建议设置 check=false)

(3)延迟加载处理

(4)check 只用来启动时检查,运行时没有相应的依赖仍然会报错

3、使用方式

(1)通过 Spring 配置文件

<!-- 关闭某个服务的启动时检查(没有提供者时报错) -->
<dubbo:reference interface="com.foo.BarService" check="false" />
<!-- 关闭所有服务的启动时检查(没有提供者时报错) -->
<dubbo:consumer check="false" />
<!-- 关闭注册中心启动时检查(注册订阅失败时报错) -->
<dubbo:registry check="false" />

(2)dubbo.properties

dubbo.reference.com.foo.BarService.check=false
dubbo.consumer.check=false
dubbo.registry.check=false

(3)-D 参数

java -Ddubbo.reference.com.foo.BarService.check=false
java -Ddubbo.consumer.check=false 
java -Ddubbo.registry.check=false

4、含义

(1)dubbo.reference.com.foo.BarService.check,覆盖 com.foo.BarService的 reference 的 check 值,就算配置中有声明,也会被覆盖

(2)dubbo.consumer.check=false,是设置 reference 的 check 的默认值,如果配置中有显式的声明,如:<dubbo:reference check="true"/>,不会受影响

(3)dubbo.registry.check=false,前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试

 

超时

  属性 对应 URL 参数 类型 是否必填 默认值 作用 描述 兼容性
service timeout timeout int 可选 1000 性能调优 远程服务调用超时时间(毫秒) 2.0.0 以上版本
reference timeout timeout long 可选 缺省使用 <dubbo:consumer> 的 timeout 性能调优 服务方法调用超时时间(毫秒) 1.0.5 以上版本
registry timeout registry.timeout int 可选 5000 性能调优 注册中心请求超时时间(毫秒) 2.0.0 以上版本
config-center timeout timeout int 可选 3000ms   获取配置的超时时间 2.7.0 以上版本
metadata-report-config timeout timeout int 可选     获取元数据超时时间(ms) 2.7.0 以上版本
provider timeout default.timeout int 可选 1000 性能调优 远程服务调用超时时间(毫秒) 2.0.5 以上版本
consumer timeout default.timeout int 可选 1000 性能调优 远程服务调用超时时间(毫秒) 1.0.16 以上版本
method timeout <methodName>.timeout int 可选 缺省为的 timeout 性能调优 方法调用超时时间(毫秒) 1.0.8 以上版本

 

重试次数

  属性 对应 URL 参数 类型 是否必填 默认值 作用 描述 兼容性
service retries retries int 可选 2 性能调优 远程服务调用重试次数,不包括第一次调用,不需要重试请设为 0 2.0.0 以上版本
reference retries retries int 可选 缺省使用 <dubbo:consumer> 的 retries 性能调优 远程服务调用重试次数,不包括第一次调用,不需要重试请设为 0 2.0.0 以上版本
provider retries default.retries int 可选 2 性能调优 远程服务调用重试次数,不包括第一次调用,不需要重试请设为 0 2.0.5 以上版本
consumer retries default.retries int 可选 2 性能调优 远程服务调用重试次数,不包括第一次调用,不需要重试请设为 0,仅在 cluster 为 failback / failover 时有效 1.0.16 以上版本
method retries <methodName>.retries int 可选 缺省为<dubbo:reference>的retries 性能调优 远程服务调用重试次数,不包括第一次调用,不需要重试请设为 0 2.0.0 以上版本

 

服务分版本

1、在 Dubbo 中为同一个服务配置多个版本

2、按照以下的步骤进行版本迁移

(1)在低压力时间段,先升级一半提供者为新版本

(2)再将所有消费者升级为新版本

(3)然后将剩下的一半提供者升级为新版本

3、使用场景:当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用

4、使用方式

(1)服务提供者

<!-- 老版本服务提供者配置 -->
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
<!-- 新版本服务提供者配置 -->
<dubbo:service interface="com.foo.BarService" version="2.0.0" />

(2)服务消费者

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

(3)不区分版本

<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

 

本地存根

1、特性说明

(1)远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑

2、使用场景

(1)做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等

(2)此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub(Stub 必须有可传入 Proxy 的构造函数),然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy

3、使用方式

(1)Spring 配置文件配置

<!-- 可以配置在消费者端 -->
<dubbo:consumer interface="com.foo.BarService" stub="true" />
<!-- 或 -->
<dubbo:consumer interface="com.foo.BarService" stub="com.foo.BarServiceStub" />
<!-- 可以配置在服务者端 -->
<dubbo:service interface="com.foo.BarService" stub="true" />
<!-- 或 -->
<dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" />

(2)提供 Stub 的实现:在 interface 旁边放一个 Stub 实现,它实现 BarService 接口,并有一个传入远程 BarService 实例的构造函数

package com.foo;
public class BarServiceStub implements BarService {
    private final BarService barService;
    
    // 构造函数传入真正的远程代理对象
    public BarServiceStub(BarService barService){
        this.barService = barService;
    }
 
    public String sayHello(String name) {
        //before:此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
        try {
            //此处 Proxy 发起调用
            String name = barService.sayHello(name)
            //after-returning:在返回过程之前执行自己的逻辑
            return name;
        } catch (Exception e) {
            //after-throwing:可以容错,可以做任何AOP拦截事项
            return "容错数据";
        }
    }
}

(3)在实际开发中,本地存根一般放在接口所在位置,服务端的接口实现在另一工程

4、本地存根执行顺序

(1)服务消费者发起调用

(2)如果服务消费者端存在本地存根 Stub,会先执行本地存根

(3)本地存根 Stub 持有远程服务的 Proxy 对象,Stub 在执行时,会先执行自己的逻辑(before),然后通过 Proxy 发起远程调用,最后在返回过程之前,也会执行自己的逻辑(after-returning)

(4)如果远程服务的 Proxy 对象在执行过程中抛出 Exception,会执行服务消费端的本地伪装 Mock 的逻辑(after-throwing),返回容错数据,从而达到服务降级的目的

 

地址缓存

1、dubbo 服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心

2、当服务提供者地址发生变化时,注册中心会通知服务消费者

3、健壮性

(1)监控中心宕掉不影响使用,只是丢失部分采样数据

(2)数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务

(3)注册中心对等集群,任意一台宕掉后,将自动切换到另一台

(4)注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯

(5)服务提供者无状态,任意一台宕掉后,不影响使用

(6)服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

4、dubbo 直连

(1)reference:服务消费者引用服务配置

属性 对应 URL 参数 类型 是否必填 缺省值 作用 描述
url url string 可选   服务治理 点对点直连服务提供者地址,将绕过注册中心

 

序列化

1、dubbo 内部已经封装序列化、反序列化的过程

(1)参数及返回值需实现 Serializable 接口

(2)只需要在定义 POJO 类时,实现 Serializable 接口即可

(3)一般会定义一个公共 POJO 模块,让生产者和消费者都依赖该模块

2、在 dubbo RPC 中,同时支持多种序列化方式

(1)dubbo 序列化:阿里尚未开发成熟的高效 java 序列化实现,阿里不建议在生产环境使用它

(2)hessian2 序列化:hessian 是一种跨语言的高效二进制序列化方式,但这里实际不是原生的 hessian2 序列化,而是阿里修改过的 hessian lite,它是 dubbo RPC 默认启用的序列化方式

(3)json 序列化:目前有两种实现,一种是采用的阿里的 fastjson 库,另一种是采用 dubbo 中自己实现的简单 json 库,但其实现都不是特别成熟,而且 json 这种文本序列化性能一般不如上面两种二进制序列化

(4)java 序列化:主要是采用 JDK 自带的 Java 序列化实现,性能很不理想

(5)在通常情况下,这四种主要序列化方式的性能从上到下依次递减

(6)对于dubbo RPC这种追求高性能的远程调用方式来说,实际上只有 1、2 两种高效序列化方式比较般配,而第 1 个 dubbo 序列化由于还不成熟,所以实际只剩下 2 可用,所以 dubbo RPC 默认采用 hessian2 序列化

(7)但 hessian 是一个比较老的序列化实现,而且它是跨语言的,所以不是单独针对 java 进行优化的。而 dubbo RPC 实际上完全是一种 Java to Java 的远程调用,其实没有必要采用跨语言的序列化方式(当然肯定也不排斥跨语言的序列化)

3、最近几年,各种新的高效序列化方式层出不穷,不断刷新序列化性能的上限,最典型的包括

(1)专门针对 Java 语言的:Kryo,FST 等等

(2)跨语言的:Protostuff,ProtoBuf,Thrift,Avro,MsgPack 等等

(3)这些序列化方式的性能多数都显著优于 hessian2(甚至包括尚未成熟的 dubbo 序列化)

(4)有鉴于此,为 dubbo 引入 Kryo 和 FST 这两种高效 Java 序列化实现,来逐步取代 hessian2

(5)其中,Kryo 是一种非常成熟的序列化实现,已经在 Twitter、Groupon、Yahoo 以及多个著名开源项目(如:Hive、Storm)中广泛的使用。而 FST 是一种较新的序列化实现,目前还缺乏足够多的成熟使用案例

(6)在面向生产环境的应用中,建议目前更优先选择 Kryo

 

负载均衡

1、在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用

2、具体实现上,Dubbo 提供的是客户端负载均衡,即由 Consumer 通过负载均衡算法得出需要将请求提交到哪个 Provider 实例

3、目前 Dubbo 内置了如下负载均衡算法,用户可直接配置使用

算法 特性 备注
RandomLoadBalance 加权随机 默认算法,默认权重相同
RoundRobinLoadBalance 加权轮询 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同,
LeastActiveLoadBalance 最少活跃优先 + 加权随机 背后是能者多劳的思想
ShortestResponseLoadBalance 最短响应优先 + 加权随机 更加关注响应速度
ConsistentHashLoadBalance 一致性 Hash 确定的入参,确定的提供者,适用于有状态请求

4、Random

(1)加权随机,按权重设置随机概率

(2)在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重

(3)缺点:存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上

5、RoundRobin

(1)加权轮询,按公约后的权重设置轮询比率,循环调用节点

(2)缺点:同样存在慢的提供者累积请求的问题

(3)加权轮询过程过程中,如果某节点权重过大,会存在某段时间内调用过于集中的问题

(4)例如 ABC 三节点有如下权重:{A: 3, B: 2, C: 1}

(5)那么按照最原始的轮询算法,调用过程将变成:A A A B B C

(6)对此,Dubbo 借鉴 Nginx 的平滑加权轮询算法,对此做了优化,调用过程可抽象成下表

轮前加和权重(上轮权重 + 初始配置权重) 本轮胜者 合计权重 轮后权重(胜者减去合计权重)
起始轮:currentWeight 全为 0 \ \ A(0), B(0), C(0)
A(3), B(2), C(1) A 6 A(-3), B(2), C(1)
A(0), B(4), C(2) B 6 A(0), B(-2), C(2)
A(3), B(0), C(3) A 6 A(-3), B(0), C(3)
A(0), B(2), C(4) C 6 A(0), B(2), C(-2)
A(3), B(4), C(-1) B 6 A(3), B(-2), C(-1)
A(6), B(0), C(0) A 6 A(0), B(0), C(0)

(7)经过合计权重(3+2+1)轮次后,循环又回到了起点,整个过程中节点流量是平滑的,且哪怕在很短的时间周期内,概率都是按期望分布的

(8)如果用户有加权轮询的需求,可放心使用该算法

6、LeastActive

(1)加权最少活跃调用优先,活跃数越低,越优先调用,相同活跃数的进行加权随机

(2)活跃数指调用前后计数差(针对特定提供者:请求发送数 - 响应返回数),表示特定提供者的任务堆积量,活跃数越低,代表该提供者处理能力越强

(3)使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大;相对的,处理能力越强的节点,处理更多的请求

7、ShortestResponse

(1)加权最短响应优先,在最近一个滑动窗口中,响应时间越短,越优先调用。相同响应时间的进行加权随机

(2)使得响应时间越快的提供者,处理更多的请求

(3)缺点:可能会造成流量过于集中于高性能节点的问题

(4)此处响应时间 = 某个提供者在窗口时间内的平均响应时间,窗口时间默认是 30s

8、ConsistentHash

(1)一致性 Hash,相同参数的请求总是发到同一提供者

(2)当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动

(3)缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />

(4)缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" />

9、配置

(1)服务端服务级别

<dubbo:service interface="..." loadbalance="roundrobin" />

(2)客户端服务级别

<dubbo:reference interface="..." loadbalance="roundrobin" />

(3)服务端方法级别

<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>

(4)客户端方法级别

<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

10、负载均衡扩展

(1)扩展接口:org.apache.dubbo.rpc.cluster.LoadBalance

(2)扩展配置

<dubbo:protocol loadbalance="xxx" />
<!-- 缺省值设置,当<dubbo:protocol>没有配置loadbalance时,使用此配置 -->
<dubbo:provider loadbalance="xxx" />

 

服务降级

1、特性说明

(1)推荐使用相关限流降级组件(如 Sentinel)以达到最佳体验

(2)服务降级是指服务在非正常情况下进行降级应急处理

2、使用场景

(1)某服务或接口负荷超出最大承载能力范围,需要进行降级应急处理,避免系统崩溃

(2)调用的某非关键服务或接口暂时不可用时,返回模拟数据或空,业务还能继续可用

(3)降级非核心业务的服务或接口,腾出系统资源,尽量保证核心业务的正常运行

(4)某上游基础服务超时或不可用时,执行能快速响应的降级预案,避免服务整体雪崩

3、使用方式

(1)以下将 xml 配置为例:(通过注解方式配置类似)

(2)配置 mock="true"

<!-- 这种方式需要在相同包下有类名 + Mock后缀的实现类,即com.xxx.service包下有DemoServiceMock类 -->
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="true" />

(3)配置 mock="com.xxx.service.DemoServiceMock"

<!-- 这种方式指定 Mock 类的全路径 -->
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="com.xxx.service.DemoServiceMock" />

(4)配置 mock="[fail|force]return|throw xxx"

fail 或 force 关键字可选,表示调用失败或不调用强制执行 mock 方法,如果不指定关键字默认为 fail
return 表示指定返回结果
throw 表示抛出指定异常
xxx 根据接口的返回类型解析,可以指定返回值或抛出自定义的异常
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="return" />
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="return null" />
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="fail:return aaa" />
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="force:return true" />
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="fail:throw" />
<dubbo:reference id="demoService" interface="com.xxx.service.DemoService" mock="force:throw java.lang.NullPointException" />

4、配合 dubbo-admin 使用

(1)应用消费端引入 dubbo-mock-admin 依赖

(2)应用消费端启动时设置 JVM 参数,-Denable.dubbo.admin.mock=true

(3)启动 dubbo-admin,在服务 Mock -> 规则配置菜单下设置 Mock 规则

(4)以服务方法的维度设置规则,设置返回模拟数据,动态启用 / 禁用规则

5、注意事项

(1)Dubbo 启动时会检查配置,当 mock 属性值配置有误时会启动失败,可根据错误提示信息进行排查

(2)配置格式错误,如:return+null 会报错,被当做 mock 类型处理,return 后面可省略不写或者跟空格后再跟返回值

(3)类型找不到错误,如:自定义 mock 类、throw 自定义异常,请检查类型是否存在或是否有拼写错误

 

集群容错

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

2、各节点关系

(1)此处 Invoker 是 Provider 的一个可调用 Service 的抽象,Invoker 封装 Provider 地址及 Service 接口信息

(2)Directory 代表多个 Invoker,可以把它看成 List<Invoker> ,但与 List 不同的是,它的值可能是动态变化的,比如注册中心推送变更

(3)Cluster 将 Directory 中的多个 Invoker 伪装成一个 Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个

(4)Router 负责从多个 Invoker 中按路由规则选出子集,比如读写分离,应用隔离等

(5)LoadBalance 负责从多个 Invoker 中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选

3、Failover Cluster

(1)该配置为缺省配置

(2)失败自动切换,当出现失败,重试其它服务器

(3)通常用于读操作,但重试会带来更长延迟

(4)可通过 retries="2" 来设置重试次数(不含第一次)

(5)重试次数配置如下

<dubbo:service retries="2" />
<dubbo:reference retries="2" />
<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>

4、Failfast Cluster

(1)快速失败,只发起一次调用,失败立即报错

(2)通常用于非幂等性的写操作,比如新增记录

5、Failsafe Cluster

(1)失败安全,出现异常时,直接忽略

(2)通常用于写入审计日志等操作

6、Failback Cluster

(1)失败自动恢复,后台记录失败请求,定时重发

(2)通常用于消息通知操作

7、Forking Cluster

(1)并行调用多个服务器,只要一个成功即返回

(2)通常用于实时性要求较高的读操作,但需要浪费更多服务资源

(3)可通过 forks="2" 来设置最大并行数

8、Broadcast Cluster

(1)2.1.0 开始支持

(2)广播调用所有提供者,逐个调用,任意一台报错则报错

(3)通常用于通知所有提供者更新缓存或日志等本地资源信息

(4)现在广播调用中,可以通过 broadcast.fail.percent 配置节点调用失败的比例,当达到这个比例后,BroadcastClusterInvoker 将不再调用其他节点,直接抛出异常

(5)broadcast.fail.percent 取值在 0~100 范围内,默认情况下当全部调用失败后,才会抛出异常

(6)broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点,并不改变结果(任意一台报错则报错)

(7)broadcast.fail.percent 参数在 dubbo 2.7.10 及以上版本生效

(8)Broadcast Cluster 配置 broadcast.fail.percent

(9)broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点

@reference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"})

9、Available Cluster

(1)调用目前可用的实例(只调用一个),如果当前没有可用的实例,则抛出异常

(2)通常用于不需要负载均衡的场景

10、Mergeable Cluster

(1)将集群中的调用结果聚合起来返回结果,通常和 group 一起配合使用

(2)通过分组对结果进行聚合并返回聚合后的结果,比如菜单服务,用 group 区分同一接口的多种实现,现在消费方需从每种 group 中调用一次并返回结果,对结果进行合并之后返回,这样就可以实现聚合菜单项

11、ZoneAware Cluster

(1)多注册中心订阅的场景,注册中心集群间的负载均衡

(2)对于多注册中心间的选址策略有如下四种

(3)指定优先级:preferred="true" 注册中心的地址将被优先选择

<dubbo:registry address="zookeeper://127.0.0.1:2181" preferred="true" />

(4)同中心优先:检查当前请求所属的区域,优先选择具有相同区域的注册中心

<dubbo:registry address="zookeeper://127.0.0.1:2181" zone="beijing" />

(5)权重轮询:根据每个注册中心的权重分配流量

<dubbo:registry id="beijing" address="zookeeper://127.0.0.1:2181" weight="100" />
<dubbo:registry id="shanghai" address="zookeeper://127.0.0.1:2182" weight="10" />

(6)缺省值:选择一个可用的注册中心

12、集群模式配置

(1)服务提供方配置集群模式

<dubbo:service cluster="failsafe" />

(2)服务消费方配置集群模式

<dubbo:reference cluster="failsafe" />

13、集群扩展

(1)扩展接口:org.apache.dubbo.rpc.cluster.Cluster

(2)扩展配置 

<dubbo:protocol cluster="xxx" />
<!-- 缺省值配置,如果<dubbo:protocol>没有配置cluster时,使用此配置 -->
<dubbo:provider cluster="xxx" />
posted @   半条咸鱼  阅读(111)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示