RPC 的全称是 Remote Procedure Call,即远程过程调用。
功能:
发起调用请求的那一方叫做调用方,被调用的一方叫做服务提供方。RPC 一般默认采用 TCP 来传输。我们常用的 HTTP 协议也是建立在 TCP 之上的。
RPC 的通讯流程:序列化 ---> 网络传输 ---> 反序列化
数据格式的约定内容叫做“协议”。大多数的协议会分成两部分,分别是数据头和消息体。数据头一般用于身份识别,包括协议标识、数据大小、请求类型、序列化类型等信息;消息体主要是请求的业务参数信息和扩展属性等。
更上一层楼,其中简化 API,屏蔽掉 RPC 细节,让使用方只需要关注业务接口也是关键(可以参考AOP 技术)。
AOP 技术:采用动态代理的技术,通过字节码增强对方法进行拦截增强,以便于增加需要的额外处理逻辑。
RPC 的通讯就变成流程:动态代理 ---> 序列化 ---> 网络传输 ---> 反序列化 ----> 执行
RPC 是解决应用间通信的一种方式,而无论是在一个大型的分布式应用系统还是中小型系统中,应用架构最终都会从“单体”演进成“微服务化”,整个应用系统会被拆分为多个不同功能的应用,并将它们部署在不同的服务器中,而应用之间会通过 RPC 进行通信,可以说 RPC 对应的是整个分布式应用系统,就像是“经络”一样的存在
RPC 框架能够帮助我们解决系统拆分后的通信问题,并且能让我们像调用本地一样去调用远程方法。利用 RPC 我们不仅可以很方便地将应用架构从“单体”演进成“微服务化”,而且还能解决实际开发过程中的效率低下、系统耦合等问题,这样可以使得我们的系统架构整体清晰、健壮,应用可运维度增强。当然 RPC 不仅可以用来解决通信问题,它还被用在了很多其他场景,比如:发 MQ、分布式缓存、数据库等。
上面的图不能表达所有的情况,但是能说明 RPC 的框架。
一句话概括: RPC 是我们最“熟悉的陌生人”。
这样整个协议就会拆分成两部分:协议头和协议体。
可以扩展的协议:
整体协议就变成了三部分内容:固定部分、协议头内容、协议体内容,前两部分我们还是可以统称为“协议头”
序列化就是将对象转换成二进制数据的过程,而反序列就是反过来将二进制转换为对象的过程。
常用的序列化
如何选择序列化?
首先可能想到的是性能和效率,还有空间开销,也就是序列化之后的二进制数据的体积大小。序列化协议的通用性和兼容性,序列化后的字节数据体积越小,网络传输的数据量就越小,传输数据的速度也就越快。
RPC 框架的过程中,构造入参、返回值对象,注意的问题:
网络 IO 模型:
最常用的就是同步阻塞 IO 和 IO 多路复用。
同步阻塞 IO:
应用进程发起 IO 系统调用后,应用进程被阻塞,转到内核空间处理。之后,内核开始等待数据,等待到数据之后,再将内核中的数据拷贝到用户内存中,整个 IO 处理完毕后返回进程。最后应用的进程解除阻塞状态,运行业务逻辑。这里我们可以看到,系统内核处理 IO 操作分为两个阶段——等待数据和拷贝数据。
IO 多路复用:
多路就是指多个通道,也就是多个网络连接的 IO,而复用就是指多个通道复用在一个复用器上。当用户进程调用了 select,那么整个进程会被阻塞。同时,内核会“监视”所有的 socket,当任何一个 socket 中的数据准备好了,select 就会返回。这个时候用户进程再调用 read 操作,将数据从内核中拷贝到用户进程。
什么是零拷贝?
所谓的零拷贝,就是取消用户空间与内核空间之间的数据拷贝操作。零拷贝有两种解决方式,分别是 mmap+write 方式和 sendfile 方式,mmap+write 方式的核心原理是通过虚拟内存来解决的。
五、动态代理
Spring AOP:
就是采用动态代理技术,通过对字节码进行增强,在方法调用的时候进行拦截,以便于在方法调用前后,增加我们需要的额外处理逻辑 。
参考:https://www.cnblogs.com/joy99/p/10941543.html
RPC 会自动给接口生成一个代理类,当我们在项目中注入接口的时候,运行过程中实际绑定的是这个接口生成的代理类。这样在接口方法被调用的时候,它实际上是被生成代理类拦截到了,这样我们就可以在生成的代理类里面,加入远程调用逻辑。
动态代理可以从这样三个角度去考虑: