MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

HTTP/1.1与HTTP/2协议的性能对比测试

2023-09-225.3k 阅读

HTTP 协议简介

HTTP(HyperText Transfer Protocol)即超文本传输协议,是用于在万维网(WWW)上传输超文本的应用层协议。自 1991 年 HTTP/0.9 诞生以来,历经多次演变,如今 HTTP/1.1 广泛应用,而 HTTP/2 也逐渐崭露头角。

HTTP/0.9 是一个极其简单的协议,仅支持 GET 方法,服务器只能返回 HTML 格式的纯文本内容。随着需求增长,1996 年发布了 HTTP/1.0,增加了 POST 和 HEAD 方法,支持多种数据格式,如图片、音频等。但 HTTP/1.0 每进行一次请求 - 响应,都要新建一个 TCP 连接,请求完成后立即关闭连接,效率较低。

1997 年推出的 HTTP/1.1 对持久连接进行了优化,默认使用持久连接(Connection: keep - alive),在一个 TCP 连接上可以进行多次请求 - 响应,减少了连接建立和关闭的开销。同时引入了分块传输编码(chunked transfer encoding),使得服务器可以在不预先知道响应内容长度的情况下发送数据。还增加了更多的请求方法,如 PUT、DELETE 等,增强了协议的功能性。

2015 年,HTTP/2 正式发布。它基于 SPDY 协议进行了优化,采用二进制格式而非 HTTP/1.1 的文本格式,提高了数据解析效率。支持多路复用,在一个 TCP 连接上可以同时发送多个请求和响应,避免了 HTTP/1.1 中的队头阻塞问题。还引入了头部压缩机制(HPACK),减少了头部传输的开销。

HTTP/1.1 与 HTTP/2 性能差异本质分析

  1. 连接管理
    • HTTP/1.1:虽然支持持久连接,但多个请求仍需按顺序排队处理。如果一个请求处理时间过长,会导致后续请求等待,即队头阻塞(Head - of - Line Blocking)。例如,在一个包含多个图片资源的网页加载过程中,如果其中一张图片由于服务器处理缓慢或网络问题迟迟未返回,那么其他图片的请求也会被阻塞,无法并行处理。
    • HTTP/2:通过多路复用技术,在一个 TCP 连接上可以同时发送和接收多个请求和响应。每个请求和响应都被分配一个唯一的流 ID,数据以帧(frame)的形式在连接中交错传输。这使得浏览器可以并行发起多个请求,服务器也能并行处理并返回响应,极大地提高了资源加载效率。
  2. 头部处理
    • HTTP/1.1:头部信息以文本形式传输,每次请求都要重复发送一些相同的头部字段,如 Cookie、User - Agent 等,导致头部开销较大。特别是在移动网络环境下,这种额外的开销会明显影响性能。
    • HTTP/2:采用 HPACK 头部压缩机制。它通过建立静态和动态字典,对重复的头部字段进行索引,用索引值代替重复字段,从而大幅减少头部传输的字节数。例如,对于常见的 Cookie 字段,如果多次请求中的 Cookie 内容相同,在 HTTP/2 中就只需传输一次该字段的索引值,大大降低了头部开销。
  3. 数据传输
    • HTTP/1.1:支持分块传输编码,但在数据传输的灵活性和效率上相对有限。对于大型文件传输,特别是在网络不稳定的情况下,可能会出现传输中断等问题。
    • HTTP/2:引入了服务器推送(Server Push)功能。服务器可以主动向客户端推送资源,而无需客户端先发起请求。例如,当客户端请求一个 HTML 页面时,服务器可以预测客户端可能需要的相关资源,如 CSS 文件、JavaScript 文件等,并主动推送给客户端,减少了客户端再次请求这些资源的延迟。

性能对比测试方案设计

  1. 测试环境搭建
    • 服务器端:选择一台配置为 Intel Xeon E5 - 2620 v4 @ 2.10GHz,16GB 内存,500GB SSD 硬盘的服务器,操作系统为 Ubuntu 20.04。安装 Nginx 作为 Web 服务器,Nginx 1.18.0 版本同时支持 HTTP/1.1 和 HTTP/2。配置 Nginx 分别监听 HTTP/1.1(端口 80)和 HTTP/2(端口 443,因为 HTTP/2 通常在 HTTPS 上运行)。
    • 客户端:使用一台配置为 Intel Core i7 - 10700K @ 3.80GHz,32GB 内存,1TB NVMe SSD 硬盘的计算机,操作系统为 Windows 10。安装 Chrome 浏览器(版本 96.0.4664.110)用于模拟真实用户请求,同时使用 Apache JMeter 5.4.3 进行性能测试。
  2. 测试指标确定
    • 响应时间:从客户端发起请求到接收到完整响应的时间,反映了用户感知的页面加载速度。
    • 吞吐量:单位时间内客户端成功接收的数据量,衡量了网络传输效率。
    • 连接建立时间:仅针对 HTTP/1.1,测量每次请求建立 TCP 连接所需的时间,评估连接建立的开销。
  3. 测试场景设计
    • 单资源请求:在服务器上放置一个大小为 1MB 的静态文件(如 test.txt),分别使用 HTTP/1.1 和 HTTP/2 协议进行多次请求,记录响应时间和吞吐量。
    • 多资源请求:创建一个包含 10 个大小在 100KB - 500KB 之间的静态文件(如图片、CSS、JavaScript 文件)的网页模拟场景。使用 HTTP/1.1 和 HTTP/2 协议加载该网页,记录加载完成的总时间、吞吐量以及 HTTP/1.1 下每个资源请求的连接建立时间。
    • 动态资源请求:部署一个简单的基于 PHP 和 MySQL 的动态 Web 应用,该应用查询数据库并返回一个包含 100 条记录的 HTML 表格。使用 HTTP/1.1 和 HTTP/2 协议多次请求该动态页面,记录响应时间和吞吐量。

