RPC:在分布式计算,远程过程调⽤(英语:Remote Procedure Call,缩写为 RPC)是⼀个计算机通信协 议。该协议允许运⾏于⼀台计算机的程序调⽤另⼀个地址空间(通常为⼀个开放⽹络的⼀台计算机)的 ⼦程序,⽽程序员就像调⽤本地程序⼀样,⽆需额外地为这个交互作⽤编程(⽆需关注细节)。RPC是 ⼀种服务器-客户端(Client/Server)模式,经典实现是⼀个通过发送请求-接受回应进⾏信息交互的 系统。
Apache Dubbo 是⼀款⾼性能、轻量级的开源 Java 服务框架
基本原理:
负载均衡
如果在消费端和服务端都配置了负载均衡策略,以消费端为准。 这其中⽐较难理解的就是最少活跃调⽤数是如何进⾏统计的?
讲道理,最少活跃数应该是在服务提供者端进⾏统计的,服务提供者统计有多少个请求正在执⾏中。 但在Dubbo中,就是不讲道理,它是在消费端进⾏统计的,为什么能在消费端进⾏统计?
逻辑是这样的:
- 消费者会缓存所调⽤服务的所有提供者,⽐如记为p1、p2、p3三个服务提供者,每个提供者内都有⼀ 个属性记为active,默认位0
- 消费者在调⽤次服务时,如果负载均衡策略是leastactive
- 消费者端会判断缓存的所有服务提供者的active,选择最⼩的,如果都相同,则随机
- 选出某⼀个服务提供者后,假设为p2,Dubbo就会对p2.active+1
- 然后真正发出请求调⽤该服务
- 消费端收到响应结果后,对p2.active-1
- 这样就完成了对某个服务提供者当前活跃调⽤数进行了统计,并且并不影响服务调⽤的性能
服务超时
在服务提供者和服务消费者上都可以配置服务超时时间,这两者是不一样的。
消费者调⽤⼀个服务,分为三步:
- 消费者发送请求(⽹络传输)
- 服务端执⾏服务
- 服务端返回响应(⽹络传输)
如果在服务端和消费端只在其中⼀⽅配置了timeout,那么没有歧义,表示消费端调⽤服务的超时时间,消费端如果超过时间还没有收到响应结果,则消费端会抛超时异常,
但,服务端不会抛异常,服务端在执⾏服务后,会检查执⾏该服务的时间,如果超过timeout,则会打印⼀个超时⽇志。服务会正常的执⾏完。
如果在服务端和消费端各配了⼀个timeout,那就比较复杂了,
假设 1. 服务执⾏为5s 2. 消费端timeout=3s 3. 服务端timeout=6s 那么消费端调⽤服务时,消费端会收到超时异常(因为消费端超时了),服务端⼀切正常(服务端没有超时)。
集群容错
集群容错表示:服务消费者在调⽤某个服务时,这个服务有多个服务提供者,在经过负载均衡后选出其中 ⼀个服务提供者之后进⾏调⽤,但调⽤报错后,Dubbo所采取的后续处理策略。
服务降级
服务降级表示:服务消费者在调⽤某个服务提供者时,如果该服务提供者报错了,所采取的措施。
集群容错和服务降级的区别在于:
- 集群容错是整个集群范围内的容错
- 服务降级是单个服务提供者的⾃身容错
本地存根
本地存根,名字很抽象,但实际上不难理解,本地存根就是⼀段逻辑,这段逻辑是在服务消费端执⾏的, 这段逻辑⼀般都是由服务提供者提供,服务提供者可以利用这种机制在服务消费者远程调⽤服务提供者之前或之后再做⼀些其他事情,⽐如结果缓存,请求参数验证等等。
本地伪装
本地伪装就是Mock,Dubbo中Mock的功能相对于本地存根更简单⼀点,Mock其实就是Dubbo中的服务容错的解决方案。
参数回调 Callback
在Dubbo中,参数回调通常指的是一种服务提供者在完成某些异步任务后,通过回调函数将结果返回给服务消费者的机制。这种机制可以用于处理一些异步场景,例如,服务提供者在处理任务完成后,通知消费者。
⾸先,如果当前服务⽀持参数回调,意思就是:对于某个服务接⼝中的某个⽅法,如果想⽀持消费者在调⽤这个⽅法时能设置回调逻辑,那么该⽅法就需要提供⼀个⼊参⽤来表示回调逻辑。
参数回调的机制使得服务提供者和消费者能够在异步场景中更灵活地进行通信。
因为Dubbo协议是基于⻓连接的,所以消费端在两次调⽤同⼀个⽅法时想指定不同的回调逻辑,那么就需 要在调⽤时在指定⼀定key进行区分。
异步调⽤
理解起来比较容易,主要要理解CompletableFuture,如果不理解,就直接把它理解为Future
泛化调用
实现了GenericService接⼝的就是泛化服务
Dubbo中的REST
注意Dubbo的REST也是Dubbo所支持的⼀种协议。 当我们⽤Dubbo提供了⼀个服务后,如果消费者没有使⽤Dubbo也想调⽤服务,那么这个时候我们就可以让我们的服务支持REST协议,这样消费者就可以通过REST形式调⽤我们的服务了。
注意:如果某个服务只有REST协议可⽤,那么该服务必须⽤@Path注解定义访问路径
蓝绿发布与灰度发布
在一般情况下,升级服务器端应用,需要将应用源码或程序包上传到服务器,然后停止掉老版本服务,再启动新版本。但是这种简单的发布方式存在两个问题,一方面,在新版本升级过程中,服务是暂时中断的,另一方面,如果新版本有BUG,升级失败,回滚起来也非常麻烦,容易造成更长时间的服务不可用。
为了解决这些问题,人们研究出了多种发布策略,下面我们一一介绍。
蓝绿部署
所谓蓝绿部署,是指同时运行两个版本的应用,如上图所示,蓝绿部署的时候,并不停止掉老版本,而是直接部署一套新版本,等新版本运行起来后,再将流量切换到新版本上。但是蓝绿部署要求在升级过程中,同时运行两套程序,对硬件的要求就是日常所需的二倍,比如日常运行时,需要10台服务器支撑业务,那么使用蓝绿部署,你就需要购置二十台服务器。
滚动发布
滚动发布能够解决掉蓝绿部署时对硬件要求增倍的问题。
所谓滚动升级,就是在升级过程中,并不一下子启动所有新版本,是先启动一台新版本,再停止一台老版本,然后再启动一台新版本,再停止一台老版本,直到升级完成,这样的话,如果日常需要10台服务器,那么升级过程中也就只需要11台就行了。
但是滚动升级有一个问题,在开始滚动升级后,流量会直接流向已经启动起来的新版本,但是这个时候,新版本是不一定可用的,比如需要进一步的测试才能确认。那么在滚动升级期间,整个系统就处于非常不稳定的状态,如果发现了问题,也比较难以确定是新版本还是老版本造成的问题。
为了解决这个问题,我们需要为滚动升级实现流量控制能力。
灰度发布
灰度发布也叫金丝雀发布,起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。
在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的A/B测试。
当确认新版本运行良好后,再逐步将更多的流量导入到新版本上,在此期间,还可以不断地调整新旧两个版本的运行的服务器副本数量,以使得新版本能够承受越来越大的流量压力。直到将100%的流量都切换到新版本上,最后关闭剩下的老版本服务,完成灰度发布。
如果在灰度发布过程中(灰度期)发现了新版本有问题,就应该立即将流量切回老版本上,这样,就会将负面影响控制在最小范围内。
Dubbo底层⽹络连接模型
在Dubbo中,有两个参数⽤来配置服务消费者和服务提供者直接的socket连接个数:
- shareconnections:表示可共享的socket连接个数
- connections:表示不共享的socket连接个数
服务A的shareconnections为2时,服务A的消费者会向服务A的提供者建⽴两个socket连接:
服务A的connections为2时,服务A的消费者会向服务A的提供者建⽴两个socket连接:
当某个消费者应⽤引⼊了同⼀个服务的两个版本(这两个版本共⽤⼀个端⼝号:20881),这时如果 shareconnections为2,则在消费端这边所引⼊的两个版本服务会共享这两个socket连接,如果有3个版 本,也会共享这两个socket连接。
当某个消费者应⽤引⼊了同⼀个服务的两个版本(这两个版本共⽤⼀个端⼝号:20881),这时如果 connections为2,则在消费端这边所引⼊的两个版本服务会单独拥有两个socket连接,如果有3个版本, 就会有3个socket连接。
Dubbo消费端的线程模型
在整个消费者调⽤过程中,最关键的是DefaultFuture,DefaultFuture起到的最⽤是衔接Request和 Response,既保证了⾮阻塞调⽤,也达到了Request-Response模型。
Dubbo服务端的线程模型
在整个消费者调⽤过程中,各个线程池都⽐较重要,其中⽐较有特⾊的就是AllChannelHandler,它完成 了IO线程转向⽤户线程的任务转移,⽐较关键。