RPC

sanlanlan 2021-11-10 标签: GO 浏览:819 评论:0

什么是RPC ?

RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。


为什么使用RPC呢?

就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求


解决什么问题?
最终解决的问题:让分布式或者微服务系统中不同服务之间的调用像本地调用一样简单。


完整的 RPC 实现一般会包含有 传输协议 和 序列化协议 这两个。
而 HTTP 是一种传输协议,RPC 框架完全可以使用 HTTP 作为传输协议,也可以直接使用 TCP,使用不同的协议一般也是为了适应不同的场景。


为什么用 RPC,不用 HTTP

首先需要指正,这两个并不是并行概念。RPC 是一种设计,就是为了解决不同服务之间的调用问题,完整的 RPC 实现一般会包含有 传输协议序列化协议 这两个。

而 HTTP 是一种传输协议,RPC 框架完全可以使用 HTTP 作为传输协议,也可以直接使用 TCP,使用不同的协议一般也是为了适应不同的场景。


使用 TCP 和使用 HTTP 各有优势:

传输效率

  • TCP,通常自定义上层协议,可以让请求报文体积更小
  • HTTP:如果是基于HTTP 1.1 的协议,请求中会包含很多无用的内容

性能消耗,主要在于序列化

和反序列化的耗时

  • TCP,可以基于各种序列化框架进行,效率比较高
  • HTTP,大部分是通过 json 来实现的,字节大小和序列化耗时都要更消耗性能

跨平台

  • TCP:通常要求客户端和服务器为统一平台
  • HTTP:可以在各种异构系统上运行

总结
RPC 的 TCP 方式主要用于公司内部的服务调用,性能消耗低,传输效率高。HTTP主要用于对外的异构环境,浏览器接口调用,APP接口调用,第三方接口调用等。

RPC 原理

rpc.jpg

  • 服务消费方(client)调用以本地调用方式调用服务;
  • client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
  • client stub找到服务地址,并将消息发送到服务端;
  • server stub收到消息后进行解码;
  • server stub根据解码结果调用本地的服务;
  • 本地服务执行并将结果返回给server stub;
  • server stub将返回结果打包成消息并发送至消费方;
  • client stub接收到消息,并进行解码;
  • 服务消费方得到最终结果。

  • RPC 核心功能

    一个 RPC 的核心功能主要有 5 个部分组成,分别是:客户端、客户端 Stub、网络传输模块、服务端 Stub、服务端等。


    771365725.jpg


    下面分别介绍核心 RPC 框架的重要组成:

    • 客户端(Client):服务调用方。
    • 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
    • 服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
    • 服务端(Server):服务的真正提供者。
    • Network Service:底层传输,可以是 TCP 或 HTTP。


    完整的 RPC 框架


    在一个典型 RPC 的使用场景中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进行网络传输和序列化。


    3461264051.jpg


    1. gRPC

    它的原理是通过 IDL(Interface Definition Language)文件定义服务接口的参数和返回值类型,然后通过代码生成程序生成服务端和客户端的具体实现代码,这样在 gRPC 里,客户端应用可以像调用本地对象一样调用另一台服务器上对应的方法。


    它的主要特性包括三个方面。

    通信协议采用了 HTTP/2,因为 HTTP/2 提供了连接复用、双向流、服务器推送、请求优先级、首部压缩等机制

    IDL 使用了ProtoBuf,ProtoBuf 是由 Google 开发的一种数据序列化协议,它的压缩和传输效率极高,语法也简单

    多语言支持,能够基于多种语言自动生成对应语言的客户端和服务端的代码。



    2. Thrift

    Thrift 是一种轻量级的跨语言 RPC 通信方案,可以通过代码生成器,生成各种编程语言的 Client 端和 Server 端的 SDK 代码,这样就保证了不同语言之间可以相互通信。



    自己实现框架:

    如果想要自己实现一个 RPC,最简单的方式要实现三个技术点,分别是:

    • 服务寻址
    • 数据流的序列化和反序列化
    • 网络传输
    服务寻址


    服务寻址可以使用 Call ID 映射。

    客户端在做远程过程调用时,必须附上这个 ID。然后我们还需要在客户端和服务端分别维护一个函数和Call ID的对应表。

    当客户端需要进行远程调用时,它就查一下这个表,找出相应的 Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。


    实现方式:服务注册中心。

    要调用服务,首先你需要一个服务注册中心去查询对方服务都有哪些实例。


    序列化和反序列化

    客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。

    但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。

    这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。

    只有二进制数据才能在网络中传输,序列化和反序列化的定义是:

    • 将对象转换成二进制流的过程叫做序列化
    • 将二进制流转换成对象的过程叫做反序列化

    这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。

    网络传输

    网络传输:远程调用往往用在网络上,客户端和服务端是通过网络连接的。

    所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把 Call ID 和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。

    只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。


    所以,要实现一个 RPC 框架,只需要把以下三点实现了就基本完成了:

    • Call ID 映射:可以直接使用函数字符串,也可以使用整数 ID。映射表一般就是一个哈希表。
    • 序列化反序列化:可以自己写,也可以使用 Protobuf 或者 FlatBuffers 之类的。
    • 网络传输库:可以自己写 Socket,或者用 Asio,ZeroMQ,Netty 之类。




    简单对比 RPC 和 Restful API

    RESTful API 架构

    REST ***的几个特点为:资源、统一接口、URI 和无状态。




    RPC 和 Restful API 对比

    面对对象不同:

    • RPC 更侧重于动作。
    • REST 的主体是资源


    参考:https://www.grpc.io/docs/what-is-grpc/introduction/


    本文相关标签:

    发表评论: