RPC
远程过程调用(Remote Procedure Call Protocol
),是从一台机器通过网络调用到另一台机器的某个方法。
基本结构
一个最简单的 RPC
框架分成三个部分:注册中心、服务端、客户端。
一个基本的 RPC
框架,需要包含以下部分:
注册中心:
服务端在启动的时候,扫描所有的服务,然后将自己的服务地址和服务名注册到注册中心。
客户端在调用服务之前,通过注册中心查找到服务的地址,就可以通过服务的地址调用到服务啦。
常见的注册中心有
Zookeeper
、Eureka
等。动态代理:
- 客户端调用接口,需要框架能自己根据接口去远程调用服务,这一步是用户无感知的。
- 这样一来,就需要使用到动态代理,用户调用接口,实际上是在调用动态生成的代理类。
- 常见的动态代理有:
JDK Proxy
,CGLib
,Javassist
等。网络传输:
RPC
远程调用实际上就是网络传输,所以网络传输是RPC
框架中必不可少的部分。- 网络框架有
Java NIO
、Netty
框架等。自定义协议:
- 网络传输需要制定好协议,一个良好的协议能提高传输的效率。
序列化:
- 网络传输肯定会涉及到序列化,常见的序列化有
Json
、Protostuff
、Kyro
等。负载均衡:
- 当请求调用量大的时候,需要增加服务端的数量,一旦增加,就会涉及到符合选择服务的问题,这就是负载均衡。
- 常见的负载均衡策略有:轮询、随机、加权轮询、加权随机、一致性哈希等等。
集群容错:
- 当请求服务异常的时候,我们是应该直接报错呢?还是重试?还是请求其他服务?这个就是集群容错策略啦。
当调用本地的一个服务类的某个方法时,实际上这个服务类已经是一个代理类了。
- 调用这个类的某个方法,实际上代理方法中可以加入很多额外的逻辑。
比如构造
HTTP
请求、构造TCP
请求等等,最终穿过网络调用到真正的服务提供方的同名方法。
序列化和反序列化功能会在代理中进行(编解码)。
封装的网络请求既有可能是
HTTP
请求,也有可能是Sockets
请求,比如有很多RPC
功能都使用Netty
作为通讯层。
网络通信协议协议
用来规范传输的数据的,它是一个应用层协议,比如
HTTP
,而不是传输层的协议,比如TCP 、UDP
。比如
GRPC
框架中用的协议是HTTP2
,Dubbo
中可以选择多种协议,比如Hession
、HTTP
等。
序列化机制
数据要想在网络中传输,必须是二进制的形式。
在远程调用里,像调用本地方法那样调用,使用的参数都是和当前项目语言一致的参数类型。
比如
Java
中的String
、List
、Map
等等,要把这些类型转换成二进制,需要序列化算法。