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

前言:

这篇文章我们来聊一聊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调用模型图如下所示:

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

2.1 注册中心

注册中心是RPC框架中的管理者和协调者角色,虽然在远程过程调用中服务消费者会不经过注册中心,会直接向服务提供者发送请求,但是随着我们的服务方越来越多,每个服务的实例也不断变化的,且每个服务的地址,端口等信息是需要通知到消费方的,所以我们需要一个类似“管家”的角色,来负责管理服务注册和发现的工作,这个“管家”我们称之为注册中心。

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

目前市面上比较流行的注册中心有:Zookper、 Nacos、Consul、Eurake等,针对于上面功能的实现方式也有所不同,以下是注册中心的对比:

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方式来进行选择的,后续如果需要进行拓展和按不同配置加载,可以通过配置的方式来实现插件的可插拔。

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

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

3.1 注册中心

代码实现如下:

因为我们是以可拓展和接口方式实现的,所以我们定义了一些接口,通过不同的实现来进行区分,后期可以通过不同的配置来选择合适的注册中心。

3.2 服务提供方

服务提供方通过使用Spring的事件来进行监听,同时根据声明式的注解来进行解析和注册,同时通过组装元数据,将自己的服务注册到注册中心,完成服务提供方的服务注册,同时启动Netty的客户端,来进行客户端的监听,从而进行服务调用,具体流程图如下:

部分实现代码如下:

自动装备逻辑:

使用和服务注册逻辑:

3.3 服务消费方

服务消费方的逻辑稍微复杂一些,需要通过自动装配来创建新的BeanDefination, 然后从所有的Bean中找到相关的带有RPC注解的参数,重写BeanDefination,重写的Bean需要构建新的元数据和存入客户端缓存,然后通过动态代理的方式,创建一个代理对象,对象使用负载均衡在服务发现的时候选择一个地址,通过Netty的方式进行通信和数据交互,最后返回相关数据对象,具体的流程如下图:

部分实现代码如下:

启动开始类代码:

代理类实现代码:

负载均衡实现代码:(SPI可拓展模式)

目前采用轮训和随机的方式实现的,后期可根据接口进行拓展。

3.4 通讯框架

我们使用Netty4实现了通讯框架,采用了NettyClient和NettyServer来实现:

3.5 通讯协议

我们目前使用了自定义的通信协议来实现:

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

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

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

第四个字节表示消息长度,即此四个字节后面此长度的内容是消息content。

3.6 序列化协议

目前支持JSON和ProtoBuf,后期我们可以通过SPI进行拓展和可配置。

整体核心调用流程:

四、总结

本文从整体名词介绍、内部组件组件介绍等两个方面阐述了RPC的框架模型,从技术选型、具体代码等实现了一个RPC框架并应用到项目中。目前RPC框架整体搭建完成,可以正常通过注解接入业务方使用,但还有很多细节需要更仔细地去考虑和思索,比如系统的可拓展性和框架的整体性能等。希望通过阅读本篇文章,可以让读者对RPC有更清晰的了解,让自己的基础技能有一个更高的提升。

*文/Wade

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

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

原文地址:https://cloud.tencent.com/developer/article/2192171

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340