Dubbo
1、基础知识
1)发展演变:单一应用架构——>垂直应用架构——>分布式架构(RPC远程过程调用)——>流动计算架构(基于访问压力实时管理集群容量,提高集群利用率)
2)RPC基本原理
-
网络通信 IO socket BIO、NIO、AIO
-
序列化协议:http json xml hession2 protobuf thrift
-
客户端构建消息体:classname methodName params types
-
服务端通过反射执行
-
客户端动态代理
3)RPC的两个核心模块:
-
网络通信
-
序列化
4)常见RPC框架:
-
dubbo、gRPC、Thrift、HSF(High Speed Service Framework)、SpringCloud
5)Dubbo:高性能、轻量级的开源JavaRPC框架,提供了三大核心能力:
-
面向接口的远程调用
-
智能容错和负载均衡
-
服务自动注册和发现
2、环境搭建
(1)官方推荐Zookeeper作为注册中心
(2)dubbo-admin监控平台、监控中心:dubbo-monitor-simple
(3)测试程序
1)准备工作
-
引入dubbo2.6版本
-
引入zookeeper依赖(dubbo2.6及以后版本使用curator,之前使用zkClient)
2)将服务提供者注册到注册中心
<dubbo:application name="user-service"/> // 指定当前服务名称
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>//指定注册中心方式及位置
<dubbo:protocol name="dubbo" port=""/>//指定通信规则
<dubbo:service interface="" ref=""/>//指定暴露的服务
<dubbo:monitor protocol="registry"/> // 配置监控中心,且是自动发现模式
3)将服务消费者注册到注册中心
<dubbo:reference interface="" id=""/> //声明需要调用远程服务的接口,生成远程服务代理
<dubbo:monitor protocol="registry"/> // 配置监控中心,且是自动发现模式
(4)springboot整合dubbo
1)引入依赖,添加配置
2)服务提供者的接口上添加@Service(dubbo包)便可暴露服务
3)服务提供者主启动类添加@EnableDubbo注解,开启dubbo功能
4)服务消费者中通过@Reference注解表明消费服务引用远程调用
(5)Dubbo_dubbo.properties&属性加载顺序
1)覆盖策略:
-
JVM启动 -D参数优先;XML次之;dubbo.properties
2)启动时检查,默认消费者服务启动时会检查服务提供者是否启动,未启动消费者会报错。可设置为不检查
<dubbo:reference interface="" id="" check="false"/> //声明需要调用远程服务的接口,生成远程服务代理
或
<dubbo:consumer check="false"/> //配置消费者统一规则,所有服务都不检查
<dubbo:registry check="false"/> // 关闭注册中心启动时检查
3)超时配置:默认是1000毫秒,超时报错
<dubbo:reference interface="" id="" check="false" timeout="3000"/> //声明需要调用远程服务的接口,生成远程服务代理
-
以timeout为例,配置信息优先级为:精确优先、消费者优先
-
方法级优先,接口级次之,全局配置再次之
-
如果级别一样,则消费方优先,提供方次之
4)重试次数配置(不包括第一次),如果是多个服务,还会尝试调用其他服务
<dubbo:reference interface="" id="" check="false" timeout="3000" retries="3"/> //声明需要调用远程服务的接口,生成远程服务代理
-
在幂等方法上可以设置重试次数,但是非幂等方法(新增)不能设置重试次数
5)多版本配置(灰度发布)
<dubbo:reference interface="" id="" check="false" timeout="3000" retries="3" version="2.0.0"/> //声明需要调用远程服务的接口,生成远程服务代理
-
version="*"表示随机调用版本
6)配置本地存根(调用前进行校验,满足后在进行调用)
3、高可用---zookeeper宕机与dubbo直连
现象:zookeeper注册中心宕机,还可以消费dubbo暴露的服务。
原因:
监控中心宕机后不影响使用,只是丢失部分采样数据;
数据库宕机后,注册中心仍然能通过缓存提供服务列表查询,但不能注册新服务;
注册中心对等集群,任意一台宕机后,将自动切换到另一台;
注册中心全部宕机后,服务提供者和服务消费者仍然能通过本地缓存通讯;
服务提供者全部宕机后,服务消费者将无法使用,并无限次重连等待服务提供者恢复。
没有注册中心也可以通过dubbo直连的方式进行通讯。
4、高可用---负载均衡机制
Random LoadBalance:基于权重的随机负载均衡机制
RoundRobin LoadBalance:基于权重的轮询
LeastActive LoadBalance:基于最少活跃数(根据前一次调用响应时间最短决定)
ConsistenHash LoadBalance:基于一致性hash
5、高可用---服务降级
两种方式:
(1)mock=force:return+null:消费方对该服务的方法调用都直接返回null,不发起远程调用。可在控制台直接屏蔽。
(2)mock=fail:return+null:消费方对该服务的方法调用失败后再返回null,不抛出异常。可在控制台直接屏蔽。
6、高可用---集群容错
在集群调用失败时,Dubbo提供了很多容错方案,缺省为failover重试。
Failfast:快速失败,通常用于非幂等性的写操作
FailSafe:安全失败,出现异常直接忽略,通常用于写入审计日志。
Failback:失败自动恢复,失败后定时重发
7、RPC原理
一次完整的RPC调用流程(同步调用,异步另说)如下:
-
服务消费方以本地调用方式调用服务
-
client stub(代理)接收到调用后负责将方法、参数等组装成能进行网络传输的消息体
-
client stub找到服务地址,将消息发送到服务端
-
server stub 收到消息后进行解码
-
server stub根据解码结果利用反射调用本地服务
-
本地服务执行并将结果返回给server stub
-
server stub将结果打包成消息并发送至消费方
-
client stub接收到消息并进行解码
-
服务消费方得到最终结果
8、Dubbo原理
(1)框架设计
(2)启动解析、加载配置信息:DubboBeanDefinitionParser:每个标签都有一个对应的Config配置类来进行解析
(3)服务暴露
1)将解析到的信息进行保存
2)监听容器启动完成的事件,回调onApplicationEvent(方法);
3)判断是否要暴露,然后调用export()方法的doExport()方法暴露服务
4)执行doExportUrls()方法暴露URL地址,该方法通过loadregistries(true)方法获取注册中心信息,然后循环protocols执行doExportUrlsFor1Protocol()方法暴露地址和协议
5)doExportUrlsFor1Protocol方法中,通过代理工厂将接口、实现类、Url地址等信息封装成wrapperInvoker,然后调用protocol.export(wrapperInvoker)方法
6)protocol是利用spring的SPI机制获取的,实际实现为DubboProtocol和RegistryProtocol
7)RegistryProtocol#export中先调用 进行本地暴露,本地暴露会调用DubboProtocol#export的openServer(url)方法创建Netty的Exchange服务器监听指定端口
8)通过ConcurrentHashMap<String,set<ProviderInvokerWrapper>> providerInvokers保存服务提供者信息(Url地址和服务执行器)
9)通过ConcurrentHashMap<String,set<ConsumerInvokerWrapper>> consumerInvokers保存服务消费者信息
(4)服务引用
(5)服务调用
3、Dubbo内核SPI机制源码剖析
(1)在META-INF/dubbo/目录下新建配置文件
(2)在配置文件中写入需要加载的类,key-value结构,value为类的全限定名
(3)接口一定要添加@SPI注解
(4)dubbo对jdk的SPI做了扩展,不只是解决了jdk SPI的弊端(将配置文件中的类全部加载),还实现了自己的IOC、AOP功能
1)@Adaptive