理解rpc/grpc及请求协议http2

1. 理解rpc

rpc在大众的定义上称为:远程过程调用,下面举个例子给大家分析。

如:从订单服务中获取用户的信息

在单体服务下(new UserService).GetUser(uid)我们可以这样的方式调用获取,但是当服务拆分开后代码也拆分为两份,这个时候就无法如单体服务那样new的方式调度,需通过rpc进行调度。

图片

在每个微服务中会开启一个rpc服务供其他服务访问,请求方这时会创建一个rpc的客户端,然后通过这个客户端向目标服务发送rpc请求,服务端收到请求后,根据请求信息就可以调用GetUser(uid)返回结果。

图片

再来理解rpc的定义【远程调度过程】,

  • 这里的远程就是指因为系统根据服务拆分了,原本的调度过程是通过new的方式,现在要改为从当前服务器去另一台服务器中调度。
  • 那调度过程又是指什么呢?指的是rpc_client请求rpc_server的过程,而此处的过程在细节上是调度的传输协议、连接方式、序列化及数据格式等。

即该定义【RPC:远程调度过程】,就是对在微服务中服务与服务之间相互调度的方式过程的统称。

2. RPC的通信过程

了解到RPC的定义后那RPC又是如何通信的呢:我们通过如下几个问题来理解。

问题1:我们应该如何找到目标服务

通过ip和port既可以确定目标服务器和程序。

问题2:请求的目标是什么?

根据上面的例子是调用的userServer中的GetUser方法,及以用户服务中的业务方法作为目标。

问题3:调度传输的数据结构如何设计?

针对该问题可能存在的几个情况

  1. 首先需要固定一个特定格式作为rpc_client与rpc_server的通信格式标准
  2. 请求的目标服务可能存在多个方法,因此我们在请求的时候需要告服务,我们要请求的方法
  3. 请求的目标服务还需要考虑传递参数
  4. 在细节点可能因网络关系会存在消息接收延迟,可能同时接收了多个消息,因此还需考虑消息的区分问题。

因此可以约定如下格式

图片

问题4:数据用传输协议?

rpc的通信中传输协议可以用json/xml/binary等

问题5:rpc服务客户端基于什么网络协议实现?

rpc并没有固定采用特定的网络协议来实现,在目前业界中以tcp与http2协议为主实现,也可以通过http甚至是udp也是可以的。

最后我们来看看RPC的通信过程示意图:

图片

在上图中:

  1. 客户端与服务端之间会先约定统一的编码/数据格式,一般都是以服务端定义为主。
  2. 客户端在本地代码中发起调度
  3. client stub(客户端存根):实际就是对rpc请求的封装包代码,主要事情是将接收到的调度请求,进行组装为对应的数据结构/编码/并将消息通过网络发送给目标服务器
  4. server stub(服务端存根):实际就是对rpc请求的封装包代码,主要是将接收到的消息按照定义好的编码拆包,获取请求方法与参数,并根据方法名和参数进行本地调用。
  5. 服务端处理完请求,将结果通过server stub处理返回给调用的客户端。
  6. 调用的客户端中基于client stub获取到请求后解析,最终得到本次rpc调用的结果

3. 通信协议的选择

为什么RPC会大都以tcp协议为主实现呢?而不是采用http。

RPC通信采用TCP为主而不是HTTP的原因有以下几点:

  1. 效率:TCP是一种面向连接的可靠传输协议,相对于HTTP来说,TCP协议的通信效率更高。TCP在传输数据时,采用了流式传输的方式,可以保证数据的完整性和可靠性,适合于需要高效传输大量数据的场景。
  2. 传输量:RPC通常用于传输大量的数据,而HTTP协议对于传输大量数据的支持相对较弱。HTTP协议在传输数据时,会对数据进行分块传输,增加了数据的传输量和传输时间。
  3. 灵活性:RPC通信可以使用多种通信协议,包括TCP、UDP等,而HTTP协议只能使用TCP作为传输协议。RPC可以根据具体的需求选择合适的通信协议,提供更灵活的通信方式。
  4. 安全性:TCP协议支持加密和身份验证等安全机制,可以提供更高的安全性。对于需要保护数据安全的场景,RPC通信采用TCP协议可以更好地满足安全需求。

尽管HTTP协议也可以用于RPC通信,但相对于TCP来说,它的通信效率和传输量较低,不适合于需要高效传输大量数据的场景。因此,RPC通信更倾向于采用TCP作为主要的传输协议。

4. grpc协议

普通的rpc协议会带来新的问题,如

  1. rpc如何设计可以很好的支持版本的迭代发展问题
  2. 在各个项目中对于rpc的交互如何实现跨平台跨语言的问题