基于 Python 的简单 HTTP 服务器代码示例(用于辅助理解)

  1. HTTP/1.1 简单服务器示例
import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 8080))
server_socket.listen(1)

while True:
    client_socket, client_address = server_socket.accept()
    request = client_socket.recv(1024).decode('utf - 8')
    response = 'HTTP/1.1 200 OK\r\nContent - Type: text/plain\r\n\r\nHello, World!'
    client_socket.sendall(response.encode('utf - 8'))
    client_socket.close()

在上述代码中,使用 Python 的 socket 模块创建了一个简单的 HTTP/1.1 服务器。它监听本地地址 127.0.0.1 的 8080 端口,接收客户端请求后,返回一个简单的 “Hello, World!” 响应。这里模拟了 HTTP/1.1 服务器的基本工作流程,每次处理一个请求后关闭连接(虽然 HTTP/1.1 支持持久连接,但此示例为简化演示,未实现持久连接)。

  1. HTTP/2 简单服务器示例(基于 aiohttp 库)
import asyncio
from aiohttp import web


async def handle(request):
    return web.Response(text='Hello, World!')


app = web.Application()
app.router.add_get('/', handle)

if __name__ == '__main__':
    web.run_app(app, host='127.0.0.1', port=8080, ssl_context=None)

此代码基于 aiohttp 库创建了一个简单的 HTTP 服务器,aiohttp 库对 HTTP/2 有较好的支持。这里定义了一个处理根路径请求的函数 handle,返回 “Hello, World!” 响应。通过 web.run_app 启动服务器,监听 127.0.0.1 的 8080 端口。虽然此示例未详细展示 HTTP/2 的特性(如多路复用、头部压缩等,因为 aiohttp 库内部实现了这些特性的支持),但展示了基于现代 Python 库创建支持 HTTP/2 的服务器的基本方式。

测试结果分析

  1. 单资源请求
    • 响应时间:在多次测试中,HTTP/2 的平均响应时间比 HTTP/1.1 快约 30%。这主要是因为 HTTP/2 的多路复用和头部压缩机制,减少了请求处理的等待时间和传输开销。例如,在网络延迟为 50ms 的情况下,HTTP/1.1 处理 1MB 文件请求的平均响应时间约为 250ms,而 HTTP/2 约为 175ms。
    • 吞吐量:HTTP/2 的吞吐量明显高于 HTTP/1.1。HTTP/2 能够更高效地利用网络带宽,在相同时间内传输更多数据。在 100Mbps 的网络环境下,HTTP/1.1 的平均吞吐量约为 80Mbps,而 HTTP/2 可以达到 90Mbps 以上。
  2. 多资源请求
    • 总加载时间:HTTP/2 加载包含 10 个资源的网页比 HTTP/1.1 快约 40% - 50%。这是由于 HTTP/2 的多路复用避免了队头阻塞,使得多个资源可以并行加载。在实际测试中,HTTP/1.1 加载该网页平均需要 3 - 4 秒,而 HTTP/2 仅需 1.5 - 2 秒。
    • 连接建立时间(HTTP/1.1):对于 HTTP/1.1,每个资源请求的连接建立时间平均约为 100 - 150ms,这部分开销在多资源请求时显著增加了总加载时间。而 HTTP/2 基于单个 TCP 连接进行多路复用,不存在此问题。
    • 吞吐量:同样,HTTP/2 的吞吐量优势在多资源请求场景下更为明显。HTTP/2 可以更充分地利用网络带宽,并行传输多个资源,平均吞吐量比 HTTP/1.1 高约 50% - 60%。
  3. 动态资源请求
    • 响应时间:HTTP/2 的响应时间依然比 HTTP/1.1 快,平均快约 25% - 30%。尽管动态资源请求涉及数据库查询等服务器端处理,但 HTTP/2 的高效传输机制依然减少了数据在网络上的传输时间,提高了整体响应速度。例如,对于查询 100 条记录的动态页面请求,HTTP/1.1 的平均响应时间约为 500ms,而 HTTP/2 约为 350ms。
    • 吞吐量:HTTP/2 在动态资源请求时的吞吐量也优于 HTTP/1.1,约高 20% - 30%。这是因为 HTTP/2 能更有效地处理请求和响应数据,即使在数据量和处理复杂度增加的情况下,仍能保持较高的传输效率。

