前语:

这篇文章咱们来聊一聊RPC结构,为什么要聊RPC呢 ?

首先从个人成长视点,假如一个新时代码农能清楚的了解RPC结构所具有的要素,把握RPC结构中触及的服务注册发现、负载均衡、序列化协议、RPC通讯协议、Socket通讯、异步调用、熔断降级等技能,能够全方位的提高根本素质。

其次,现在市面上也有十分多优异的结构,GitHub上也有相关源码,但好记性不如烂笔头,只要自己真正了解并且动手去尝试写一个RPC结构,才是咱们去把握这门技能的最优路径。

一、介绍

研究一个概念或许结构,带着三个W去考虑,可能会对他有更加深刻的了解:

1)What,什么是RPC结构,RPC是 Remote Procedure Call 的简称,长途过程调用,那么什么叫长途过程调用呢,你能够了解为咱们调用外部(长途)服务就像调用自己本地方法相同。

2)Where,RPC结构用在什么地方,在分布式体系和微服务盛行的今日,各事务体系会被独立拆分出来成为一个个独立的web运用,运用之间的交互和数据传输就成了必不可少的一环,RPC便是为了完结独立服务之间长途交互的结构。

3)Why,为什么需求一个RPC结构,服务之间的调用需求各种场景和因素的考虑,内部原理十分杂乱和繁琐,一起在集群情况下,服务的负载均衡,熔断,限流等都是需求去考虑的,这时分就需求一个集服务注册发现、负载均衡、序列化协议、RPC通讯协议、Socket通讯、异步调用、熔断降级等技能为一体的技能去完结这些公共功用,RPC结构便是在这种情况下应运而生。

现在比较干流的RPC结构包含谷歌开源的GRPC、阿里巴巴的Dubbo、Netflix 的SpringCloud等。

二、RPC结构根本组成

RPC结构需求的最根本的三个要素:

  • ServiceProvider: 服务供给方,供给相关服务接口。
  • ServiceConsumer: 服务消费方,消费服务供给方的接口。
  • Registry: 注册中心,用于进行服务的注册、发现、治理、高可用。

依据三个最根本要素,还会延伸出包含负载均衡器、熔断降级器、通讯协议组件、序列化协议等等组件。

一个最简略的RPC调用模型图如下所示:

带你手把手实操一个RPC框架

下面做一些名词的介绍和解释:

2.1 注册中心

注册中心是RPC结构中的管理者和协调者人物,虽然在长途过程调用中服务消费者会不经过注册中心,会直接向服务供给者发送恳求,但是随着咱们的服务方越来越多,每个服务的实例也不断改变的,且每个服务的地址,端口等信息是需求通知到消费方的,所以咱们需求一个相似“管家”的人物,来担任管理服务注册和发现的工作,这个“管家”咱们称之为注册中心。

一个合格的注册中心需求具有包含缓存和持久化服务供给方数据,动态更新服务供给者信息,动态监听服务供给方节点改变,推送节点改变到消费方,查询服务供给方数据等功用。

现在市面上比较盛行的注册中心有:Zookper、 Nacos、Consul、Eurake等,针对于上面功用的完结方法也有所不同,以下是注册中心的比照:

Zookeeper Nacos Consul Eurake
一致性协议 CP CP + AP CP AP
雪崩保护
多数据中心 不支撑 支撑 支撑 支撑
主动刊出实例 支撑 支撑 支撑 支撑

2.2 服务供给方(RPC服务端)

其需求对外供给服务接口,一个服务方需求包含发动连接注册中心,注册相关信息到注册中心,供给服务下线和更新机制,保护服务名和服务的映射,序列化和反序列化,发动通讯等

现在服务供给方有两种服务供给维度,依据接口的服务供给和依据服务的服务供给,Dubbo3.0 之前是依据接口维度做的服务注册,Dubbo3.0之后逐渐向服务维度的服务注册发现挨近,SpringCloud是依据服务来进行注册发现的,在云原生和容器化越来越火的今日,依据服务能够更好的适配容器化和云原生。

