这是我参与「第三届青训营 –后端场」笔记创作活动的的第五篇笔记.

  • 本篇笔记首要分红两个部分,分别是RPC结构的根本概念,以及它的分层规划。

  • 下篇笔记将会介绍RPC的要害目标和它的企业实践

话不多说,咱们敞开本篇笔记~

1.根本概念

本地函数调用

深入浅出RPC框架(上篇)| 青训营笔记

  1. 将a和b的值压栈
  2. 经过函数指针找到calculate函数,进入函数取出栈中的值2和3,将其赋予x和y。
  3. 计算x*y,并将结果存在Z。
  4. 将Z的值压栈,然后从calculate返回。
  5. 从中取出Z返回值,并赋值给result。

远端函数调用(RPC-Remote Procedure Calls)

RPC需求解决的问题:

深入浅出RPC框架(上篇)| 青训营笔记
1. 函数映射

Q:咱们怎么告知支付服务咱们要调用付款这个函数,而不是退款或者充值呢?

在本地调用中,函数体是直接经过函数指针来指定的,咱们调用哪个办法,编译器就自动帮咱们调用它相应的函数指针。但是在长途调用中,函数指针是不可的,因为两个进程的地址空间是彻底不一样的。所以函数都有自己的一个ID,在做 RPC的时分要附上这个ID,还得有个 ID 和函数的对照关系表,经过 ID找到对应的函数并执行。

2. 数据转换成字节省

Q:客户端怎么把参数值传给长途的函数呢?

在本地调用中,咱们只需求把参数压到栈里,然后让函数自己去栈里读就行。但是在长途进程调用时,客户端跟服务端是不同的进程,不能经过内存来传递参数。这时分就需求客户端把参数先转成一个字节省,传给服务端后,再把字节省转成自己能读取的格局。

  1. 网络传输 Q:长途调用往往用在网络上,怎么确保在网络上高效安稳地传输数据?

RPC概念模型

深入浅出RPC框架(上篇)| 青训营笔记

这是理论模型

一次RPC的完整进程

深入浅出RPC框架(上篇)| 青训营笔记

  • IDL (Interface description language)文件 IDL经过一种中立的办法来描绘接口,使得在不同渠道上运行的目标和用不同言语编写的程序能够彼此通信。(约好调用标准)

相比本地函数调用,长途调用的话咱们不知道对方有哪些办法,以及参数长什么样,所以需求有一种办法来描绘或者说声明我有哪些办法,办法的参数都是什么姿态的,这样的话咱们就能依照这个来调用,这个描绘文件便是 IDL 文件。

  • 生成代码 经过编译器工具把IDL文件转换成言语对应的静态库。(详细调用的时分用户代码需求依靠生成代码,所以能够把用户代码和生成代码看做一个全体)

  • 编解码 从内存中表明到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化。

  • 通信协议 标准了数据在网络中的传输内容和格局。除有必要的恳求/呼应数据外,一般还会包括额外的元数据。

  • 网络传输 一般基于老练的网络库走TCP/UDP传输。

服务两边是经过约好的标准进行长途调用,两边都依靠同一份IDL文件,需求经过工具来生成对应的生成文件,详细调用的时分用户代码需求依靠生成代码,所以能够把用户代码和生成代码看做一个全体。
编码只是解决了跨言语的数据交换格局,但是怎么通讯呢?需求制定通讯协议,以及数据怎么传输?我的网络模型怎么呢?那便是这儿的 transfer 要做的工作。

RPC的好处

  • 单一职责,有利于分工协作和运维开发
  • 可扩展性强,资源运用率高
  • 毛病阻隔,服务的全体可靠性更高

RPC带来的问题

  • 服务宕机,对方应该怎么处理?
  • 在调用进程中网络反常,怎么确保消息的可达性?
  • 恳求量剧增导致服务无法及时处理,有哪些应对办法?

小结

  • 本地函数调用和RPC调用的差异:函数映射、数据转成字节省、网络传输
  • RPC的概念模型: User、 User-Stub、 RPC- Runtime、Server Stub、Server
  • 一次PRC的完整进程,并讲解了RPC的根本概念界说
  • RPC带来好处的同时也带来了不少新的问题,将由RPC结构来解决

2.分层规划

编解码层-以Apache Thrift为例

深入浅出RPC框架(上篇)| 青训营笔记

  • 生成代码

依靠同一份IDL文件生成不同言语的代码。

  • 数据格局
  1. 言语特定的格局

许多编程言语都内建了将内存目标编码为字节序列的支撑,例如Java有java.io.Serializable (这种编码形式好处是十分方便,能够用很少的额外代码完成内存目标的保存与康复,这类编码一般与特定的编程言语深度绑定,其他言语很难读取这种数据。假如以这类编码存储或传输数据,那你就和这门言语绑死在一起了。安全和兼容性也是问题)

  1. 文本格局

JSON、XML、CSV等文本格局,具有人类可读性 (文本格局具有人类可读性,数字的编码多有歧义之处,比方XML和CSV不能区别数字和字符串,JSON尽管区别字符串和数字,但是不区别整数和浮点数,并且不能指定精度,处理很多数据时,这个问题更严重了;没有强制模型束缚,实际操作中往往只能选用文档办法来进行约好,这或许会给调试带来一些不便。 因为JSON在一些言语中的序列化和反序列化需求选用反射机制,所以在功能比较差)

  1. 二进制编码

具有跨言语和高功能等长处,常见有Thrift 的BinaryProtocol, Protobuf 等 (完成能够有很多种,TLV 编码 和 Varint 编码)

  • 二进制编码

