全面解析HTTP/2:历史、特性、调试、性能

简介: 相比之前的传输协议,HTTP/2在底层方面做了很多优化。有安全、省时、简化开发、更好的适应复杂页面、提供缓存利用率等优势,阿里云早在去年发布的CDN6.0服务就已正式支持HTTP/2,访问速度最高可提升68%。今天我们从历史、特性、调试、性能四个层面来全面解析HTTP/2

写在前面

超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是互联网上应用最为广泛的一种网络协议。设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。通过 HTTP 或者 HTTPS 协议请求的资源由统一资源标识符(URI)来标识。

虽然HTTP/1.1稳定运行了十多年了,但HTTP/2来势汹汹,作为技术工程师有必要学习一下HTTP/2。今天,阿里云CDN安防技术专家金九将从历史、特性、调试、性能四个层面,来全面解析HTTP/2,希望本文可以给你带来一些启发。


一、历史

1、 HTTP/0.9
最早的原型,1991年发布,该版本极其简单,只支持 GET 方法,不支持 MIME 类型和各种 HTTP 首部等等。

2、 HTTP/1.0
1996年发布。HTTP/1.0在HTTP/0.9的基础之上添加很多方法,各种 HTTP 首部,以及对多媒体对象的处理。

除了GET命令,还引入了POST命令和HEAD命令,丰富了浏览器与服务器的互动手段。

任何格式的内容都可以发送。这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件。这为互联网的大发展奠定了基础。

HTTP请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。

可以说,HTTP/1.0是对HTTP/0.9做了革命性的改变,但HTTP/1.0依然有一些缺点,其主要缺点是每个TCP连接只能发送一个请求,发送数据完毕后连接就关闭,如果还要请求其他资源,就得再新建一个连接。虽然有些浏览器为了解决这个问题,用了一个非标准的Connection头部,但这个不是标准头部,各个浏览器和服务器实现有可能不一致,因此不是根本解决办法。

3 、HTTP/1.1
1999年正式发布。HTTP/1.1是当前主流的 HTTP 协议。完善了之前 HTTP 设计中的结构性缺陷,明确了语义,添加和删除了一些特性,支持更加复杂的的 Web 应用。

经过了十多年将近20年的发展,这个版本的HTTP协议已经很稳定了,跟HTTP/1.0相比,它新增了很多引人注目的新特性,比如Host协议头、Range分段请求、默认持久连接、压缩、分块传输编码(chunked)、缓存处理等等,至今都大量使用,而且很多软件依赖这些特性。

虽然HTTP/1.1并不像HTTP/1.0对于HTTP/0.9那样的革命性,但是也有很多增强,目前主流浏览器均默认采用HTTP/1.1。

# 4、SPDY
SPDY(发音:speedy)协议由Google开发,主要解决 HTTP/1.1 效率不高的问题,于2009年公开,到2016年初结束使命。因为HTTP/2已经被IETF标准化了,以后各种新版浏览器都会支持HTTP/2,Google认为SPDY已经没有存在的必要了,接下来的使命由HTTP/2去完成。

5、HTTP/2
HTTP/2是最新的HTTP协议,已于2015年5月份正式发布, Chrome、 IE11、Safari以及Firefox 等主流浏览器已经支持 HTTP/2协议。

注意是HTTP/2而不是HTTP/2.0,这是因为IETF(Internet Engineering Task Force,互联网工程任务组)认为HTTP/2已经很成熟了,没有必要再发布子版本了,以后要是有重大改动就直接发布HTTP/3。

其实,HTTP/2的前身是SPDY,甚至它俩的目标、原理和基本实现都差不多。IETF组委会中有很多Google工程师,将SPDY推动成为标准也就不足为奇了。

HTTP/2不仅优化了性能而且兼容了HTTP/1.1的语义,其几大特性与SPDY差不多,与HTTP/1.1有巨大区别,比如它不是文本协议而是二进制协议,而且HTTP头部采用HPACK进行压缩,支持多路复用、服务器推送等等。


二、特性

1、二进制协议

