浅谈rpc

什么是RPC?  (参考自:https://www.cnblogs.com/jimoer/p/15511954.html)
RPC(Remote Procedure Call)翻译成中文就是远程过程调用。RPC框架起到的作用就是为了实现,调用远程方法时,能够做到和调用本地方法一样,让开发人员更专注于业务开发,不用去考虑网络编程等细节。

 

RPC框架怎么就实现不让开发人员关注网络编程等细节呢?

首先我们区分两个角色一个服务提供方,一个是服务调用方。服务调用方其实是通过动态代理负载均衡网络调用等机制去服务提供方的机器上去执行对应的方法。服务提供方将方法执行完成后,将执行结果再通过网络传输返回到服务提供方。

 

 

 

 现在的服务都是集群部署,那么服务调用方怎么应该实时的知道服务提供方的集群中的变化,例如服务提供方的IP地址变了,或者是服务重启时怎么能够及时的切换流量呢?

这就需要注册中心起作用了,我们可以把注册中心看作服务端,然后每个服务都看成客户端,每个客户端都需要将自己注册到注册中心,然后一个服务调用方要调用另一个服务时,需要从注册中心获取服务提供方的信息,主要是获取服务提供方的服务器IP地址列表和端口信息,.

服务调用方获取到这些信息后缓存到自己本地,并且跟注册中心保持一个长连接当服务提供方有任何变化时,注册中心能够实时的通知给服务调用方,调用方能够及时更新自己本地缓存的信息(也可以采用定时轮询的方式)。

服务调用方获取到服务器IP地址信息后,根据自己的负载均衡策略选择一个IP地址然后发起网络调用的请求。

 

 

 

 

那么网络客户端是通过什么发起的网络调用呢?

可以自己使用JDK原生的BIO活NIO来实现一套网络通信模块,但是这里我们建议直接使用强大的网络通信框架Netty。它是基于NIO的网络通信框架,支持高并发,封装完善,而且性能好传输快。

 

 

客户端调用过程

因为我们知道数据在网络中传输的时候都是以二进制的形式的,所以在调用方将调用的参数进行传递的时候是需要进行序列化的。服务提供方在接收到参数时也是需要进行反序列化的。

 

 

网络协议

调用方既然需要序列化,服务提供方又要进行反序列化,这样双方就要确定好一个协议,调用方传输什么参数,服务提供方就按照这个协议去进行解析,而且在返回结果的时候也是按照这个协

 

 

 

这个协议应该是怎么样的结构,都是什么样子的呢?

首先第一个参数interfaces是,我们要让服务提供方知道调用方要调用哪个接口,以及接口中的哪个方法,并且方法的参数是什么类型的。

第二个参数是当前一次请求的一个唯一标识,在多个线程同时请求一个方法时,用这个id来进行区分,以后无论是做链路追踪还是日志管理都可以以此id为依据。

第三个参数就是 实际的调用方法中的参数值。具体是什么类型的,每个属性值都是什么。

 

 

调用

执行过程大致分为这几步:

  1. 获取调用服务的地址列表。
  2. 通过自身的负载均衡策略选择一个地址。
  3. Netty的网络请求处理(选择一个渠道Channel)。
  4. 根据接口类的全路径名和方法生成唯一标识。
  5. 通过加锁的方式保证生成的requestId的唯一性。
  6. 组织请求参数。
  7. 发起调用。
  8. 线程阻塞,直到服务提供方返回结果。
  9. 填充返回结果,返回到调用方。

 

 

 

服务端处理过程

服务调用方发起网络请求后,会阻塞住,直到服务提供方返回数据,所以服务提供方处理完调用方法的逻辑后,还是要唤醒阻塞的调用线程的。

服务提供方在处理请求时也是先通过Netty获取到数据,然后再进行反序列化,然后再根据协议获取到需要调用的方法,然后通过反射去进行调用。

 

Netty的返回入口在下面这部分逻辑里:

Netty的client接收到响应的消息后,先将结果返回到调用方,处理完成之后再去释放之前的阻塞调用线程。上面的步骤就是这样,按照之前请求的唯一标识放入到返回的信息中,然后将结果设置到代理对象中,再通过返回结果,然后唤醒之前的调用阻塞线程。

 

 

总结

其实整个RPC的请求过程就是如下(不含异步调用):

做一个总结,用大白话把一个RPC请求流程描述出来:
首先无论是调用方还是服务提供方都要注册到注册中心;

  1. 服务调用方把请求参数对象序列化成二进制数据,通过动态代理生成代理对象,通过代理对象,使用Netty选择一个从注册中心拉取到的服务提供方的地址,然后发起网络请求。
  2. 服务提供方从TCP通道中接收到二进制数据,根据定义的RPC网络协议,从二进制数据中反序列化后,分割出接口地址和参数对象,再通过反射找到接口执行调用。
  3. 然后服务提供方再把调用执行结果序列化后,回传到TCP通道中。
  4. 服务调用方获取到应答二进制数据后,再反序列化成结果对象。

这样就完成了一次RPC网络调用,其实后面框架扩展后,还要考虑限流、熔断、服务降级、序列化多样性扩展,服务监控、链路追踪等等功能。这些就要后面再扩展的讲了,这次就先到这了。

 

 

 

一个RPC请求是一个TCP的长连接还是短连接?

TCP连接的RPC请求一般都是使用的TCP的长连接,而长连接比短连接更节省资源,效率更高,例如dubbo、gRPC等。

 

TCP的长连接和短连接的区别

TCP短连接: client向server发起请求,server接收到请求,然后建立连接。client向server发送消息,server回应client,这样一次读写就完成了。一般是client端发起close操作。TCP短连接的优点是:管理起来比较简单,存在的连接都是有用的连接

TCP长连接:client向server发起请求连接,server接收到client的请求,建立连接。client与server完成一次请求后,并不会关闭连接,后面的读写操作都会继续使用这个连接。

由于TCP长连接一直不关闭,若是客户端以及不存在了,那么这个连接就会处于一个半关闭的状态。TCP的保活功能就是用来检测这种连接,但是如果长连接一直未关闭,当客户端越来越多,server早晚抗不住的,所以server会采取一些措施降低损耗,如关闭一些长时间没有读写事件发生的连接,还有做的更好的会以客户端为粒度,限制单个客户端的 最大链接数。

长连接多用于频繁操作,点对点的通信,而且连接数不能太多的情况。
短连接一般用于web网站的http服务,http应用层的短连接本质依赖的就是TCP的短连接。

 

 

 补充:

tcp/ip协议包含应用层、传输层、网络层、网络接口层。

1、应用层:应用程序间沟通的层,如简单电子邮件传输、文件传输协议、网络远程访问协议等。

2、传输层:在此层中,它提供了节点间的数据传送,应用程序之间的通信服务,主要功能是数据格式化、数据确认和丢失重传等。

3、网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。

4、网络接口层:接收IP数据报并进行传输,从网络上接收物理帧,抽取IP数据报转交给下一层,对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。

 

 

 

 

常用的网络通讯协议有哪些?

RMI,Hessian,Burlap,Httpinvoker,web service

RMI是java语言本身提供的远程通讯协议,稳定高效,是EJB的基础。但它只能用于JAVA程序之间的通讯。
Hessian和Burlap是caucho公司提供的开源协议,基于HTTP传输,服务端不用开防火墙端口。协议的规范公开,可以用于任意语言。
Httpinvoker是SpringFramework提供的远程通讯协议,只能用于JAVA程序间的通讯,且服务端和客户端必须使用SpringFramework。
Web service是连接异构系统或异构语言的首选协议,它使用SOAP形式通讯,可以用于任何语言,目前的许多开发工具对其的支持也很好。
 
 

常用的rpc协议有哪些?

XML-RPC,SOAP,WebService
  • 冗余数据太多,处理速度太慢。
  • RPC 风格的 Web Service 跨语言性不佳,而 Document 风格的 Web Service 又太过难用。
  • Web Service 没有解决用户的真正问题,只是把一个问题变成了另一个问题。
  • Web Service 的规范太过复杂,以至于在 .NET 和 Java 平台以外没有真正好用的实现,甚至没有可用的实现。
  • 跨语言跨平台只是 Web Service 的一个口号,虽然很多人迷信这一点,但事实上它并没有真正实现。
PHPRPC
  • 基于 PHP 内置的序列化格式,在跨语言的类型映射上存在硬伤。
  • 通讯上依赖于 HTTP 协议,没有其它底层通讯方式的选择。
  • 内置的加密传输既是特点,也是缺点。
  • 虽然比基于 XML 的 RPC 速度快,但还不是足够快。
Hessian
  • 二进制的数据格式完全不具有可读性。
  • 官方只提供了两个半语言的实现(Java,ActionScript 和不怎么完美的 Python 实现),其它语言的第三方实现良莠不齐。
  • 支持的语言不够多,对 Web 前端的 JavaScript 完全无视。
  • 虽然是动态 RPC,但动态性仍然欠佳。
  • 虽然比基于 XML 的 RPC 速度快,但还不是足够快。
JSON-RPC
  • JSON 具有文本可读性,且比 XML 更简洁。
  • JSON 受 JavaScript 语言子集的限制,可表示的数据类型不够多。
  • JSON 格式无法表示数据内的自引用,互引用和循环引用。
  • 某些语言具有多种版本的实现,但在类型影射上没有统一标准,存在兼容性问题。
  • JSON-RPC 虽然有规范,但是却没有统一的实现。在不同语言中的各自实现存在兼容性问题,无法真正互通。

 

 

常用的rpc协议有哪些?

Java中的RPC框架比较多,各有特色,广泛使用的有RMI、Hessian、Dubbo

 

posted @   雪域飞魂  阅读(235)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示