目录
一. dubbo 概述
- 一款高性能透明化的rpc远程服务调用框架,提供了SOA服务治理,默认采用dubbo协议的,单一长连接,NIO异步通信,基于hessian作为序列化协议
- 默认采用javassist动态字节码生成,创建代理类
- 为什么使用dubbo: 项目结构,代码复用,提供负载,容错,链路监控功能
dubbo中的角色分析:
- provider 生产者服务注册方,提供服务
- consumer 消费者服务注册方,调用生产者服务进行消费
- registry 服务注册与发现的注册中心(通常使用Zookeeper)
- Monitor 监控中心,监控服务调用,统计服务调用时间,调用次数(负载就是通过获取此处的统计数据进行处理的)
dubbo 以 Zookeeper作为注册中心时的执行流程
- 执行流程
- 服务生产者启动时,会以当前服务中提供生产的类的全类名作为持久节点,当前服务器的ip做为临时节点注册到Zookeeper上
- 利用Zookeeper监听数据修改,事件通知机制,临时节点断开连接节点消失的特性,当生产者发生改变时,ZooKeeper监听回调执行Watcher中的process()方法,基于长链接通知服务消费方
- 服务消费者调用生产者,持有生产者全类名,调用服务生产者时,通过全类名在Zookeeper上获取该服务的调用地址
- 获取到所有地址后进行本地负载
- 更新流程: RegistryDirectory 实现了 NotifyListener,在 ZK 节点变化时能收到通知更新内存缓存,其中 RegistryDirectory#mergeUrl() 方法中会按照优先级合并参数(动态配置在此处生效)
dubbo 负载均衡策略
当一个服务有多个服务提供者时,消费端在进行服务调用时选择服务服务提供者的负载均衡算法,dubbo 支持: 随机负载(random), 轮询负载(roundRoobin), 最少活跃负载(leastActive), 一致性hash(consistentHash)
- ConsistentHashLoadBalance
可以通过< dubbo:service loadbalance=“consistenthash” …/>或< dubbo:provider loadbalance = “consistenthash” …/>
负载均衡算法:一致性Hash算法,在AbstractClusterInvoker中从多个服务提供者中选择一个服务提供者时被调用。- LeastActiveLoadBalance
可以通过< dubbo:service loadbalance=“leastactive” …/>或< dubbo:provider loadbalance = “leastactive” …/>
负载均衡算法:最小活跃调用。- RandomLoadBalance
可以通过< dubbo:service loadbalance=“random” …/>或< dubbo:service loadbalance = “random” …/>
负载均衡算法:随机,如果weight(权重越大,机会越高)- RoundRobinLoadBalance
可以通过< dubbo:service loadbalance=“roundrobin” …/>或< dubbo:provider loadbalance = “roundrobin” …/>
负载均衡算法:加权轮询算法
xml 方式配置负载均衡策略
- 服务提供方注入bean时配置
<dubbo:service interface="..." loadbalance="roundrobin" />
- 服务消费方配置
<dubbo:reference interface="..." loadbalance="roundrobin" />
- 对指定方法进行特殊配置
<dubbo:service interface="...">
<dubbo:method name="hello" loadbalance="roundrobin"/>
</dubbo:service>
SpringBoot yml 文件配置 dubbo 负载配置示例
dubbo:
reference:
loadbalance: roundrobin #轮询
dubbo 容错
dubbo 消费方抛出异常或调用超时,默认重试2次,失败自动切换调用其它服务器,会出现接口幂等问题,在实际开发中,可以查询接口保证幂等的进行重试,修改数据接口直接报错,不进行重试(通常不会使用重试),默认是开启容错的 check=“true”,通过 retries="3"指定重试次数
- 容错模式:
- AvailableClusterInvoker
通过< dubbo:service cluster = “available” …/> 或 < dubbo:reference cluster=“available” …/>
集群策略:总是选择第一个可用的服务提供者。- BroadcastClusterInvoker
通过< dubbo:service cluster = “broadcast” …/> 或 < dubbo:reference cluster=“broadcast” …/>
集群策略:广播模式,向所有服务提供者都发送请求,任何一个调用失败,则认为失败。- FailbackClusterInvoker
通过< dubbo:service cluster = “failback” …/> 或 < dubbo:reference cluster=“failback” …/>
集群策略:服务调用失败后,定时重试,重试次数无线次,重试频率:5s。并不会切换服务提供者。- FailfastClusterInvoker
通过< dubbo:service cluster = “failfast” …/> 或 < dubbo:reference cluster=“failfast” …/>
集群策略:服务调用后,快速失败,直接抛出异常,并不重试,也不受retries参数的制约,适合新增、修改类操作。- FailoverClusterInvoker
通过< dubbo:service cluster = “failover” …/> 或 < dubbo:reference cluster=“failover” …/>
集群策略:服务调用后,如果出现失败,则重试其他服务提供者,默认重试2次,总共执行3次,重试次数由retries配置,dubbo集群默认方式。- FailsafeClusterInvoker
通过< dubbo:service cluster = “failsafe” …/> 或 < dubbo:reference cluster=“failsafe” …/>
集群策略:服务调用后,只打印错误日志,然后直接返回。- ForkingClusterInvoker
通过< dubbo:service cluster = “forking” …/> 或 < dubbo:reference cluster=“forking” …/>
集群策略:并发调用多个服务提供者,取第一个返回的结果。可以通过forks设置并发调用的服务台提供者个数。
xml 方式配置容错重试
- 服务提供方配置容错机制: 配置注入服务提供方"DemoService",通过cluster指定容错策略,通过retries指定重试次数
<dubbo:service interface="org.apache.dubbo.demo.DemoService" check="true" ref="demoService"cluster="failover">
//对指定方法进行特殊配置,该bean中的sayHello()方法重试2次
<dubbo:method name="sayHello" retries="2" />
</dubbo:reference>
- 服务消费方配置容错机制: 配置服务消费方获取调用的服务提供方接口,通过cluster指定重试策略,通过retries指定重试次数
<dubbo:reference id="demoService" interface="org.apache.dubbo.demo.DemoService" check="true" cluster="failover" retries="1"/>
注解方式配置容错重试
在SpringBoot中不使用xm,通常采用注解方式配置,有两种,在服务提供方使用@Service注解注入bean时设置容错,或者在服务消费方通过@Reference获取服务提供方时设置容错
- @Service 服务提供方注入bean时设置,注意该注解时dubbo下的,不是Spring下的
import com.alibaba.dubbo.config.annotation.Service;
import com.server.api.ServerProduckApi;
//version 指定当前服务提供方的版本
//timeout 服务调用超时时间
//retries 重试次数
//cluster 重试策略
//loadbalance 负载均衡策略
@Service(version = "1.0", timeout = 1000, retries = 5, cluster ="failover",loadbalance="leastActive")
public class ServerProduckApiImpl implements ServerProduckApi {
@Override
public String getVal(){
System.out.println("服务生产方执行----->");
return "我是服务生产数据";
}
}
- @Reference 服务消费方获取调用服务提供方的bean时设置容错
@Controller
public class TestController {
//设置调用的服务提供方serviceApi,该bean中的所有方法的容错
@Reference(interfaceClass = ServerProduckApi .class, retries =5, timeout = 5000,cluster = "failover", loadbalance="leastActive")
private TestServiceApi serviceApi;
//设置调用的服务提供方所有方法使用的容错,并且通过parameters属性对该bean下的指定方法进行特殊处理
//"getVal.retries", "2":
// 该bean下的getVal()方法指定容错重试2次
//"getVal.timeout", "2000":
// 该bean下的getVal()方法超时时间为2000毫秒
//"getVal.cluster", "Failback":
// 该bean下的getVal()方法使用 failback 容错策略,失败自动恢复,后台记录失败请求,定时重发
//"addDiscuss.cluster", "failfast":
// 该bean下的addDiscuss()方法使用failfast容错策略,快速失败,只发起一次调用,失败立即报错
@Reference(interfaceClass = ServerProduckApi .class, retries =5, timeout = 5000, parameters = {
"getVal.retries", "2", "getVal.timeout", "2000","getVal.cluster", "failback",
"addDiscuss.cluster", "failfast"})
private ServerProduckApi serverProduckApi;
public void test(){
//调用服务提供方
String s = serverProduckApi.getVal();
}
}
dubbo 超时与降级
- 服务提供方,在配置注入要调用的服务接口时,通过timeout属性指定调用的超时时间,通过mock指定调用服务接口超时后的处理
<dubbo:service interface="com.xx.service.HelloService" ref="helloServiceImpl" timeout="200" />
<bean id="helloServiceImpl" class="com.xx.service.HelloServiceImpl" />
- 在接口的同一路径下创建一个与指定接口类名相同,并增加后缀为Mock的类,实现该接口,重写接口中的方法,当调用服务的接口超时没有返回响应时,会自动执行该Mock类中对于的接口
- 服务消费方,通过timeout属性指定调用该类中接口的超时时间,通过mock属性设置当指定时间内调用服务接口没有相应,如果 mock值为"return null" 返回默认数据,如果mock值为true
<dubbo:reference id="consumerService" interface="com.xx.service.ConsumerService" timeout="10000" check="false" mock="return null"/>
dubbo 心跳检测
- dubbo 提供心跳机制 检测provider与consumer之间的connection连接是否正常,如果连接断了,需要作出相应的处理。
provider:dubbo的心跳默认是在heartbeat(默认是60s)内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,provider会关闭channel。
consumer:dubbo的心跳默认是在60s内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,consumer会进行重连。
- 服务提供方设置心跳检测时间
<dubbo:service ...>
<dubbo:parameter key="heartbeat" value="3000"/>
</dubbo:service>
- 服务消费方设置心跳检测时间
<dubbo:reference ...>
<dubbo:parameter key="heartbeat" value="3000"/>
</dubbo:reference>
二. dubbo 其它常见问题
dubbo 通信相关问题
- dubbo 使用的通信协议与序列化协议: 默认采用dubbo协议,单一长连接,NIO异步通信,基于hessian作为序列化协议,实际基于不同的通信协议,支持hessian、java二进制序列化、json、SOAP文本序列化多种序列化协议。
- 还支持的通信协议:
- rmi 协议 基于java二进制序列化,多个短连接,适合消费者和提供者数量差不多,适用于文件的传输,一般较少用
- hessian协议: 基于hessian序列化协议,多个短连接,适用于提供者数量比消费者数量还多,适用于文件的传输,一般较少用
- http协议: 基于 json 序列化
- webservice: 基于SOAP文本序列化
dubbo的spi
- 什么是 spi : 假设有个接口,对应该接口有3个实现类,在系统运行的时候对这个接口到底选择哪个实现类呢?这就需要spi了,需要根据指定的配置或者是默认的配置,去找到对应的实现类加载进来,然后用这个实现类的实例对象。