内容简介:如果你有过HTTP/2的相关经验,你可能会知道HTTP/2强大的性能依靠了一些如下的特点,比如流复用、显示流依赖以及服务端推送。但是还有一个并不明显注意到但是却很重要的功能点,那就是HPACK头部压缩。这篇文章给出了设计HPACK的一些理由,以及它背后带来的带宽和延时上的收益。
如果你有过HTTP/2的相关经验,你可能会知道HTTP/2强大的性能依靠了一些如下的特点,比如流复用、显示流依赖以及服务端推送。
但是还有一个并不明显注意到但是却很重要的功能点,那就是HPACK头部压缩。
这篇文章给出了设计HPACK的一些理由,以及它背后带来的带宽和延时上的收益。
一些背景
你可能知道,常规HTTPS连接事实上是多层模型的多个连接的叠加。你通常关系的最基本的连接就是TCP连接(传输层),在它的上面你会有一个TLS连接(传输层/应用层混合),然后最后是一个HTTP连接(应用层)
多年以前,HTTP压缩是在TLS层使用gzip去处理的。header和body都会被压缩,因为TLS层不感知传输的数据类型,实际上两者都是使用DEFLATE算法进行压缩的。
然后提出了新的专门进行头部压缩的算法SPDY。尽管是为了headers特殊设计,包括使用了一个预处理字典,包括动态Huffman编码和字符串匹配,但是它依旧使用的是DEFLATE算法。
实际上DEFLATE和SPDY都有被攻击的危险,因为攻击者可以从压缩的头部里提取cookie中的授权秘钥:因为DEFLATE使用后向字符串匹配和动态Huffman编码,攻击者可以控制部分请求头部,然后通过修改请求部分然后看压缩之后大小改变多少,来逐步恢复完整cookie。
由于这种风险,大多数的边缘网络都禁用了头部压缩。直到HTTP/2的出现改变了这种窘况
HPACK
HTTP/2支持一种新的专门进行头部压缩的算法,叫做HPACK。HPACK的开发设计考虑到了被攻击的危险,因此可以安全使用。
HPACK能够防御攻击者攻击,因为它没有像DEFLATE一样使用后向字符串匹配和动态Huffman,它使用了下面这三种方法进行压缩:
- 静态字典表:由61个常规header域和一些预定义的values组成的预定义字典表。
- 动态字典表:在连接中遇到的实际header域的列表。这个字典表有大小限制,新的key进来,旧的key可能会被移除。
- Huffman编码:静态的Huffman编码可以对任何字符串进行编码:名称或者是值。这种编码特定地用在HTTP的request/response头中,ASCII码和小写字母的编码会更短。编码最短可能只有5bits长(一个字节8bits),因此最大的原长和压缩长比率为8:5(或者是37.5%的压缩率)
HPACK流
当HPACK需要把一个header编码为name:value的形式,它首先会看静态和动态字典表。如果全部的name:value都有的话,它会简单地去找字典表的对应条目。 这通常需要1byte,在大多数情况下2bytes也就足够了。整个header编码成一个byte,太赞了。
因为许多header头都是重复的,所以上面的策略有很高的成功率。 举个例子,像这种headers: authority:www.cloudflare.com 或者是一些大的cookie通常是这种情况。
当HPACK在字典表里不能匹配整个header的时候,它就会去尝试找有相同name的header。大多数常见的haeder name会在静态表里有,比如 content-encoding, cookie, etag 。剩下的一些可能会有重复的会在动态表里。比如Cloudflare会为每一个response分配 cf-ray header,而它的值是不同的,但是name是可以复用的。
如果找到了name,它就可以再次用1~2个bytes来表示,否则的话会使用其他的原生编码或者是Huffman编码(两者中取短的那个)。header中的value也是同样的原理。
我们发现单独使用Huffman编码会节省30%的header大小。
尽管HPACK不做字符串匹配,对于攻击者来说为了找到header的value,他必须猜测整个字典表条目的value,而不是像DEFLATE一样逐步匹配,但是HPACK还是有可能受到攻击。
Request Headers
HPACK为HTTP提供的收益里面,request会比response收益更大。request的headers能够更有效的进行压缩,因为在header里面有更多的重复项。比如下面是两个requests的header,用的是Chrome浏览器:
Request #1:
authority: blog. cloudflare. com
method:GET
path: /
scheme:https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
accept-encoding: gzip, deflate, sdch, br
accept-language: en-US,en;q=0.8
cookie: 297 byte cookie
upgrade-insecure-requests:1user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2853.0 Safari/537.36
我把那些使用静态字典表的可以被压缩的headers标注了红色。有3个field: method:GET, path:/ 和 scheme:https ,它们始终在静态字典表里,并且会被编码成1个byte.一些其他的field只有name会被编码为1byte: authority, accept, accept-encoding, accept-language, cookie , user-agent
所有其他的部分标记为绿色,会按照Huffman编码进行处理。
没有匹配上的headers,会插到动态字典表里为后面的request去使用
让我们看一下另外一种情况:
authority:blog.cloudflare.com
method:GET
path: /assets/images/cloudflare-sprite-small.png
scheme:https
accept: image/webp,image/,/*;q=0.8
accept-encoding: gzip, deflate, sdch, br
accept-language: en-US,en;q=0.8
cookie: 297 byte cookie
referer: blog.cloudflare.com/assets/css/…
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2853.0 Safari/537.36
这里我加上了蓝色的编码域,它们表明了那些header域匹配上了动态字典表。很明显那些域在不同的requests里面都有重复。这里面有两个域又一次出现在静态字典表里,也就是说每个域可以编码为1或者2个bytes串。一个是大概有300byte场的 cookie 头,另一个是大概130byte长的 user-agent 。把430bytes的长度压缩到仅仅4个bytes,压缩了99%。
总之多于所有的重复的request,只有两三个短字符串会编码为Huffman编码。
这个是Cloudflare在6个小时里的访问入口进来的流量的头部况
我们可以看到请求来的头部压缩了76%。因为headers占访问流量大部分,因此所有的访问流量的空间节约十分可观
我们可以看到由于HPACK压缩,整个流量数据量大小减少了53%。
关于http不同版本的区别参考这篇文章https://mp.weixin.qq.com/s/GICbiyJpINrHZ41u_4zT-A
Response Headers
对于response头部,HPACK的收益相对少一些。
Response #1:
cache-control: public, max-age=30
cf-cache-status:HIT
cf-h2-pushed: ,
cf-ray:2ded53145e0c1ffa-DFW
content-encoding: gzip
content-type: text/html; charset=utf-8
date: Wed, 07 Sep 2016 21:41:23 GMT
expires: Wed, 07 Sep 2016 21:41:53 GMT
link: < //cdn.bizible.com/scripts/bizible.js >; rel=preload; as=script, code.jquery.com/jquery-1.11… ; rel=preload; as=script
server: cloudflare-nginx
status:200
vary: Accept-Encoding
x-ghost-cache-status:From Cache
x-powered-by:Express
第一个response的大部分header头会编码为霍夫曼编码,还有一些匹配上了静态字典表。
Response #2:
cache-control: public, max-age=31536000
cf-bgj:imgq:100
cf-cache-status:HIT
cf-ray: 2ded53163e241ffa-DFW
content-type: image/png
date:Wed, 07 Sep 2016 21:41:23 GMT
expires: Thu, 07 Sep 2017 21:41:23 GMT
server:cloudflare-nginx
status:200
vary:Accept-Encoding
x-ghost-cache-status:From Cache
x-powered-by:Express
又一次看到,蓝色的部分匹配上了动态字典表,红色表明匹配上了静态字典表,绿色部分代表了Huffman编码的串。
第二个response可能匹配了全部12个headers中的7个。剩下的5个里面,有4个header的name可以匹配上,然后有6个字符串会去使用Huffman编码。
尽管有两个expires的header是几乎完全相同的,它们也仅使用Huffman编码,因为不能完全匹配上。
有越多的请求去处理,动态字典表就会越大,就会有越多的headers被匹配上,就会提高压缩率。
下面是返回的流量里的header情况。
平均的压缩率是69%。但是整个出口流量的影响并没有很大。
可能压缩情况不容易观察,但是在整个HTTP/2的出口流量里,我们还是有1.4%的节约量。虽然看起来不多,但是数据压缩量的在很多情况还是有增加的。这个数字也会因为网站处理大文件的时候受到影响。我们测量了一些网站的节约量在15%左右
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 快速提高MySQL性能的 ——10大“杀手锏”
- 为了控制 Bean 的加载我使出了这些杀手锏
- 腾讯十年运维老兵:运维团队的五个“杀手锏”
- 提高网络灵活性和效率的杀手锏—SD-WAN
- Go 结构体标签表达式 v1.0 发布,成参数校验杀手锏
- Go 结构体标签表达式 v1.0 发布,成参数校验杀手锏
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
编程原本
Alexander Stepanov、Paul McJones / 裘宗燕 / 机械工业出版社华章公司 / 2012-1-10 / 59.00元
本书提供了有关编程的一种与众不同的理解。其主旨是,实际的编程也应像其他科学和工程领域一样基于坚实的数学基础。本书展示了在实际编程语言(如C++)中实现的算法如何在最一般的数学背景中操作。例如,如何定义快速求幂算法,使之能使用任何可交换运算。使用抽象算法将能得到更高效、可靠、安全和经济的软件。 这不是一本很容易读的书,它也不是能提升你的编程技能的秘诀和技巧汇编。本书的价值是更根本性的,其终极目......一起来看看 《编程原本》 这本书的介绍吧!