Dubbo
2023-12-27 15:04:58 20 举报
AI智能生成
Dubbo
作者其他创作
大纲/内容
RPC
优点<br>
简单、直接、开发方便。<br>
<b><font color="#9c27b0">长链接</font></b>,不必每次通信都要像http一样去3次握手什么的,减少了网络开销
RPC框架一般都有注册中心,有丰富的监控管理
发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作
RPC一般配合netty框架、spring自定义注解来编写轻量级框架,<br>较新的jdk的IO一般是NIO,即非阻塞IO,在高并发网站中,RPC的优势会很明显<br>
组件<br>
客户端(Client)<br>
客户端存根(Client Stub)
存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端
服务端存根(Server Stub)
接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理
服务端(Server)<br>
具体调用过程
<ol><li>服务消费者(client客户端)通过调用本地服务的方式调用需要消费的服务;</li><li>客户端存根(client stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体;</li><li>客户端存根(client stub)找到远程的服务地址,并且将消息通过网络发送给服务端;、</li><li>服务端存根(server stub)收到消息后进行解码(反序列化操作);</li><li>服务端存根(server stub)根据解码结果调用本地的服务进行相关处理;</li><li>本地服务执行具体业务逻辑并将处理结果返回给服务端存根(server stub);</li><li>服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方;</li><li>客户端存根(client stub)接收到消息,并进行解码(反序列化);</li><li>服务消费方得到最终结果;</li></ol>
目标
RPC框架的实现目标则是将上面的第2-10步完好地封装起来,<br>也就是<b><u>把调用、编码/解码的过程给封装起来</u></b>,让用户感觉上像调用本地服务一样的调用远程服务<br>
其他相关概念
REST
SOAP
SOA
需要解决的问题
1、如何确定客户端和服务端之间的通信协议?<br>2、如何更高效地进行网络通信?<br>3、服务端提供的服务如何暴露给客户端?<br>4、客户端如何发现这些暴露的服务?<br>5、如何更高效地对请求对象和响应结果进行序列化和反序列化操作?
1、需要有非常高效的网络通信,比如一般选择Netty作为网络通信框架;<br>2、需要有比较高效的序列化框架,比如谷歌的Protobuf序列化框架;<br>3、可靠的寻址方式(主要是提供服务的发现),比如可以使用Zookeeper来注册服务等等;<br>4、如果是带会话(状态)的RPC调用,还需要有会话和状态保持的功能;
关键技术<br>
动态代理
序列化与反序列化
NIO通信<br>
注册中心<br>
其他主流RPC框架<br>
RMI<br>
Hessian<br>
potobuf-rpc-pro
Thrift<br>
<span style="color: rgb(62, 62, 62); font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; font-size: 15px; letter-spacing: 0.544px; text-align: justify;">Finagle </span>
Avro<br>
Dubbo<br>
实现<br>
建立通信<br>
是通过在客户端和服务器之间建立TCP连接
连接分类<br>
按需连接
需要的时候建立连接,用后关闭<br>
长连接<br>
客户端和服务器建立起连接之后保持长期持有,<br>不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效;<br><b><font color="#ba68c8">多个远程过程调用共享同一个连接</font></b>。<br>
服务寻址
采用Redis或者Zookeeper来注册服务
服务提供者角度<br>
将自己提供的服务注册到指定的注册中心<br>
各种原因致使提供的服务停止时,需要向注册中心注销停止的服务;
服务的提供者需要定期向服务注册中心发送心跳检测,<br>服务注册中心如果一段时间未收到来自服务提供者的心跳后,认为该服务提供者已经停止服务,则将该服务从注册中心上去掉<br>
调用者角度<br>
消费的服务上线或者下线的时候,注册中心会告知该服务的调用者
服务调用者下线的时候,则取消订阅
网络传输<br>
序列化
传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输
反序列化<br>
将二进制信息恢复为内存中的表达方式,<br>然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理Proxy去调用,通常会有JDK动态代理、CGLIB动态代理、Javassist生成字节码技术等),之后得到调用的返回值。<br>
服务调用<br>
SPI
Dubbo SPI
<ol><li>对 Dubbo 进行扩展,不需要改动 Dubbo 的源码</li><li><font color="#b71c1c">按需加载</font>:延迟加载,可以一次只加载自己想要加载的扩展实现。</li><li><font color="#b71c1c">增加了对扩展点 IOC 和 AOP 的支持</font>,一个扩展点可以直接 setter 注入其它扩展点。</li><li>Dubbo 的扩展机制能很好的支持第三方 IoC 容器,默认支持 Spring Bean。</li></ol>
依靠SPI机制实现插件化功能
Java SPI
JDK 标准的 SPI 会一次性加载所有的扩展实现,<br>如果有的扩展很耗时,但也没用上,很浪费资源。<br>所以只希望加载某个的实现,就不现实了<br>
实现方法
需要一个目录META/services 在classpath下面
目录下放置配置文件
文件名为要扩展的接口全名<br>
文件内容为要实现的接口的实现方法
文件必须为UTF-8编码
使用方法
ServiceLoader<接口> searchServiceLoader = ServiceLoader.load(接口.class);<br> Iterator<Search> iterable = searchServiceLoader.iterator();
解释:<b><u>SPI ,全称为 Service Provider Interface,是一种服务发现机制</u></b>
运维管理<br>
通过接口版本号兼容老接口
可以利用 telnet 命令进行调试、管理。<br><u><b>Dubbo2.0.5 以上版本服务提供端口支持 telnet 命令</b></u><br>
参考资料:<br><font color="#31a8e0">https://www.cnblogs.com/suger43894/p/9372123.html<br>https://www.jianshu.com/p/bbb1c92cb113</font><br>
服务降级
1.在监控管理界面处理<br>
2.通过代码
mock=force:return+null
不发起远程调用看,直接放回null。用来屏蔽不重要服务不可用时对调用方的影响
mock=fail:return+null
在远程调用失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
mock=“return null”
dubbo:reference 中设置 mock=“return null”。<br>mock 的值也可以修改为 true,然后再跟接口同一个路径下实现一个 Mock 类,<br>命名规则是 “<font color="#f44336"><b>接口名称+Mock</b></font>” 后缀。<font color="#f15a23"><b>mock实现需要保证有无参的构造方法</b></font>。<br>然后在 Mock 类里实现自己的降级逻辑<br>
3.集成Hystric
优雅停机<br>
通过 JDK 的 S<font color="#f15a23">hutdownHook 来完成优雅停机</font>的,<br>如果使用kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过<font color="#f15a23"> kill PID</font> 时,才会执行。<br>
通信协议<br>
通信框架
默认netty<br>
支持的协议<br>
Dubbo
<font color="#f68b1f">单一长连接和 NIO 异步通讯</font>,<font color="#f15a23">适合</font><b style=""><font color="#9c27b0">大并发小数据量</font></b><font color="#f15a23">的服务调用</font>,以及消费者远大于提供者。<br>传输协议 TCP,<br>异步 Hessian 序列化。<br>
RMI
JDK 标准的 RMI 协议实现,<br>传输参数和返回参数对象需要实现 Serializable 接口使用 Java 标准序列化机制,<br>使用<font color="#f68b1f">阻塞式短连接</font>,传输数据包大小混合,<br><font color="#f68b1f">消费者和提供者个数差不多,可传文件</font>,<br>传输协议 TCP。 多个短连接 TCP 协议传输,同步传输,适用常规的远程服务调用和 RMI 互操作。<br>在依赖低版本的 Common-Collections 包,<u><font color="#f15a23">Java 序列化存在安全漏洞。</font></u><br>
WebService<br>
集成 CXF 实现,提供和原生 WebService 的互操作。<br><font color="#ff9800">多个短连接</font>,基于 HTTP 传输,同步传输,<br>适用系统集成和跨语言调用。<br>
Http<br>
使用 Spring 的 HttpInvoke 实现。<br><font color="#f68b1f">多个短连接</font>,传输协议 HTTP,传入参数大小混合,<br>提供者个数多于消费者,需要给应用程序和浏览器 JS 调用。<br>
Hessian<br>
集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,<br>Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。<br><font color="#f68b1f">多个短连接,同步 HTTP 传输</font>,<br>Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件。<br>
Memcache<br>
基于 Memcache实现的 RPC 协议。
Redis
基于 Redis 实现的RPC协议。
Thrift
其他<br>
调用失败默认重试两次
不支持事务,需要集成第三方<br>
缓存
为了提高数据访问的速度。Dubbo 提供了<font color="#f15a23"><font color="#c41230">声明式缓存</font>,以减少用户加缓存的工作量<dubbo:reference cache=“true”</font> />
支持的序列化方式<br>
Hessian(默认)<br>
Dubbo序列化
FastJson<br>
Java自带序列化<br>
安全措施<br>
通过 Token 令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。
提供服务黑白名单,来控制服务所允许的调用方。
<font color="#f15a23">Zookeeper 的注册可以添加用户权限认证</font>
是否阻塞调用<br>
<font color="#f15a23"><b>默认是阻塞的,可以<font color="#c41230">异步调用</font></b></font>,没有返回值的可以这么做。<br>Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个 Future 对象。<br>
服务时效踢出原理<br>
基于 <font color="#f15a23">zookeeper 的临时节点</font>原理。
Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。
当<b><u>一个接口有多种实现时,可以用 group 属性来分组</u></b>,服务提供方和消费方都指定同一个 group 即可。
可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。
Dubbo 的设计目的是为了<b style=""><font color="#f57c00">满足高并发</font><font color="#f44336">小数据量</font><font color="#f57c00">的 rpc 调用</font></b>,在<u>大数据量</u>下的性能表现并不好,<u>建议使用 rmi 或 http 协议。</u>
<b>管理控制台</b>主要包含:<b>路由规则</b>,<b>动态配置</b>,<b>服务降级</b>,<b>访问控制</b>,<b>权重调整</b>,<b>负载均衡</b>,等管理功能。
Dubbo <u><b>默认使用 Netty 框架</b></u>,也是推荐的选择,另外内容还集成有<u>Mina</u>、<u>Grizzly</u>。
基础知识
使用场景<br>
透明化的远程调用<br>
像掉本地方法一样调用远程方法
软负载均衡及容错机制<br>
服务自动注册与发现<br>
不需要写死服务提供方地址,而是通过注册中心管理服务提供方<br>
核心功能<br>
Remoting(网络通信框架)<br>
提供对多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。
Cluster(集群框架)<br>
提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
Registred(服务注册中心)<br>
基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
注册中心<br>
Multicast 注册中心
Multicast 注册中心不需要任何中心节点,只要广播地址,就能进行服务注册和发现,基于网络中组播传输实现。
组播受网络结构限制,只适合小规模应用或开发阶段使用
Provider 和 Consumer 和 Registry 不能跨机房(路由)
Zookeeper注册中心<br>
基于分布式协调系统 Zookeeper 实现,采用 Zookeeper 的 watch 机制实现数据变更。
Redis注册中心<br>
基于 Redis 实现,采用 key/map 存储,<br>key 存储服务名和类型,<br>map 中 key 存储服务 url,value 服务过期时间。基于 Redis 的发布/订阅模式通知数据变更。<br>
通过心跳的方式检测脏数据,<u>服务器时间必须相同</u><br><b>脏数据由监控中心删除。</b>(注意:<b>服务器时间必需同步</b>,否则过期检测会不准确)<br>
Simple注册中心<br>
注册中心<b>本身就是</b>一个普通的<b>Dubbo服务</b>,可以减少第三方依赖,使整体通讯方式一致。<br>SimpleRegistryService只是简单实现,<b>不支持集群</b>,可作为自定义注册中心的参考,但不适合直接用于生产环境<br>
参考:<br><font color="#31a8e0">https://zhuanlan.zhihu.com/p/73949200<br>https://www.cnblogs.com/twoheads/p/10119251.html</font><br>
配置
配置说明<br>
服务配置<dubbo:service/>
用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心
引用配置<dubbo:reference/><br>
用于创建一个远程服务代理,一个引用可以指向多个注册中心
协议配置<dubbo:protocol/><br>
用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受
应用配置<dubbo:application/><br>
用于配置当前应用信息,不管该应用是提供者还是消费者
模块配置<dubbo:module/>(可选)<br>
用于配置当前模块信息
注册中心配置<dubbo:registry/><br>
用于配置连接注册中心相关信息
监控中心配置<dubbo:monitor/>(可选)<br>
用于配置连接监控中心相关信息
提供方配置<dubbo:provider/>(可选)
当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值
消费方配置<dubbo:consumer/>(可选)<br>
当 ReferenceConfig 某属性没有配置时,采用此缺省值
方法配置<dubbo:method/>
用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息
参数配置<dubbo:argument/>
用于指定方法参数配置
超时设置方式
服务提供者端设置超时(<font color="#f68b1f"><b>如果消费端配置则以消费端配置为主</b>,</font><u><i>如果消费方超时,服务端线程不会定制,会产生警告</i></u>)
推荐使用<br>
服务消费者端设置超时<br>
不建议使用<br>
分布式框架
类似框架
spring cloud
dubbox
dubbo的扩展,增加了restful调用,增加了开源组件等<br>
与springCloud区别<br>
dubbo
主要关注服务调用,流量分发,流量监控和熔断,服务的方方面面<br>
底层使用Netty这样的NIO框架,是基于TCP传输协议,配合Hession序列化完成RPC调用<br>
springCloud
微服务的方方面面,打造一个生态<br>
基于Http协议Rest远程调用过程的协议;报文更大;占用带宽更多;但更灵活,只通过契约约束,不存在代码依赖<br>
架构设计
核心组件<br>
Provider<br>
Consumer
Registry<br>
Monitor
注册发现流程<br>
1.服务提供者启动时,向注册中心注册自己提供的服务;<br>2.Consumer在启动时,向注册中心获取自己所需的服务;<br>3.注册中心返回提供者注测的消费者所需接口给消费者;<b style=""><font color="#2196f3">如果有变更,基于</font><font color="#ff0000">长连接</font><font color="#2196f3">通知消费者</font></b>;<br>4.消费者从服务提供者地址列表中,基于<font color="#00a650">软负载均衡</font>,先取一个进行调用,如果失败再调用另一台;<br>
服务提供者和消费者在内存中记录调用次数和时间,定时<font color="#f15a23"><u><b>每分钟</b></u></font>发送一次统计数据到监控中心Monitor;<br>
框架设计分层<br>
接口服务层(Service)
开发的业务逻辑层
配置层(Config)
用于扩展实现consumer/provider配置信息,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过Sping解析配置生成配置类
服务代理层(Proxy)
使用动态代理的方式为接口创建代理类,Proxy 层最主要的接口就是 ProxyFactory。其默认的扩展点有:<b>stub</b>、<b>jdk</b>、<b>javassist</b>。jdk 使用反射的方式创建代理类,javassist 通过拼接字符串然后编译的方式创建代理类。<br>对于服务提供者,代理的对象是接口的真实实现。<br>对于服务消费者,代理的对象是远程服务的 invoker 对象。
服务注册层(Registry)
注册层主要负责的就是服务的注册发现。这层的主要接口就是 RegistryFactory,默认的扩展实现有:<br><ul><li><b>zookeeper</b></li><li><b>redis</b></li><li><b>multicast(广播模式)</b></li><li><b>内存</b></li></ul>
集群层(Cluster)
对多提供者调用场景的抽象,是 Dubbo 整个集群容错的抽象层。主要的扩展点有:<br><ul><li><b>容错(Cluster)</b>、</li><li><b>路由(RouterFactory)、</b></li><li><b>负载均衡(LoadBalance)。</b></li></ul>
监控层(Monitor)
RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory,Monitor和MonitorService
远程调用层(Protocol)<br>
在这一层发起服务暴露(protocol.export)和服务引用(protocol.refer)。<br>Dubbo 提供的协议有:<br><ul><li><b>Dubbo (默认);</b></li><li><b>injvm;</b></li><li><b>rmi;</b></li><li><b>http;</b></li><li><b>hessian;</b></li><li><b>thrift。</b></li></ul>
信息交换层(Exchange)
封装 Request/Response 对象。
网络传输层(Transport)
数据传输就是在传输层发生的,所以这层包含 <b>Transport(传输)</b>、<b>Dispatcher(分派)</b>、<b>Codec2(编解码)</b>、<b>ThreadPool(线程池)</b>,这几个接口。<br>数据传输发生在传输层,所以传输层一定需要具备数据传输的能力,也就是 Transport 和 Codec2,其中 Transport 就是 Netty 等网络传输的接口,编解码不必说了,传输肯定需要;<br>除了传输能力,数据接收之后的处理,Dispatcher 和 ThreadPool,也就是分派任务和任务提交给线程池处理,也是必不可少的。<br>
数据序列化层(Serialize)
序列化的作用是把对象转化为二进制流,然后在网络中传输。Dubbo 提供的序列化方式有:<br><b>Hessian2(默认);<br>Fastjson;<br>fst;<br>Java;<br>Kayo;<br>protobuff。</b>
Monitor实现原理<br>
Consumer 端在发起调用之前会先走<b> filter 链</b>;<br>provider 端在接收到请求时也是先走<b> filter 链</b>,<br>然后才进行真正的业务逻辑处理。默认情况下,在 consumer 和provider 的 filter 链中都会有 Monitorfilter。<br>
流程<br>
1、MonitorFilter 向 DubboMonitor 发送数据
2、DubboMonitor 将数据进行聚合后(默认聚合 <b><font color="#ff0000">1min</font> </b>中的统计数据)暂存到<b>ConcurrentMap<Statistics, AtomicReference> statisticsMap</b>,然后使用一个含有 <b>3 个线程</b>(线程名字:DubboMonitorSendTimer)<b>的线程池</b>每隔 <b>1min</b> 钟,调用 SimpleMonitorService 遍历发送 statisticsMap 中的统计数据,每发送完毕一个,就重置当前的 Statistics 的 AtomicReference
3、SimpleMonitorService 将这些聚合数据塞入 BlockingQueue queue 中(队列大写为 100000)
4、SimpleMonitorService 使用一个后台线程(线程名为:DubboMonitorAsyncWriteLogThread)将 queue 中的数据写入文件(该线程以死循环的形式来写)
5、SimpleMonitorService 还会使用一个含有 1 个线程(线程名字:DubboMonitorTimer)的线程池每隔<font color="#ff0000"> <b>5min</b></font> 钟,将文件中的统计数据画成图表
集群
负载均衡策略
<b>随机</b>选取提供策略(Random loadBalance)<b><font color="#c41230">(默认)</font></b>
有利于动态调整提供者权重。截面碰撞率高,调用次数越多,分布越均匀。
<b>循环选取</b>提供策略(RoundRobin loadBalance)<br>
平均分布,但是存在请求累积的问题。
<b>量少活跃</b>调用策略(LeastActive loadBalance)<br>
解决慢提供者接收更少的请求。
<b>一致性哈希策</b>略(Constant loadBalance)<br>
使相同参数请求总是发到同一提供者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提<br>供者的剧烈变动。
容错策略<br>(消费者,cluster属性设置)<br>
失败切换(Failover)<br>
当出现失败,重试其它服务器。<b>通常用于读操作</b>,但重试会带来更长延迟。
快速失败(FailFaster)
只发起一次调用,失败立即报错。通常用于<b>非幂等性的写操作</b>,比如新增记录。
失败安全(FailSafe)
出现异常时,<b>直接忽略</b>。通常用于写入审计日志等操作。
失败自动恢复(FailBack)<br>
后台记录失败请求,<b>定时重发</b>。通常用于消息通知操作。
并行调用多个服务器(Forking)<br>
<b>只要一个成功即返回</b>。通常用于<b>实时性要求较高的读操作</b>,但需要浪费更多服务资源。<br>可通过 forks=”2″ 来设置最大并行数。<br>
广播调用所有提供者(Broadcast)<br>
<b>逐个调用,任意一台报错则报错 </b>。通常用于<u>通知所有提供者更新缓存或日志等本地资源信息</u>。
路由
条件路由
文件路由
脚本路由
0 条评论
下一页