2.3 服务消费方(RPC消费端)

服务消费方需求具有能够从注册中心拉取服务列表,缓存服务列表,动态监听和更新服务列表的功用,还需求具有针对于服务的负载均衡战略,序列化和反序列化,依据约好的通讯协议进行调用等。

现在Dubbo是依据署理和Spring的BeanDefination来完结的,在消费发动的时分会去扫描依据自界说注解或配备的信息,然后生成一个相应的署理目标,注册到Spring容器中,在调用的时分直接经过署理类进行相关一系列调用。SpringCloud是依据HTTP协议和增强版的RestTemplate来完结的,内部完结了Ribbon的负载均衡,消费方能够经过Feign或许RestTemplate完结长途调用。

2.4 通讯结构

通讯结构是服务之间进行IO交互和传输的确保,消费端需求经过通讯结构和供给方进行交互,获取数据,现在市面上干流的依据Java的NIO通讯结构便是Netty。

2.5 通讯协议

通讯协议是消费端和服务端约好好一种交互协议,当消费端拿到服务端供给的IO流之后,需求依据通讯协议获取详细的数据内容,现在TCP通讯协议比较通用的是HTTP、FTP、SMTP协议等,SpringCloud是依据HTTP的通讯协议完结的,Dubbo内部自己集成了一套通讯协议。

业界的干流协议的解决方案能够归纳如下:

  • 音讯定长,例如每个报文的巨细为固定长度100字节,假如不够用空格补足。
  • 在包尾特殊结束符进行切割。
  • 将音讯分为音讯头和音讯体,音讯头中包含表明音讯总长度(或许音讯体长度)的字段。

经过比照,咱们发现第三点是最为灵活和可拓宽的,一般引荐都会运用第三种。

2.6 序列化

2.6.1 概念介绍

序列化(serialization)便是将目标序列化为二进制形式(字节数组),一般也将序列化称为编码(Encode),首要用于网络传输、数据持久化等。

反序列化(deserialization)则是将从网络、磁盘等读取的字节数组还原成原始目标,以便后续事务的进行,一般也将反序列化称为解码(Decode),用于网络传输目标的解码,以便完结长途调用。

2.6.2 序列化协议

  • XML & SOAP

XML是一种常用的序列化和反序列化协议,具有跨机器,跨语言等长处。XML历史悠久,其1.0版别早在1998年就形成标准,并被广泛运用至今,现在金融和银行职业运用较多。

  • JSON

JSON 全称 (Javascript Object Notation) 起源于弱类型语言Javascript, 它的发生来自于一种称之为”Associative array”的概念,其本质是便是选用”Attribute-value”的方法来描绘目标。实际上在Javascript和PHP等弱类型语言中,类的描绘方法便是Associative array。JSON的具有数据简略,可接受程度高,结构简练,序列化包体小等特色,现在大部分的公司都是运用这种序列化协议来完结的。

  • Protobuf

由谷歌开发的一款高功能序列化结构,是一个纯粹的展现层协议,能够和各种传输层协议一起运用,现在支撑Java、C++、Python 等多种语言,他具有更小的数据量,更快的解析速度,简略的调用等特色,现在得物运用的Dubbo2.7.7版别 默认运用这种序列化协议。

2.7 负载均衡

负载均衡是确保服务供给方在多实例的情况下确保负载的均衡的一种战略,现在大体有如下几种负载均衡战略:

1)轮训,选用计数器的方法,依据计数器的值和实例数量进行取余。

2)随机,选用随机恳求的方法,随机一个Random的数值,依据random进行取余。

3)加权轮训,选用权重的方法,给每一个实例配备不同的权重份额,经过份额挑选合适的实例。

4) 一致性Hash,选用Hash环的方法,大体的完结思路是经过寻址的方法找到就近的一个节点,详细能够自行网上查找一下相关文档了解。

三、完结

