RPC学习

介绍

RPC全称叫Remote Procedure Call,中文叫远程过程调用,它是一种通过网络从一台计算机向另一台远程计算机上所写的模块上请求服务,一般是函数调用形式,而不需要自己实现底层变量类型转换数据再传输等网络技术的协议。

优点

安全性一直是RPC的弊病,因为此协议一般没有用于验证调用者机制,如果把它直接替代简单的CURD并暴露给外部用户使用可能会很快被黑客利用。所以一般应用在企业内网或者设定防火墙ACL或者由远程计算机自行判断IP。

缺点

安全性一直是RPC的弊病,因为此协议一般没有用于验证调用者机制,如果把它直接替代简单的CURD并暴露给外部用户使用可能会很快被黑客利用。所以一般应用在企业内网或者设定防火墙ACL或者由远程计算机自行判断IP。

RPC架构

在这里插入图片描述
在这里插入图片描述

RPC的实现原理

1)一个典型的rpc实现

在这里插入图片描述
RpcServer: 负责导出(export)远程接口

RpcClient: 负责导入(import)远程接口的代理实现

RpcProxy: 远程接口的代理实现

RpcInvoker:

​ 客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回

​ 服务方实现:负责调用服务端接口的具体实现并返回调用结果

RpcProtocol: 负责协议编/解码

RpcConnector: 负责维护客户方和服务方的连接通道和发送数据到服务方

RpcAcceptor: 负责接收客户方请求并返回请求结果

RpcProcessor: 负责在服务方控制调用过程,包括管理调用线程池、超时时间等

RpcChannel: 数据传输通道

2)实现过程

RPC服务方通过RpcServer去导出(export)远程接口方法,而客户方通过RpcClient去引入(import)远程接口方法。

客户方像调用本地方法一样去调用远程接口方法,RPC框架提供接口的代理实现,实际的调用将委托给代理RpcProxy。

代理封装调用信息并将调用转交给RpcInvoker去实际执行。

在客户端的RpcInvoker通过连接器RpcConnector去维持与服务端的通道RpcChannel,并使用RpcProtocol执行协议编码(encode)并将编码后的请求信息通过通道发送给服务方。

Rpc服务端接收器RpcAcceptor接收客户端的调用请求,同样使用RpcProtocol执行协议解码(decode)。

解码后的调用信息传递给RpcProcessor去控制处理调用过程,最后再委托给RpcInvoker去实际执行并返回调用结果。

RPC调用的过程需要解决四个问题:

客户端和服务端如何建立网络连接?

服务端如何处理请求?

数据传输采用什么协议?

数据该如何序列化和反序列化?

客户端和服务端如何建立网络连接

客户端和服务端之间基于TCP协议建立网络连接最常用的途径有两种。

1、HTTP通信

HTTP通信是基于应用层HTTP协议的,而HTTP协议又是基于传输层TCP协议的。一次HTTP通信过程就是发起一次HTTP调用,而一次HTTP调用就会建立一个TCP连接,经历一次三次握手的过程来建立连接,请求完成后再经历一次四次挥手的过程来断开连接。
在这里插入图片描述
2、Socket通信

Socket通信是基于TCP/IP协议的封装,建立一次Socket连接至少需要一对套接字,其中一个运行的客户端,成为ClientSocket;另一个运行于服务器端,称之为ServerSocket。

服务监听器:ServerSocket通过调用bind()函数绑定某个具体端口,然后调用listen()函数实时监控网络状态,等待客户端的连接请求。

客户端请求:ClientSocket调用connect()函数向ServerSocket绑定的地址和端口发起连接请求。

服务端连接确认:当ServerSocket监听到或者接收到ClientSocket的连接请求时,调用accept()函数响应ClinetSocket的请求,同客户端建立连接。

数据传输:当ClientSocket和ServerSocket建立连接后,ClinetSocket调用send()函数,ServerSocket调用receive()函数,ServerSocket处理完请求后,调用send()函数,ClientSocket调用receive()函数,就可以得到返回结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nsue0tN3-1661156784377)
在这里插入图片描述

服务端如何处理请求

假设这时候客户端和服务端已经建立了网络连接,服务端又该如何处理客户端的请求呢?通常来讲,有三种处理方式。

  • 同步阻塞方式:客户端每发一次请求,服务端就生成一个线程去处理。

  • 同步非阻塞方式:客户端每发一次请求,服务端并不是每次都创建一个新线程来处理,而是通过I/O多路复用技术进行处理。就是把多个I/O的阻塞复用到同一个select的阻塞上,从而使系统在单线程的情况下可以同时处理多个客户端请求。这种方式的优势是

  • 异步非阻塞方式:客户端只需要发起一个I/O操作然后立即返回,等I/O操作真正完成以后,客户端会得到I/O操作完成的通知,此时客户端只需要对数据进行处理就好了,不需要进行实际的

    I/O读写操作,因为真正的I/O读取或者写入操作已经由内核完成了。这种方式的优势是客户端无需等待,不存在阻塞等待问题。