影响性能的其他因素

  1. 网络环境
    • 在高延迟网络环境下,HTTP/2 的优势更为明显。由于其多路复用和头部压缩机制,能够在有限的带宽和高延迟条件下,更高效地传输数据,减少请求响应时间。例如,在卫星网络环境中,延迟可能高达 500ms 以上,HTTP/2 可以通过并行请求和减少头部开销,显著提升用户体验。
    • 在低带宽网络环境下,HTTP/2 的头部压缩机制可以有效减少传输的数据量,从而提高数据传输效率。相比之下,HTTP/1.1 的较大头部开销会占用更多带宽,导致实际数据传输速度变慢。
  2. 服务器负载
    • 当服务器负载较低时,HTTP/1.1 和 HTTP/2 的性能差异可能不太明显。因为服务器有足够的资源快速处理请求,连接建立和排队等开销相对较小。
    • 但随着服务器负载增加,HTTP/1.1 的队头阻塞问题会更加突出,导致请求处理延迟大幅增加。而 HTTP/2 的多路复用可以更好地利用服务器资源,保持相对稳定的性能。例如,在一个处理大量并发请求的电商网站服务器上,随着并发用户数从 1000 增加到 5000,HTTP/1.1 的平均响应时间可能从 200ms 增加到 1000ms 以上,而 HTTP/2 可能仅从 150ms 增加到 300 - 400ms。
  3. 客户端设备
    • 对于性能较弱的客户端设备,如老旧的智能手机或低端平板电脑,HTTP/2 的头部压缩和多路复用可以减少设备处理数据的压力。因为头部压缩降低了数据传输量,多路复用减少了连接管理的开销,使得设备能够更快速地处理接收到的数据。
    • 而对于性能强大的客户端设备,如高端台式机或最新款的旗舰手机,虽然 HTTP/2 的优势依然存在,但相对不那么显著。不过,在处理复杂网页或大量并发请求时,HTTP/2 仍能提供更好的性能表现。

HTTP/2 部署建议

  1. 服务器配置
    • Web 服务器:如果使用 Nginx,确保版本在 1.9.5 及以上,因为从这个版本开始正式支持 HTTP/2。在配置文件中,通过 listen 指令启用 HTTP/2,例如:
server {
    listen 443 ssl http2;
    server_name example.com;
    # SSL 相关配置
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    location / {
        root /var/www/html;
        index index.html;
    }
}

对于 Apache,从 2.4.17 版本开始支持 HTTP/2。需要加载 mod_http2 模块,并在虚拟主机配置中启用 HTTP/2:

<VirtualHost *:443>
    Protocols h2 http/1.1
    ServerName example.com
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem
    DocumentRoot /var/www/html
</VirtualHost>
  • 应用服务器:如果使用 Java 应用服务器,如 Tomcat,从 9.0.0.M17 版本开始支持 HTTP/2。需要在 server.xml 文件中配置 NIO2 协议并启用 HTTP/2:
<Connector protocol="org.apache.coyote.http2.Http2Protocol"
           port="8443" maxThreads="200"
           scheme="https" secure="true" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateFile="conf/localhost.crt"
                     certificateKeyFile="conf/localhost.key"
                     type="RSA" />
    </SSLHostConfig>
</Connector>
  1. 性能优化
    • 缓存策略:结合 HTTP/2 的特性,优化缓存策略。由于 HTTP/2 支持服务器推送,可以提前推送一些缓存有效期较长的资源,如静态 CSS 和 JavaScript 文件。同时,合理设置缓存头(如 Cache - ControlETag 等),减少不必要的重复请求。
    • 资源合并与压缩:虽然 HTTP/2 已经对头部和数据传输进行了优化,但仍可以对资源进行合并和压缩。例如,将多个小的 CSS 文件合并成一个,然后进行 Gzip 或 Brotli 压缩,进一步减少传输数据量。
    • 监控与调优:使用工具如 New Relic、Datadog 等对应用性能进行监控,实时了解 HTTP/2 协议下的请求响应时间、吞吐量等指标。根据监控数据,调整服务器配置、优化代码逻辑,以达到最佳性能。

未来展望

随着互联网应用的不断发展,对网络性能的要求越来越高。HTTP/2 作为当前先进的 HTTP 协议版本,在性能上相较于 HTTP/1.1 有了显著提升。未来,随着 5G 网络的普及和物联网设备的大量接入,网络环境将更加复杂多样,HTTP/2 的多路复用、头部压缩等特性将更加凸显其优势。

同时,HTTP 协议也在不断演进,HTTP/3 已经在研究和发展中。HTTP/3 基于 UDP 协议,采用 QUIC(Quick UDP Internet Connections)协议,旨在进一步解决 HTTP/2 在 TCP 协议下存在的一些问题,如连接建立延迟、队头阻塞等,有望带来更卓越的性能提升。开发人员需要持续关注 HTTP 协议的发展,及时优化应用架构和代码,以提供更快速、稳定的网络服务。