1. 前言
学习了前文【Golang | gRPC】使用gRPC实现简单远程调用,后面开始了解gRPC
的流模式,分为三种:
- 客户端流
- 服务端流
- 双向流
那什么是流,在谈流的概念前,有必要先简单了解下HTTP
的连接管理经历了哪些演变。
2. HTTP连接
HTTP
连接其实就是TCP
连接及其使用规则。一旦建立了TCP连接后,客户端开始发送HTTP请求,而服务端读取请求,当读取完整条请求报文后,就会对请求进行处理,执行所请求的动作,然后将数据写回客户端。最后客户端读取数据,并对响应数据进行处理。
3. HTTP连接管理
3.1 串行连接(短连接)
如果对HTTP连接只进行简单的管理,当HTTP事务串行加载时,TCP的连接时延就会叠加起来,如下图:
3.2 并行连接
通过多条TCP连接发起并发的HTTP请求,克服单条连接的空载时间和带宽限制。但是并行连接会导致服务端打开大量连接从而消耗内存资源,引发性能问题
3.3 持久连接(长连接)
重用TCP连接,以消除连接及关闭时延。HTTP/1.1(包括HTTP/1.0的各种增强版本)允许事务处理结束后保持TCP连接处于打开状态
3.4 管道化连接
无论是串行连接还是持久连接,HTTP报文都遵循一发一收的流程,HTTP/1.1引入的管道化连接允许将多条请求放入队列,依次发送,服务端按照与请求相同的顺序回送HTTP响应(这种机制可能导致队首阻塞问题,即如果服务端的某一个请求处理耗时过久,会导致后面请求对应的响应阻塞,不能发送给客户端)
3.5 HTTP/2.0中的流(stream)
不同HTTP/1.0协议,HTTP/2.0在TCP层(或者TLS层,如果有)和HTTP层之间添加一层二进制分帧层(Binary Framing Layer),将HTTP报文分为更小的Headers帧(对应HTTP/1.0报文的起始行和首部)和DATA帧(对应HTTP/1.0报文主体部分),然后进行二进制编码发送给对端
要理解这样的二进制分帧机制,首先要理解几个概念:stream(流
)、message(消息)
、frame(帧)
stream
是一条抽象意义的双向字节流,建立在TCP连接之上。一条TCP连接可以有多条stream,每条stream可以传输一个或者多个messagemessage
可以类比HTTP/1.0协议的一条请求报文(或者响应报文),由frame组成(Headers Frame
和DATA Frame
,通过Type
字段标识)。属于同一个message的帧必须要按指定顺序发送,然后到对端按照Stream Identifier
(流标志符)进行组合,多个message的帧可以交错发送frame
是HTTP/2.0的最小通信单元,通过Flags
可以标志流的结束
如下是一个HTTP/2.0帧格式和gRPC报文格式
整个基于HTTP/2.0协议的网络通信可以简单理解为:先建立TCP连接,然后是HTTP/2.0协议的一些初始化通信(比如SETTING帧)。之后客户端将message拆分成多个frame(HEADERS帧
,DATA帧
),通过stream发送frame,服务端收到后将frame重新组合成message;反之亦然
4. HTTP/2.0与gRPC的流模式
gRPC框架中的C/S通信就是使用的HTTP/2.0协议
HTTP/2.0的优点除了降低了通信时延,另一方面使C/S通信不再局限于HTTP/1.0的一发一收模式,同时有效地解决了HTTP/1.1的管道化连接带来的响应报文队首阻塞问题(注:这里的队首阻塞仅是指HTTP层)
客户端可以发送多个message请求,服务端在获取所有的message请求后返回message响应(对应gRPC中的客户端流模式);客户端发送单个message请求,服务端接收处理后,可以返回多个message响应(对应gRPC中的服务端流模式);客户端也可以每发送一个message请求,服务端接受处理后就返回一个message响应(对应gRPC中的双向流模式)