针对普通rpc在通讯中存在的问题google提出grpc来解决。grpc是一个高性能、开源、通用的rpc框架,基于http2协议标准设计开发,grpc使用protocol buffers作为默认的序列化和反序列化机制,支持多种开发语言。grpc还提供了一种简单的方法来精确的定义服务,并且为客户端和服务端自动生成可靠的功能库。

针对上面的问题,grpc更像是定义rpc的通讯模板或者说是基于说明书创作,在使用grpc的之前,需要先定义一个.protoc的文件,可以取名叫user.protoc或者是goods.protoc,这个文件的作用就相当于一个说明书。服务端根据该文件创建服务定义方法以及每个方法的请求与相应的信息,而客户端通过这个文件就可以知道目标服务端的方法定义、请求参数、响应参数。

图片

而在通讯中的数据传输的协议序列化与反序列化,通过grpc框架内部提供的功能库实现,而通讯之中的协议运用http2基于post请求。

5. 了解http1及问题

在讲http2之前先了解http1,因为http2是http1的扩展,所以http2的语义是、功能、http方法、状态码、url和首部字段等这些核心概念是不变的。

在浏览器中通过输入url我们就可以访问到想访问的服务器,并从中获取相关的服务器资源信息。

图片

而url指向的服务器地址,可以翻译为就是协议+域名+端口+路径的信息组成,而其中 http则就是最常用的协议,默认端口是80,通常可以省略。

HTTP 超文本传输协议是位于 TCP/IP 体系结构中的应用层协议,它是万维网的数据通信基础。

图片

  1. #### http的连接建立过程
  2. 浏览器请求,先通过dns解析域名的ip地址
  3. 通过tcp三次握手建立tcp连接
  4. 发起http请求
  5. 目标服务器接收到http请求并处理
  6. 目标服务器往浏览器发送http响应
  7. 浏览器解析并渲染页面

图片

  1. #### http1报文

http报文由请求行、首部、实体主体组成,它们之间由CRLF分隔开 注意:实体包括首部和实体主体,sp即是空格space。

图片

  1. #### http1协议的问题
  2. 低效的tcp利用
  3. 臃肿的消息首部
  4. 明文传输
  5. 传输效率低

5. 理解http2的设计

接下来看看http2,在目前的浏览器浏览器中http2的实现是基于ssl/tls,因此http2的连接建立过程和https是差不多的,而http2在http1的基础上做了如下改进。

  1. 传输的改进:二进制传输
  2. 请求头优化
  3. 多路复用
  4. 服务端可以推送
  5. 基于SSL/TLS提高安全性
  6. 传输协议的改进

http1在传输中会遇到如下问题:

  1. 一次只能处理一个请求或响应完成之前不能停止解析;
  2. 无法预判解析需要多少内存;
  3. 还需考虑个别浏览器用LF做分隔符;

http2在传输中的是采用帧进行解决,在设计思想上与分段传输及tcp包头有相似之处。

图片

在应用层和传输层之间增加一个二进制分帧层,http/2会将所有传输的信息分割为更小的消息和帧,并采用二进制格式的编码。这时原本以固有的header+body的组合报文方式就改为了一个个碎片,这些碎片数据信息可以乱序发送,而浏览器会根据流id重新组合起来,以获得实际传输的数据。

简化的理解为,http2将原本的数据包拆分成为多个小的数据包,然后在每个数据包上编个序号,基于流发送客户端。客户端在接收到这些数据包后,就可以根据固定位获取编号再组装数据。

  1. #### 请求头的优化

http协议是不带状态的,每次请求都必须要附带上所有的信息,因此客户端在请求中会收到很多重复的内容,如cookie、user agent这样就会浪费很多的资源,也影响速度。

http/2对这一点上做了优化。

  1. 是信息压缩:头信息使用gzip或compress压缩后再发送;
  2. 双方信息缓存:客户端和服务端同时维护一张头信息表,当需要更改时发送对应信的索引号即可;

图片

属性
:method GET
:scheme https
:host 360.cn
:path
accept image/jpeg
user-agent Mozilla/5.0…
  1. #### 多路复用

在连接和传输上http2也做了优化,在目前浏览器中打开一个页面总会加载很多的js/css/img等文件信息,因http1是短连接,因此每一个信息都可以视为是一个新的请求,需要与服务端建立多次tcp的连接才能获取到所有信息。

并且在收到数据信息后,还需要按照顺序一一对应,就形成了队头阻塞的情况。

图片

而http2则只需要建立一次tcp链接,通过多条流,基于帧中的标识就可以知道信息是属于哪个请求,大大的提升了http传输的性能。