既然是当作练手完结一个RPC结构,所以会尽量借鉴当时干流的结构,技能选型方面:

注册中心:挑选Zookeeper来完结。

服务供给方: 挑选依据服务维度来完结服务发现,现在干流结构都是依据这个来做的。

服务消费方: 挑选Dubbo相似的依据署理Spring的BeanDefination来完结。

通讯结构: Netty。

通讯协议: 选用上述的第三种方法。

序列化协议: 支撑JSON 和 Protobuf。

负载均衡: 完结轮训和随机。

当然,上述的组件都是运用SpringBoot的SPI方法来进行挑选的,后续假如需求进行拓宽和按不同配备加载,能够经过配备的方法来完结插件的可插拔。

废话不多说,先贴上项目全体结构:

带你手把手实操一个RPC框架

全体代码结构如上,下面针对模块一一解说:

3.1 注册中心

代码完结如下:

因为咱们是以可拓宽和接口方法完结的,所以咱们界说了一些接口,经过不同的完结来进行区别,后期能够经过不同的配备来挑选合适的注册中心。

带你手把手实操一个RPC框架

3.2 服务供给方

服务供给方经过运用Spring的事件来进行监听,一起依据声明式的注解来进行解析和注册,一起经过组装元数据,将自己的服务注册到注册中心,完结服务供给方的服务注册,一起发动Netty的客户端,来进行客户端的监听,然后进行服务调用,详细流程图如下:

带你手把手实操一个RPC框架

部分完结代码如下:

主动配备逻辑:

带你手把手实操一个RPC框架

运用和服务注册逻辑:

带你手把手实操一个RPC框架

3.3 服务消费方

服务消费方的逻辑稍微杂乱一些,需求经过主动装配来创立新的BeanDefination, 然后从一切的Bean中找到相关的带有RPC注解的参数,重写BeanDefination,重写的Bean需求构建新的元数据和存入客户端缓存,然后经过动态署理的方法,创立一个署理目标,目标运用负载均衡在服务发现的时分挑选一个地址,经过Netty的方法进行通讯和数据交互,最终返回相关数据目标,详细的流程如下图:

带你手把手实操一个RPC框架

部分完结代码如下:

发动开始类代码:

带你手把手实操一个RPC框架

带你手把手实操一个RPC框架

署理类完结代码:

带你手把手实操一个RPC框架

负载均衡完结代码:(SPI可拓宽形式)

现在选用轮训和随机的方法完结的,后期可依据接口进行拓宽。

带你手把手实操一个RPC框架

3.4 通讯结构

咱们运用Netty4完结了通讯结构,选用了NettyClient和NettyServer来完结:

带你手把手实操一个RPC框架

带你手把手实操一个RPC框架

3.5 通讯协议

咱们现在运用了自界说的通讯协议来完结:

第一个字节是魔法数,比如我界说为0X35。

第二个字节代表协议版别号,以便对协议进行扩展,运用不同的协议解析器。

第三个字节是恳求类型,如0代表恳求1代表呼应。

第四个字节表明音讯长度,即此四个字节后面此长度的内容是音讯content。

带你手把手实操一个RPC框架

3.6 序列化协议

现在支撑JSON和ProtoBuf,后期咱们能够经过SPI进行拓宽和可配备。

带你手把手实操一个RPC框架

全体核心调用流程:

带你手把手实操一个RPC框架

四、总结

本文从全体名词介绍、内部组件组件介绍等两个方面论述了RPC的结构模型,从技能选型、详细代码等完结了一个RPC结构并运用到项目中。现在RPC结构全体搭建完结,能够正常经过注解接入事务方运用,但还有许多细节需求更细心地去考虑和思索,比如体系的可拓宽性和结构的全体功能等。希望经过阅览本篇文章,能够让读者对RPC有更明晰的了解,让自己的根底技能有一个更高的提高。

*文/Wade

关注得物技能,每周一三五晚18:30更新技能干货

要是觉得文章对你有协助的话,欢迎评论转发点赞~