不同的处理方式适用于不同的业务场景:

  • BIO适用于连接数比较小的业务场景,这样的话不至于系统中没有可用线程去处理请求。这种方式写的程序也比较简单直观,易于理解。
  • NIO适用于连接数比较多并且请求消耗比较轻的业务场景,比如聊天服务器。这种方式相比BIO,相对于编程比较复杂。
  • AIO适用于连接数比较多而且请求消耗比较重的业务场景,比如涉及I/O操作的相册服务器。这种方式相比于另外两种,编程难度最大,程序也不易于理解。

上面两个问题就是“通信框架”要解决的问题,你可以基于现有的Socket通信,在服务消费者和服务提供者之间建立网络连接,然后在服务器提供者一侧基于BIO、NIO和AIO这三种方式中的任意一种实现服务端请求处理,最后再花费一些精力去解决服务消费者和服务提供者之间的网络可靠性问题。这种方式对于Socket网络编程、多线程编程知识都要求比较高,建议最为稳妥的方式是使用成熟的开源方案,比如Netty、MINA等,它们都是经过业界大规模应用后,被充分论证是跟可靠的方案。

假设客户端和服务端的连接已经建立了,服务端也能正确地处理了,接下来完成一次正常的RPC调用还需要解决两个问题,即数据传输采用什么协议以及数据该如何序列化和反序列化。

数据传输采用什么协议

最常用的有HTTP协议,它是一种开放的协议,各大网站的服务器和浏览器之间的数据传输大都采用了这种协议。还有一些定制的私有协议,比如阿里巴巴开源的Dubbo协议。无论是开放的还是私有的协议,都必须定义一个契约,以便服务器和服务提供者之间能够达成共识。服务消费者按照契约,对传输的数据进行解码,然后通过网络传输过去;服务提供者从网络上接收到数据后,按照契约,对传输的数据进行解码,然后处理请求,再把处理后的结果进行编码,通过网络传输返回给服务器消费者;服务器消费者再对返回的结果进行解码,最终得到服务器提供者处理后的返回值。

通常协议契约包括两个部分:消息头和消息体。其中消息头存放的是协议的公共字段以及用户扩展字段,消息体存放的是传输数据的具体内容。以HTTP协议为例,下图展示了一段采用HTTP协议传输的数据响应报文,主要分为消息头和消息体两部分,其中消息头中存放的是协议的公共字段,比如Server代表是服务端服务器类型,Content-Length代表返回数据的长度,Content-Type代表返回数据的类型;消息体中存放的是具体的返回结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eZRmbbht-1661156784377)
在这里插入图片描述

数据该如何序列化和反序列化

一般数据再网络中进行传输,都要先在发送方一段对数据进行编码,经过网络传输到达另一端后,再对数据进行解码,这个过程就是序列化和反序列化。

为什么要对数据进行序列化和反序列化呢?要知道网络传输的耗时一方面取决于网络带宽的大小,另一方面取决于数据传数量。想要加快网络传输,要么提高网络带宽,要么减小数据传输量,而对数据进行编码的目的就是减小数据传输量。

常用的序列化方式分为两类:文本类如XML/JSON等,二进制类如PB/Thrift等,而具体采用哪种序列化方式,主要取决于三个方面因素。

  • 支持数据结构类型的丰富度:数据结构种类支持的越多越好。
  • 跨语言支持:序列化方式是否支持跨语言也是一个很重要的因素,否则使用场景就比较局限,比如java序列化只支持java语言,就不能用于跨语言的服务调用了。
  • 性能:主要看两点,一个是序列化后的压缩比,一个是序列化数据。

常见的开源RPC框架

Dubbo:国内最早开源的RPC框架,仅支持java语言。

Dubbo具体实现:

Dubbo的架构主要包含四个角色,其中Consumer是服务消费者,Provider是服务提供者,Registry是注册中心,Monitor是监控系统。

具体的交互流程是Consumer一端通过注册中心获取到Provider节点后,通过Dubbo的客户端SDK与Provider建立连接,并发起调用。Provider一端通过Dubbo

的服务端SDK接收到Consumer的请求,处理后再把结果返回给Consumer。

服务消费者和服务提供者都需要引入Dubbo的SDK才来完成RPC调用,因为Dubbo本身是采用java语言实现的,所以要求服务消费者和服务提供者也都必须采用java语言才可以应用。

Dubbo的调用框架实现:

通用框架方面,Dubbo默认采用Netty作为通信框架。

通用协议方面,Dubbo除了支持私有的Dubbo协议外,还支持RMI协议,Hession协议、HTTP协议、Thrift协议等。

序列化格式方面,Dubbo支持多种序列化格式,比如Dubbo、Hession、JSON、Kryo、FST等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值