HTTP/2 采用二进制格式传输数据,而非HTTP/1.x的文本格式。消息头和消息体均采用二进制格式,并称之为”帧“(Frame)。Frame二进制基本格式如下(摘自rfc7540#section-4.1):

Length (24)
Type (8) Flags (8)
R Stream Identifier (31)

+=+=============================================================+

之所以说是基本格式,是因为所有HTTP/2 Frame都是由该基本格式来封装,类似于TCP头,目前有10个Frame,由Type字段来区分,各个Frame都有自己的二进制格式,都封装Frame Payload中。

其中有两个重要的Frame:Headers Frame(Type=0x1)和Data Frame(Type=0x0),分别对应HTTP/1.1中的消息头(Header)和消息体(Body),由此可见语义并没有太大变化,而是文本格式变成二进制的Frame。二者的转换和关系如下图(摘自 《High Performance Browser Networking》):

_1

此外,HTTP/2中还有流(Stream)和消息(Message)的概念,通过Stream Identifier(即流ID)字段来标识,流ID一样的是同一个流,流中包含消息,这个消息对应HTTP/1.x的请求消息(Request Message)或者响应消息(Response Message),消息是通过帧(Frame)来传输的,响应消息比较大,可能由多个Data Frame来传输。HTTP/2中流、消息和帧的对应关系如下图(摘自 《High Performance Browser Networking》):

2

2、头部压缩

HTTP/1.x 每次请求和响应,都会携带大量冗余消息头信息,比如Cookie和User Agent,基本一样的内容,每次请求浏览器都会默认携带,这会浪费很多带宽资源,也影响了速度。这是因为HTTP是无状态协议,每次请求都必须附上所有信息,从而导致了每次请求都带上大量重复的消息头。

为此,HTTP/2做了优化,对消息头采用HPACK格式进行压缩传输,并对消息头建立索引表,相同的消息头只发送索引号,从而提高效率和速度。但付出的代价是客户端和服务器均维护一个索引表,在如今内存不值钱的时代,这点空间换取时间还是非常值得的。

关于HPACK请参考RFC7541

3、多路复用

多路复用是指在一个TCP连接里,客户端和服务器都可以同时发送多个请求或者响应,对HTTP/1.x来说各个请求和响应都是有严格的次序要求,而在HTTP/2中,不用按照次序一一对应,而且并发的多个请求或者响应中任何一个请求阻塞了不会影响其他的请求或者响应,这样就避免了“队头堵塞”。如下图(摘自 《High Performance Browser Networking》):
3

4、服务器推送

服务器推送(Server Push)是指在HTTP/2中服务器未经请求可以主动给客户端推送资源。例如服务端可以主动把 图片、JS 和 CSS 文件推送给浏览器,而不需要浏览器解析HTML后再发送这些请求。当浏览器解析HTML后这些需要的资源都已经在浏览器里了,大大提高了网页加载的速度。如下图(摘自 《High Performance Browser Networking》):

4

浏览器发起请求page.html这个页面,这个页面中引用了script.js和style.css,服务器在响应page.html后顺便推送了script.js和style.css这两个文件,这样浏览器解析完page.html后发现引用的script.js和style.css已经在本地了,不需要再发送请求了,这样就节省了两次请求和这两次请求所花的网络时间,大大提高了网络性能和用户体验。

5、安全

HTTP的安全是由SSL/TLS来保障,也就是HTTPS,其实HTTP/2并不强制要求依赖SSL/TLS,但是,当前主流浏览器均只支持基于SSL/TLS的HTTP/2,况且在网络劫持日益猖獗的互联网环境下,HTTPS将是未来的趋势,HTTP/2基于HTTPS也是未来的趋势,而各大主流浏览器在实现HTTP/2之初均只支持SSL/TLS的HTTP/2,可见安全也是HTTP/2的重要特性之一。


三、调试

从原理和目标上看HTTP/2和SPDY差不多,从Nginx官方代码上看HTTP/2和SPDY的实现也差不多。Nginx官方代码中已经删除了spdy模块的代码,取而代之的是http2模块(ngx_http_v2_module)。

1、启用

1.1、在编译参数中加入http2模块(默认已经有ssl模块了):

# git clone https://github.com/alibaba/tengine.git
# cd tengine
# ./configure --prefix=/opt/tengine --with-http_v2_module
# make
# make install

1.2、生成测试证书和私钥

# cd /etc/pki/CA/
# touch index.txt serial
# echo 01 > serial
# openssl genrsa -out private/cakey.pem 2048
# openssl req -new -x509 -key private/cakey.pem -out cacert.pem
# cd /opt/tengine/conf
# openssl genrsa -out tengine.key 2048
# openssl req -new -key tengine.key -out tengine.csr
...
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:ZJ
Locality Name (eg, city) []:HZ
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Aliyun
Organizational Unit Name (eg, section) []:CDN
Common Name (e.g. server FQDN or YOUR name) []:www.tengine.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
...
# openssl x509 -req -in tengine.csr -CA /etc/pki/CA/cacert.pem -CAkey /etc/pki/CA/private/cakey.pem -CAcreateserial -out tengine.crt

1.3、配置http2

server {
      listen       443 ssl http2; 
      server_name  www.tengine.com;
      default_type  text/plain;
      ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
      ssl_certificate     tengine.crt;
      ssl_certificate_key tengine.key;
      ssl_ciphers         EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:EECDH+AES256:EECDH+3DES:RSA+3DESi:RC4-SHA:ALL:!MD5:!aNULL:!EXP:!LOW:!SSLV2:!NULL:!ECDHE-RSA-AES128-GCM-SHA256;
      ssl_prefer_server_ciphers  on;

      location / {
          return 200 "http2 is ok";
      }
  }

1.4、启动tengine即可:

# /opt/tengine/sbin/nginx -c /opt/tengine/conf/nginx.conf
1.5、测试
先绑定/etc/hosts:
127.0.0.1 www.tengine.com
用nghttp工具测试:
jinjiu@j9mac ~/work/pcap$ nghttp 'https://www.tengine.com/' -v
[  0.019] Connected
[  0.043][NPN] server offers:
          * h2
          * http/1.1
The negotiated protocol: h2
[  0.064] recv SETTINGS frame <length=18, flags=0x00, stream_id=0>
          (niv=3)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):2147483647]
          [SETTINGS_MAX_FRAME_SIZE(0x05):16777215]