**TLV编码 **

Tag:标签,能够理解为类型

Lenght:长度 Value:值,Value也能够是个TLV结构

  • 选型 兼容性

支撑自动添加新的字段,而不影响老的服务,这将进步体系的灵活度。(移动互联年代,事务体系需求的更新周期变得更快,新的需求不断涌现,而老的体系仍是需求继续维护。假如序列化协议具有杰出的可扩展性,支撑自动添加新的事务字段,而不影响老的服务,这将大大供给体系的灵活度。 )

通用性

支撑跨渠道、跨言语 (榜首、技能层面,序列化协议是否支撑跨渠道、跨言语。假如不支撑,在技能层面上的通用性就大大降低了。 第二、流行程度,序列化和反序列化需求多方参与,很少人运用的协议往往意味着昂贵的学习本钱;另一方面,流行度低的协议,往往缺乏安稳而老练的跨言语、跨渠道的公共包。)

功能

从空间和时刻两个维度来考虑,也便是编码后数据巨细和编码耗费时长。 (榜首、空间开支(Verbosity), 序列化需求在原有的数据上加上描绘字段,以为反序列化解析之用。假如序列化进程引入的额外开支过高,或许会导致过大的网络,磁盘等各方面的压力。关于海量分布式存储体系,数据量往往以TB为单位,巨大的的额外空间开支意味着昂扬的本钱。 第二、时刻开支(Complexity),复杂的序列化协议会导致较长的解析时刻,这或许会使得序列化和反序列化阶段成为整个体系的瓶颈。)

协议层

深入浅出RPC框架(上篇)| 青训营笔记

  • 概念 特别完毕符

一个特别字符作为每个协议单元完毕的标示。(过于简略,关于一个协议单元有必要要全部读入才能够进行处理,除此之外有必要要防止用户传输的数据不能同完毕符相同,不然就会出现紊乱 HTTP 协议头便是以回车(CR)加换行(LF)符号序列结尾。)

变长协议

以定长加不定长的部分组成,其间定长的部分需求描绘不定长的内容长度。(一般都是自界说协议,有 header 和 payload 组成,会以定长加不定长的部分组成,其间定长的部分需求描绘不定长的内容长度,运用比较广泛)

  • 协议结构

深入浅出RPC框架(上篇)| 青训营笔记

  • LENGTH(32bits):数据包巨细,不包括自身长度

    • HEADER MAGIC(16bits):标识版本信息,协议解析时分快速校验
    • SEQUENCE NUMBER(32bits):表明数据包的seqlD,可用于多路复用,单衔接内递增
    • HEADER SIZE(16bits):头部长度,从第14个字节开始计算一向到PAYLOAD前
    • PROTOCOL ID(unit8编码):编解码办法,取值有Binary和Compact两种。
    • TRANSFORM ID(unit8编码):紧缩办法,如zlib和snappy
    • INFO ID(unit8编码):传递一些定制的meta信息
    • PAYLOAD:消息体
  • 协议解析

深入浅出RPC框架(上篇)| 青训营笔记

网络通信层

深入浅出RPC框架(上篇)| 青训营笔记

  • Sockets API

深入浅出RPC框架(上篇)| 青训营笔记

深入浅出RPC框架(上篇)| 青训营笔记
套接字编程中的客户端有必要知道两个信息:服务器的 IP 地址,以及端口号。

socket函数创建一个套接字,bind 将一个套接字绑定到一个地址上。listen 监听进来的衔接,backlog的含义有点复杂,这儿先简略的描绘:指定挂起的衔接行列的长度,当客户端衔接的时分,服务器或许正在处理其他逻辑而未调用accept接受衔接,此时会导致这个衔接被挂起,内核维护挂起的衔接行列,backlog则指定这个行列的长度,accept函数从行列中取出衔接恳求并接纳它,然后这个衔接就从挂起行列移除。假如行列未满,客户端调用connect马上成功,假如满了或许会堵塞等候行列未满(实际上在Linux中测试并不是这样的结果,这个后面再专门来研讨)。Linux的backlog默许是128,一般情况下,咱们也指定为128即可。

connect 客户端向服务器建议衔接,accept 接纳一个衔接恳求,假如没有衔接则会一向堵塞直到有衔接进来。得到客户端的fd之后,就能够调用read, write函数和客户端通讯,读写办法和其他I/O类似

read 从fd读数据,socket默许是堵塞模式的,假如对方没有写数据,read会一向堵塞着:

write 写fd写数据,socket默许是堵塞模式的,假如对方没有写数据,write会一向堵塞着:

socket 封闭套接字,当另一端socket封闭后,这一端读写的情况:

测验去读会得到一个EOF,并返回0。

测验去写会触发一个SIGPIPE信号,并返回-1和errno=EPIPE,SIGPIPE的默许行为是停止程序,所以一般咱们应该疏忽这个信号,防止程序停止。

假如这一端不去读写,咱们或许没有办法知道对端的socket封闭了。

  • 网络库 供给易用API
    • 封装底层Socket API
    • 衔接办理和事件分发

功能

  • 协议支撑: tcp、 udp 和uds等
  • 优雅退出、反常处理等

功能

  • 应用层buffer削减copy
  • 高功能定时器、目标池等

小结

  1. RPC结构首要中心有三层:编解码层、协议层和网络通信层
  2. 二进制编解码的完成原理和选型要点
  3. 协议的一般结构, 以及结构协议解析的根本流程
  4. Socket API的调用流程,以及选型网络库时要调查的中心目标

未完待续(To Be Continue…)