HTTP: HTTP/2 - High Performance Browser Networking (O'Reilly)
以下内容都是上面这篇文章的一些总结(或者说翻译hiahia)
http2是由谷歌的SPDY之上演变而来的。主要涉及的技术包括:
头部压缩,多路复用,请求优先级
http2在socket和http之间,增加了一个binary framing层(二进制分帧层)。所以不会影响Http原先定义的任何header字段,但会影响他们传输时的编码方式。
在http2,所有的http通信都被分成了更小的message和frames来进行传输,message和frame都是二进制编码。基于这一点,服务端和客户端都必须有识别二进制分帧的机制,否则他们无法进行通信。比如http1的client是没办法识别Http2的server的。但是应用层是没办法识别底层是使用http1还是http2的。所以对应用层上的应用来说是没有影响的。
Streams,Messages,and Frames
- Stream:在一个connection之上的一次双向通信,可以携带一个或多个messages。
- Message:一个Request或Response(message)会映射成一个序列的frame。
- Frame:http2中的最小沟通单位。每一个frame都包含一个frame header。这个header至少会包含这个帧属于哪个stream的标识。
他们之间的关系:
- 一个TCP connection之上,会携带很多双向的Streams(一个HttpRequest对应一个HttpResponse)。
- 每个Stream都有一个唯一的标识,和一些额外的信息,比如优先级(请求优先级)等。
- 每个Message都是一个logical Http Message,比如一个Request或是一个Response,一个message包含一个或多个frames。
- 每个frame都是通信的最小单位,一般会携带一个specific type data,比如http headers,或message payload(body?)。不同streams上的frame有可能会交错在一起,然后在最后通过stream标识符,重新组合在一起。
这个图中,一个单向的红色箭头,是一个message,两个单向的箭头(Request和Response)合在一起称为stream。一个message由多个frame组成,比如图中Response Message由Headers frame,和data frame。
Stream Prioritization
http2给每一个stream(Request/Response)都创建了一个权重(weight)的概念,权重的值在1-255之间。
- 每一个stream都有可能有自己的权重(也有可能没有权重?)
- 一个stream有可能会对另一个stream有明显的依赖关系。
以上两点,可以让客户端创建出一个stream之间的依赖树。
对于上面这个图,可以解释为:
- A和B占用资源的全部,其中A占3/4,B占1/4(这里说的资源代表带宽,内存等)。
- D是C的parent,所以,D先被分配全部资源,然后再到C被分配全部资源。
- D先被分配全部资源,C再被分配全部资源,然后A,B再按1中的比例分配资源。
- D先被分配全部资源,E,C平分资源,再到A,B按1中比例分配资源。
比如对于浏览器,由于HTML对于构建DOM很重要,而CSS都构建CSSON很重要,而DOM和CSSOM都会被JS阻塞。而剩余的images等资源,会被赋予更低的优先级。
ONE Connection Per Origin
一个Origin,一个Connection,这个可以减少资源的消耗,增加网络吞吐量,减少传输延时。
但同时也有一些由于TCP协议而产生的开销:
- TCP层级的head-of-line blocking 头部阻塞(好像是一个packet丢了,整个序列重传?)
- 禁用TCP窗口缩放,带宽延迟及会限制连接吞吐量。
- 当有一个packet丢失,TCP的拥塞窗口大小会减小,这会降低整个连接的最大吞吐量。
Less effective header compression due to distinct compression contexts
由于不同的压缩上下文,http 头部的压缩效率较低
Less effective request prioritization due to distinct TCP streams
不同的TCP stream导致request的优先级效率较低
Less effective utilization of each TCP stream and higher likelihood of congestion due to more competing flows
更多的竞争流导致TCP stream的利用率变低,以及拥塞的可能性提高。
Increased resource overhead due to more TCP flows
Flow Control 流量控制
流量控制是放置发送方一次性发送太多数据给接收方,导致接收方的接受缓存存储不下发送的数据,导致丢包。
TCP有自己的流量控制机制,但控制的不够精细。现在HTTP2也提出一套流量控制机制:
- 流量控制是有方向性的,接收方会有可能选定对每一个stream和整个connection,它所期望的window size。
- 流量控制是基于信用的,当reciever给定它的stream和connection初始window size之后,这个window size会在收到sender发送的data frame减少,或当reciver发送WINDOW_UPDATE帧之后增加。
- 流量控制是关闭不了的。当HTTP2 connection建立之后,client和server将会交换SETTINGS frame,这个frame会设置流量控制的window size。默认的window size是65536 bytes。但是reciever可以在收到任意数据后,通过WINDOW_UPDATE frame设置更大的window size。
- 流量控制是逐跳的,而不是端到端的。
HTTP2似乎将流量控制下发到了client和server,client和server可以自己去实现流量控制的机制。
比如,应用层级别的流量控制可以表现为:
先允许浏览器获取一部分关键的资源,然后将流量窗口设置为0,先让浏览器获取更高优先级的请求,然后再恢复这个stream的获取?即,比如先获取一个图片的缩略图,展示它,然后再去获取更高优先级的资源。然后等这个资源获取到之后,再继续回去获取这个图片。
Server push
http2的新增功能,服务端的push。client端可能只发送了一个请求html的Request,server端可以返回多个response,比如html,css,js的response。
Header compression 头部压缩
头部压缩主要有两个方面:
- 使用HPACK的压缩机制对头部进行压缩:对每一个传输的header fields都编码成huffman编码(哈夫曼编码),可以减少传输的大小。
- 允许client和server保持先前看到的header的值,每次传输,只会传输head fields改了的field。
Frame种类
DATA
Used to transport HTTP message bodies
HEADERS
Used to communicate header fields for a stream
PRIORITY
Used to communicate sender-advised priority of a stream
RST_STREAM
Used to signal termination of a stream
SETTINGS
Used to communicate configuration parameters for the connection
PUSH_PROMISE
Used to signal a promise to serve the referenced resource
PING
Used to measure the roundtrip time and perform "liveness" checks
GOAWAY
Used to inform the peer to stop creating streams for current connection
WINDOW_UPDATE
Used to implement flow stream and connection flow control
CONTINUATION
Used to continue a sequence of header block fragments
Frame头部
一个frame的头部,一般是固定的9 byte。
flags一般代表的是保留字段,3 byte的容量存储frame的长度,代表一个frame最多可以携带2^24 bytes。但是http2一般规定一个frame的最大长度为16KB。
type代表的意思是上面的10个type,代表这是个header frame,或是data frame或,,,type代表的意思是上面的10个type,代表这是个header frame,或是data frame或,,,
stream identifier代表这个frame从属于哪个stream。
Frame例子
这里type显示这是个 HEADER type类型的帧
这是个DATA 帧