Dubbo在众多的微服务框架中脱颖而出,占据RPC服务框架的半壁江山,很是具备普适性,熟练掌握 Dubbo的应用技巧后深入理解其内部实现原理,让你们能更好的掌控工做,助力职场,特别能让你们在面试中脱颖而出。java
那Dubbo内部的设计理念,实现原理是什么呢?面试
本文将结合官方提供的3张图,从以下三个方面介绍其内部的核心实现、以及如何指导实践。算法
Dubbo的服务注册与发现机制以下图所示:
在Dubbo中存在4类角色:编程
具体的交互流程包括以下关键步骤:json
Dubbo官方提供了多种注册中心,接下来将以使用最为广泛的Zookeeper进一步介绍注册中心的原理。服务器
首先咱们来看一下Zookeeper注册中心中的数据存储目录结构,从目录结构来窥探其实现机制。
Dubbo Zookeeper注册中心,其目录组织结构为 /dubbo/{ServiceName},再每个服务名称下会有4个目录:网络
基于Zookeeper注册中心的实现细节以下:多线程
扩展思考:架构
一、若是注册中心所有宕机,对整个服务体系会有什么影响?并发
若是整个注册中心所有宕机,整个服务调用能正常工做,不会影响现有的服务消费者调用,但消费端没法发现新注册的服务提供者。
二、若是注册中心内存溢出或频繁发生 Full Gc,对整个集群又会带来什么影响呢?
若是频繁发生Full GC,而且若是Full GC的时间超过了Zookeeper会话的过时时间,将会形成很是严重的影响,会触发全部临时节点被删除,消费端将没法感知服务提供者的存在,影响服务调用,将大面积抛出 No provider 等错误。正所谓成也临时节点、败也临时节点。
为了不Full Gc带来的严重后果,用于Dubbo注册中心的Zookeeper,必定会要独享,并及时作好内存、CPU等的监控与告警。
Dubbo的服务调用设计十分优雅,其实现原理以下图所示:
服务调用,重点阐述客户端发起一个RPC服务调用时的全部实现细节,包括服务发现、故障转移、路由转发、负载均衡等方面,是Dubbo实现灰度发布的理论基础。
客户端在向服务端发起请求时,首先须要知道的是当前有哪些可用的服务提供者,一般有两种服务发现机制:
静态化配置
不妨回想一下,在Dubbo等微服务框架出现以前,一个模块调用另一个模块一般的作法是使用一个配置文件,将服务提供的列表配置配置在配置文件中,客户端从按照配置文件中的列表进行沦陷。
其弊端也很是明显:若是须要调用的服务众多,配置文件会变得臃肿,对扩容缩容的管理、机器宕机等变动不友好,管理很是困难。
动态发现
一般基于注册中心实现服务的注册与动态发现,因为上文已详细介绍,在这里就不累述。
客户端经过服务发现机制,能动态发现当前存活的服务提供者列表,接下来要考虑的是若是从服务提供者列表中选择一个服务提供者发起调用,这就是所谓的负载均衡,即 LoadBalance。
在Dubbo中默认提供了随机、加权随机、最少活跃链接、一致性Hash等负载均衡算法。
其实Dubbo中不只提供了负载均衡机制,还提供了智能路由机制,这是实现Dubbo灰度发布的理论基础。
所谓的路由机制,是在服务提供者列表中,再设置必定的规则,进行过滤选择,负载均衡时只从路由过滤规则筛选出来的服务提供者列表中选择,为了更加形象的阐述路由机制的工做原理,给出以下示意图:
上述设置了一条路由规则,即查询机构ID为102的查询用户请求信息,请发送到新版本,即192168.3.102上,那主要在进行负载均衡以前先执行路由规则,从原始的服务提供者列表者按照路由规则进行过滤,从中挑选出符合要求的提供者列表,而后再进行负载均衡。
路由机制的核心理念:在进行负载均衡以前先对服务提供者列表运用路由规则,得出一个参与负载均衡的提供者列表。
远程服务调用一般涉及到网络等因素,客户端向服务提供者发起RPC请求调用时并不必定100%成功,当调用失败后该采用何种策略呢?
Dubbo提供了以下策略:
failover
失败后选择另一台服务提供者进行重试,重试次数可配置,一般适合实现幂等服务的场景。
failfast
快速失败,失败后当即返回错误。
failsafe
调用失败后打印错误日志,返回成功,一般用于记录审计日志等场景。
failback
调用失败后,返回成功,但会在后台定时无限次重试,重启后再也不重试。
forking
并发调用,收到第一个响应结果后返回给客户端。一般适合实时性要求比较高的场景,但浪费服务器资源,一般能够经过forks参数设置并发调用度。
Dubbo的通讯线程模型入下图所示:
网络传输一般须要自定义通讯协议,一般采用 Header + Body 的协议设计理念,而且 Header 长度固定,而且包含一个长度字段,用于记录整个协议包的大小。
网络传输为了提升传输效率,能够采起对传输数据进行压缩,一般是对 body 进行序列化与压缩。
Dubbo支持目前支持 java、compactedjava、nativejava、fastjson、fst、hessian二、kryo等序列化协议。
在Dubbo中默认会建立200个线程用于处理业务方法,所谓的线程派发机制就是IO线程如何决定何种请求转发到哪类线程中执行。
目前Dubbo中全部的心跳包、网络读写在IO线程中执行,没法经过配置进行修改。
Dubbo提供了以下几种线程派发机制(Dispatcher):
all
全部的请求转发到业务线程池中执行(除IO读写、心跳包)
message
只有请求事件在线程池中执行,其余在IO线程上执行。
connection
请求事件在线程池中执行,链接、断开链接事件排队执行(含一个线程的线程池)。
direct
全部请求直接在IO线程中执行。
舒适提示:有关线程模型,网络通讯模式,能够参考笔者以下这篇文章。
线程派发机制之全部会有多种策略,主要是考虑线程切换带来的开销是否能容忍,即线程切换带来的开销小于多线程处理带来的提高。
例如在Dubbo中,对心跳包只需直接返回PONG包(OK),逻辑很是简单,若是将其转换到业务线程池,并不能带来性能提高,反而由于须要线程切换,带来性能损耗,故在IO线程中直接发送响应包是一个很是可取的作法。
在网络编程中须要遵循一条最佳实践:IO线程中不能有阻塞操做,阻塞操做须要转发到业务线程池。
好了,本文就介绍到这里了,您的点赞与转发是对我持续输出高质量文章最大的鼓励。
欢迎关注公众号『中间件兴趣圈』,共同探究源码,交流高并发、架构经验,回复 PDF 更是可获取大量学习资料。