rpc基本入门(go) | 青训营

50 阅读8分钟

RPC VS HTTP

参考 视频

首先明确就是RPC更早

本来需要联通两个端点需要

  • c-s:客户端-服务端 :其中一种常见的方式是使用RPC(Remote Procedure Call,远程过程调用)。通过RPC,客户端可以调用服务端的方法,从而实现数据传输和交互。

  • b-s:浏览器-服务器 :确实使用HTTP协议是非常常见的情况。在Web应用程序中,浏览器通过HTTP请求向服务器发送数据或请求页面,服务器则通过HTTP响应来返回所需的内容给浏览器。这是Web开发中最普遍的通信方式之一。

    当然这并不是绝对的

两者区别:

  • http
  1. 简单性和易用性:RPC可能需要一些额外的配置和复杂性,特别是在跨语言和跨平台的情况下
  2. 通用性:HTTP是一种通用协议,广泛用于Web应用程序和服务之间的通信。RESTful API等成为一种流行的方式,允许不同类型的客户端与服务器进行交互
  3. 安全性和防火墙友好:由于HTTP通常使用标准的80端口和443端口(HTTPS),它通常能够通过大多数防火墙和代理服务器,从而使得与服务器的通信更加便捷。而某些RPC协议可能使用非标准端口,可能会受到网络限制。
  • RPC:远程函数调用
  1. 性能:某些RPC框架在性能方面可能优于HTTP。RPC通常是基于二进制协议,可以更加高效地序列化和反序列化数据。这在大规模的数据传输和高并发场景中可能表现更好。
  2. 功能丰富:某些RPC框架提供了丰富的功能和特性,如服务发现、负载均衡、容错机制等,这些特性可以使得分布式系统的开发更加方便。
  3. 跨语言支持:RPC通常可以实现跨语言通信,这对于涉及多种编程语言的大型系统是至关重要的。

RPC 框架分层设计

参考 视频 文档

  1. RPC的概念模型
  2. THeader 协议
  3. 字节内部 Kitex 实践分享:这就是一个字节研发的RPC 框架

基本概念

网路的作用:可以获取到远程的服务、资源

  • 资源分享
  • 远程函数调用 = 远程服务 (基于资源分享)

RPC就相当于自己实现了一个http框架,可扩展性强,资源使用率更优

函数调用基本流程

func main(){
    //1.将a和b的值压栈
    var a =2    
    var b 3
    
    //2.通过函数指针找到calculate函数,进入函数取出栈中的值2和3,将其赋予×和y
    //5.从栈中取出Z返回值,并赋值给result
    result := calculateab)
    fmt.Printlnresult)
    return
}
​
func calculatexy int//3.计算×*y,并将结果存在Z
    zx*y 
    return z            //4.将z的值压栈,然后从calculate返回
}

远程调用

image-20230801212923579

  • 相比本地函数调用,RPC调用需要解决的问题

    • 函数映射 : 函数都有自已的一个ID,在做RPC的时候要附上这个ID,还得有个ID和函数的对照关系表,通过ID找到对应的函数并执行。
    • 数据转换成字节流 :数据传输
    • 网络传输:传输协议

概念模型

image-20230801213504490

具体的设计

img

apache具体实现

image-20230806202152373

实现流程

image-20230801213807123

接下来和http一起理解会很简单(真服了:小声)

  • 生或代码 (网路应用层: 提取接口: idl)url接口 通过编译器工具把IDL文件转换成语言对应的静态库 ,就是按照一定规则编译
  • 编码解码 (网路应用层:生成二进制 (类似生成json以便传输,这里是protobuf))json数据 从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化,二进制<->代码
  • 通信协议 (网路应用层:请求url的参数、响应的数据,就是这个东西)请求响应 规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据
  • 网络传输 (传输层:TCP报文传输)一样 通常基于成熟的网络库走TCP/UDP传输
  • 常见框架 thrift、kitex

IDL(nterface description language)文件: 描述有哪些方法、参数

  • 作用:IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序(比如客户单js、服务端java)可以相互通信,就是类似接口提供给客户端知道有哪些方法可以调用,特定的规则
  • 原理:服务双方是通过约定的规范进行远程调用,双方都依赖同一份IDL文件,需要通过工具来生成对应的生成文件,具体调用的时候,用户代码需要依赖生成代码,所以可以把用户代码和生成代码看做一个整体。
  • 简写:就是客户端和服务端一起维护一个idl,里边记录的就是方法接口,客户端就是根据idl的接口来知道 服务器的 那些方法,然后就可以访问服务端的对应的方法了
  • 一言以蔽之:http通过url访问对于的servlet、rpc通过idl来访问对于的方法,不过需要额外的生成
  • thrift的idldobbo的idl:一眼get

编解码层

生或代码+编码解码:生成代码和编解码层相互依赖,框架的编解码应当具备扩展任意编解码协议的能力

根据同一份IDL的协议,进行编码以实现,跨平台、跨语言(就比如生成exe文件:大家都可以调用)

所以使用二进制编码

image-20230801215422159

二进制编码:常见有 Thrift 的 BinaryProtocol,Protobuf,实现可以有多种形式,例如 TLV 编码 和 Varint 编码

  • TLV

    • tag: 标识符
    • length:数据长度
    • value:值

如:type、tag记录编号即可;length固定的变量长度不需要

原代码:1 :String : name = "zc"

编码:type:string(0b) tag: name(01) length:16 value: zc itemtype:复合类型

协议层

协议就是基于报文的,类似于http协议的报文

报文结构

以 Thrift 的 THeader 协议为例

img

  • LENGTH数据包大小,不包含自身
  • HEADER MAGIC:标识版本信息,协议解析时候快速校验
  • SEQUENCE NUMBER:表示数据包的seqID,可用于多路复用,单连接内递增
  • HEADER SIZE:头部长度,从第14个字节开始计算一直到PAYLOAD前
  • PROTOCOL ID:编解码方式,有Binary和Compact两种
  • TRANSFORM ID:压缩方式,如zb和snappy INFO ID:传递一些定制的meta信息PAYLOAD:消息体

多路复用:

如区分http连接的东西:IP-IP,同一个连接的不同请求就可以走同一条连接

协议解析

image-20230801220252819

网络通信层

img

  • 阻塞 IO 下,耗费一个线程去阻塞在 read(fd) 去等待用足够多的数据可读并返回。
  • 非阻塞 IO 下,不停对所有 fds 轮询 read(fd) ,如果读取到 n <= 0 则下一个循环继续轮询。

socket

比如使用socket,这样自定义网路传输的一个策略

image-20230801220639811

套接字编程中的客户端必须知道两个信息:服务器的P地址,以及端口号。 socket函数创建一个套接字,bind将一个套接字绑定到一个地址上。listen监听进来的连接

backlog:指定挂起的连接队列的长度,当客户端连接的时候,服务器可能正在处理其他逻辑而未调用accept接受连接,此时会导致这个连接被挂起,内核维护挂起的连接队列,backlog则指定这个队列的长度,accept函数从队列中取出连接请求并接收它,然后这个连接就从挂起队列移除。如果队列末满,客户端调用connect马上成功,如果满了可能会阻塞等待队列未满(实际上在Liux中测试并不是这样的结果这个后面再专门来研究)。Liux的backlog默认是128,通常情况下,我们也指 定为128即可

image-20230801220656596