RPC 笔记(01)— RPC概念、调用流程、RPC 与 Restful API 区别

  • Post author:
  • Post category:其他




1. 基本概念


PRC

远程过程调用

Remote Procedure Call

,其就是一个节点请求另外一个节点提供的服务。当两个物理分离的子系统需要建立逻辑上的关联时,

RPC

是牵线搭桥的常见技术手段之一。除

RPC

之外,常见的多系统数据交互方案还有分布式消息队列、

HTTP

请求调用、数据库和分布式缓存等。

  • 本地过程调用:

    如果要将本地的对象进行相关操作,可以定义一个方法,然后将相关对象传入,然后对其对象进行更新,然后由函数返回更新后的函数对象。

  • 远程过程调用:

    在上述过程中,如果其定义的函数是在另外一个服务器端,并且执行的函数体也是在另外一台远程服务器上,那么这个过程就称之为远程过程调用。



2. 调用过程

其调用过程如下所示:

1

  1. 首先客户端需要告诉服务器端,需要调用的函数,然后这里的函数和进程

    ID

    存在一个映射,客户端远程调用的时候,需要查询一下函数,找到对应的

    ID

    ,然后执行对应函数的代码。
  2. 客户端需要把本地参数传递给远程函数,在本地调用的过程中,会通过把参数转换为字节码,然后再传递给服务端,最后服务端再转换为自身可以读取的格式,这是一个序列化和反序列的过程。
  3. 转换完成数据以后,在进行传输的过程一般是使用

    HTTP



    Socket

    协议进行传输。

除去

RPC

调用以外,还有

RESTful API

进行调用。

RESTful API

调用其示例图如下图所示:


2

在上图中,一个服务 A 如果访问另外一个服务器下的 B,这个过程采用的就是

RESTful API

进行数据的传输。并且两个过程的数据会进行序列化和反序列化炒作。

两种方式进行对比而言,


  • RPC

    通信代价比较低,因为

    RPC

    是直接基于

    TCP

    进行调用的,并且传输的数据都是基于

    TCP

    进行的,所以效率更高,更优。但是由于是基于

    TCP

    的所以实现起来更为的复杂,更为的难以维护。


  • RESTful API

    由于是直接基于

    HTTP

    的所以实现更为简单,维护更为容易。

  • RPC

    快,效率高,但是不够通用,就好比地方方言,

    HTTP

    通用是普通话,但是效率不够高,传输的字节内容冗余多。

  • REST

    相对更规范,更标准,更通用,简单易用,维护性和扩展性都比较好。

  • RPC+Protobuf

    采用的是

    TCP

    做传输协议,

    REST

    直接使用

    HTTP

    做应用层协议,这种区别导致

    REST

    在调用性能上会比

    RPC+Protobuf

    低。


Go

语言中常用的

API

风格是

RPC



REST

,常用的媒体类型是

JSON



XML



Protobuf

。在

Go API

开发中常用的组合是

gRPC+Protobuf



REST+JSON

其实业界普遍采用的做法是,内部系统之间调用用

RPC

,对外用

REST

,因为内部系统之间可能调用很频繁,需要

RPC

的高性能支撑。对外用

REST

更易理解,更通用些。当然以现有的服务器性能,如果两个系统间调用不是特别频繁,对性能要求不是非常高,

REST

的性能完全可以满足。


HTTP

调用其实也是一种特殊的

RPC


HTTP1.0

协议时,

HTTP

调用还只能是短链接调用,一个请求来回之后连接就会关闭。

HTTP1.1



HTTP1.0

协议的基础上进行了改进,引入了

KeepAlive

特性可以保持

HTTP

连接长时间不断开,以便在同一个连接之上进行多次连续的请求,进一步拉近了

HTTP



RPC

之间的距离。

http


HTTP

协议进化到 2.0 之后,

Google

开源了一个建立在

HTTP2.0

协议之上的通信框架直接取名为

gRPC

,也就是

Google RPC



3. 解决问题

总之,

RPC

解决掉了在分布式系统之中,服务之间调用的问题。让服务在远程调用的时候,能够像本地调用一样非常方便,并且让调用者感知不到远程调用的具体逻辑。




RPC

只是对底层通信和交互协议的一个封装,便于上层使用。



4. 调用流程

一般来说调用过程如下所示:

3

  1. 调用者,以本地调用方式发起调用。

  2. Client stub

    客户端收到调用以后,将会把被调用的方法名,参数进行打包编码成为特定的格式,包装成为能够被网络传输的消息体。

  3. Client stub

    将消息体通过网络发送给服务端。

  4. Server stub

    将会收到通过网络接收到的消息后按照相应的格式进行拆分,获取方法名称和及其调用传入的参数。
  5. 被调用者

    Server

    本地调用执行后将会把结果返回给

    Server stub


  6. Server stub

    将会将返回值打包编码成为消息,然后通过网络发送给客户端。

  7. Client stub

    收到消息以后,将会进行拆分,然后返回给

    CLient


  8. Client

    最终获得本地

    RPC

    调用结果。

RPC 传输控制

对于消息数据的传输,主要有

HTTP

传输和

TCP

传输,一般来说

RPC

使用

TCP

进行传输,因为

TCP

其要优于

HTTP

传输。



传输过程如下图所示:


6

传输的时候一般通过

Socket

接口进行传输,也有使用

HTTP

作为底层的传输的结果,但是使用

HTTP

传输的比较少。

其过程如下:


  1. Server

    发起创建套接字请求。
  2. 创建套接字后绑定相关端口
  3. 监听链接
  4. 进入接收连接状态中。

  5. Client

    端创建套接字

  6. Client

    端和

    Server

    端刚刚建立完成的

    Socket

    进行连接的建立。

  7. Server

    端进行读取,

    Client

    进行数据写。

  8. Client

    端进行数据读取,
  9. 双方交换完数据以后,关闭连接。




Server

端代码示例:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("localhost", 8080))
sock.listen(1)  # 监听客户端连接
while True:
    conn, addr = sock.accept()  # 接收一个客户端连接
    print(conn.recv(1024))
    conn.sendall(b"world")  # 将响应发送到发送缓冲 send buffer
    conn.close()

输出结果

b'hello'


Client

端代码示例:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 8080))
sock.sendall(b"hello")  # 将消息输出到发送缓冲 send buffer
print(sock.recv(1024))
sock.close()

输出结果

b'world'


问题:客户端疯狂发送请求,但是服务器不读不处理,会发生什么?

  • 如果接收和发送队列没有设置大小,服务器处理能力弱,

    tcp

    会动态调整直至耗尽整个内存;
  • 设置了大小,

    socket

    缓冲区满,那么

    socket

    会出现阻塞,不接受发送端的消息;
  • 如果发送的请求

    size

    大于发送和接收队列之和,那么会一直阻塞下去;



5. 远程调用时序图

9

  1. 本地

    RPCTest

    类,将会调用

    ServiceProducer

    在服务端注册并启动

    Server


  2. Server

    将会调用

    register



    start

    进行初始化应用。

  3. RPCTest

    将会通过

    Client

    调用本地方法。

  4. Client

    将会调用远程服务器方法

    ServiceProducer

    并传入本地阐述,将消息发送给

    Server

    端。

  5. Server

    端放过反射,压入

    ServerTask


  6. ServerTask

    将会远程执行方法。
  7. 最后调用栈,调用完成以后,将结果返回给

    Server


  8. Server

    通过网络传输信息到

    Client


  9. Client

    把结果最终返回给

    RPCTest



版权声明:本文为wohu1104原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。