[  0.064] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
          (window_size_increment=2147418112)
[  0.064] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
          (niv=2)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[  0.064] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
          ; ACK
          (niv=0)
[  0.064] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
          (dep_stream_id=0, weight=201, exclusive=0)
[  0.064] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
          (dep_stream_id=0, weight=101, exclusive=0)
[  0.077] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
          (dep_stream_id=0, weight=1, exclusive=0)
[  0.077] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
          (dep_stream_id=7, weight=1, exclusive=0)
[  0.077] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
          (dep_stream_id=3, weight=1, exclusive=0)
[  0.077] send HEADERS frame <length=39, flags=0x25, stream_id=13>
          ; END_STREAM | END_HEADERS | PRIORITY
          (padlen=0, dep_stream_id=11, weight=16, exclusive=0)
          ; Open new stream
          :method: GET
          :path: /
          :scheme: https
          :authority: www.tengine.com
          accept: */*
          accept-encoding: gzip, deflate
          user-agent: nghttp2/1.9.2
[  0.087] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
          ; ACK
          (niv=0)
[  0.087] recv (stream_id=13) :status: 200
[  0.087] recv (stream_id=13) server: Tengine/2.2.0
[  0.087] recv (stream_id=13) date: Mon, 26 Sep 2016 03:00:01 GMT
[  0.087] recv (stream_id=13) content-type: text/plain
[  0.087] recv (stream_id=13) content-length: 11
[  0.087] recv HEADERS frame <length=63, flags=0x04, stream_id=13>
          ; END_HEADERS
          (padlen=0)
          ; First response header
http2 is ok[  0.087] recv DATA frame <length=11, flags=0x01, stream_id=13>
          ; END_STREAM
[  0.087] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
          (last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])

用chrome浏览器测试:
5

2、抓包分析

从抓包来学习HTTP/2格式是最好的办法,但HTTP/2又是基于https的,也就是加密的,直接抓包看到的是密文,没有意义,还好Wireshark提供解密https流量的办法可以比较方便地调试HTTP/2。

2.1、先导出系统变量$SSLKEYLOGFILE,以OSX系统为例

#bash
echo "\nexport SSLKEYLOGFILE=~/ssl_debug/ssl_pms.log" >> ~/.bash_profile && . ~/.bash_profile

2.2、打开Chrome或者Firefox

#chrome
open /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome 
#firefox
open /Applications/Firefox.app/Contents/MacOS/firefox

用打开的Chrome或者Firefox浏览器打开https网站,比如:https://www.taobao.com
然后看看文件~/ssl_debug/ssl_pms.log有没有内容,有内容就可以用Wireshark解密https数据了。

2.3、Wireshark设置

Wireshark->Perferences...->Protocols->SSL

启动抓包:
6

7

可见已经能得到HTTP/2的明文数据了。篇幅所限,在此不展开具体细节了,更多HTTP/2二进制协议细节请参考RFC7540


四、性能

测试机器配置:cache1.cn1, 115.238.23.13, 16核Intel(R) Xeon(R) CPU L5630 @ 2.13GHz,48G内存,万兆网卡
测试工具:h2load
测试结果:

8

9


结论

1、无论是否keepalive,HTTP/2与SPDY/3.1性能相当,HTTP/2略优。
2、在size为1k、2k、4k测试结果中保持较低RT情况下QPS也较高,CPU没有达到瓶颈,加大压测客户端数量后QPS有所提高,但RT变大,5xx也变多(这部分数据没有给出,是测试时记录的现象)。
在size为16k、32k、64k、128k、256k的测试结果中CPU达到瓶颈,随着size变大,QPS降低,RT变高,CPU性能消耗较多的函数是gcm_ghash_clmul。
在size为512k时网卡达到瓶颈,CPU没有达到瓶颈。
3、在开启keepalive的情况下,HTTP/1.1的性能与HTTP/2的性能差距不是很大。但关闭keepalive时HTTP/2的性能比HTTP/1.1更好。


写在最后

相比之前的传输协议,HTTP/2在底层方面做了很多优化。有安全、省时、简化开发、更好的适应复杂页面、提供缓存利用率等显著的优势,各大公司也已经纷纷开始使用HTTP/2协议了。阿里云早在去年发布的CDN6.0服务就已正式支持HTTP/2,访问速度最高可提升68%。不知不觉中,一个更安全、更可靠、更高速的时代已经悄然而至。

目录
相关文章
|
27天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
38 3
|
29天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
缓存 JavaScript 前端开发
Vue3与Vue2生命周期对比:新特性解析与差异探讨
Vue3与Vue2生命周期对比:新特性解析与差异探讨
86 2
|
10天前
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
25 7
C# 9.0 新特性解析
|
4天前
|
网络协议 网络安全 网络虚拟化
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算。通过这些术语的详细解释,帮助读者更好地理解和应用网络技术,应对数字化时代的挑战和机遇。
27 3
|
9天前
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
20 2
|
11天前
|
PHP 开发者
PHP 7新特性深度解析及其最佳实践
【10月更文挑战第31天】本文将深入探讨PHP 7带来的革新,从性能提升到语法改进,再到错误处理机制的变革。我们将通过实际代码示例,展示如何高效利用这些新特性来编写更加健壮和高效的PHP应用。无论你是PHP新手还是资深开发者,这篇文章都将为你打开一扇窗,让你看到PHP 7的强大之处。
|
12天前
|
安全 编译器 PHP
PHP 8新特性解析与实践应用####
————探索PHP 8的创新功能及其在现代Web开发中的实际应用
|
15天前
|
Kubernetes Cloud Native 调度
云原生批量任务编排引擎Argo Workflows发布3.6,一文解析关键新特性
Argo Workflows是CNCF毕业项目,最受欢迎的云原生工作流引擎,专为Kubernetes上编排批量任务而设计,本文主要对最新发布的Argo Workflows 3.6版本的关键新特性做一个深入的解析。
|
20天前
|
算法 网络安全 数据安全/隐私保护
HTTPS的性能
【10月更文挑战第23天】HTTPS的性能
36 5

推荐镜像

更多