摘要:本文介绍了http2协议的实现项目nghttp2的背景,诞生过程,主流服务器例如Nginx和Apache Httpd实现 http协议的不同路径。
nghttp2 项目的简介
诞生背景
简单来说,nghttp2 是一个 HTTP/2 协议的 C 语言实现库。但它的背景和诞生,与 HTTP 协议本身的演进和 Google 的实验性项目密不可分。
1. 核心背景:从 HTTP/1.1 到 HTTP/2
要理解 nghttp2,首先要明白为什么需要 HTTP/2。
-
HTTP/1.1 的瓶颈:在 nghttp2 诞生之前,HTTP/1.1 已经服务了超过 15 年。虽然它很稳定,但在现代 Web 应用面前显得力不从心:
- 队头阻塞:一个 TCP 连接上,只能按顺序处理请求。如果前一个请求很慢(例如,一个大的图片),后面的所有请求都会被阻塞,即使它们很小。
- 低效的头部传输:头部信息是纯文本,且重复发送,非常冗余。
- 并发能力差:为了绕过队头阻塞,浏览器会为同一个域名打开多个 TCP 连接(通常 6-8 个),但这增加了服务器和网络的负担。
-
SPDY 协议的出现:为了解决这些问题,Google 在 2009 年提出了 SPDY 协议。SPDY 引入了多路复用、头部压缩、服务器推送等特性,显著提升了页面加载速度。它的成功证明了新一代 HTTP 协议的可行性和巨大潜力。
-
HTTP/2 的标准化:基于 SPDY 的成功经验和社区反馈,IETF(互联网工程任务组)在 2015 年正式将 HTTP/2 标准化为 RFC 7540。HTTP/2 在很大程度上继承了 SPDY 的核心思想,并成为了其官方继任者。
2. nghttp2 项目的诞生
随着 HTTP/2 标准的制定,社区需要一个高质量、高性能、符合标准的参考实现,来推动协议的普及和采用。nghttp2 项目就是在这个背景下应运而生的。
nghttp2 项目的发起和早期开发与 日本的一家名为 Tatsuhiro Tsujikawa 的独立开发者(也是著名的 curl 和 libcurl 的核心维护者。他对网络协议有着深刻的理解。
作为 curl 的维护者,他深知 HTTP/1.1 的局限性,并且很早就意识到了 HTTP/2(以及其前身 SPDY)的重要性。为了让 curl 能够支持新一代的 HTTP 协议,他需要一个可靠、高效且符合标准的 HTTP/2 库。
与其等待别人实现,他亲自操刀,创建了 nghttp2 项目,并完成了其绝大部分的早期开发工作。他编写了核心的 C 库 libnghttp2,以及那些非常有用的命令行工具(如 nghttp 和 h2load)。
它的主要目标和定位是:
- 提供一个 C 库 (
libnghttp2):这是核心。提供一个底层、高效、可嵌入的 C 库,用于实现 HTTP/2 协议帧的组包、解包、状态机管理等。其他高级语言或应用程序可以基于这个库来构建自己的 HTTP/2 功能。比如,著名的curl项目就使用libnghttp2作为其 HTTP/2 后端之一。
libnghttp2是核心库,而nghttp2是建立在它之上的工具集和项目名称。
Tatsuhiro Tsujikawa 将 nghttp2 集成为 curl 支持 HTTP/2 的其中一个后端(也是最常用、最功能完整的一个后端)。在这个过程中,nghttp2 库本身也在 curl 的实战使用中不断得到打磨和优化。
-
提供一个命令行工具:项目提供了一系列实用的命令行工具,其中最著名的是:
nghttp:一个功能强大的 HTTP/2 客户端。可以用来测试、调试 HTTP/2 服务器,查看协议交互细节。nghttpd:一个简单的 HTTP/2 服务器。用于测试和演示。h2load:一个高性能的 HTTP/2 基准测试工具,类似于ab(Apache Bench),但专门为 HTTP/2 设计,支持多路复用和压力测试。
-
作为参考实现:在 HTTP/2 标准制定和推广初期,nghttp2 作为一个“正确性”的参考,帮助其他开发者和项目理解协议细节,确保互操作性。
项目地址: github.com/nghttp2/ngh…
3. 项目特点与影响力
- 高性能:nghttp2 从一开始就注重性能,其代码经过高度优化,能够处理高并发的 HTTP/2 连接。
- 严格遵循标准:项目致力于完全遵循 IETF 的 HTTP/2 标准(RFC 7540)和后续更新,保证了与其他合规实现的互通性。
- 对 HTTP/2 高级特性的支持:它完整支持了 HTTP/2 的所有关键特性,如:
- 多路复用:在单个 TCP 连接上同时交错传输多个请求和响应。
- 头部压缩(HPACK):使用 HPACK 算法大幅减少头部开销。
- 服务器推送:服务器可以主动向客户端推送资源。
- 流量控制:基于窗口的流量控制。
- 影响力:nghttp2 是 HTTP/2 生态系统中最核心和最重要的基础组件之一。许多知名的开源项目都直接或间接地依赖它,例如:
- curl / libcurl:最流行的命令行传输工具和网络库。
- Apache HTTP Server (httpd):通过
mod_http2模块提供 HTTP/2 支持,该模块就使用了 nghttp2 库。 - 许多其他语言(如 Python, Node.js 等)的 HTTP/2 绑定或实现也常常以 nghttp2 为基础。
总结
nghttp2 项目的背景是 HTTP/1.1 协议无法满足现代 Web 性能需求,从而催生了 HTTP/2 标准。该项目旨在为社区提供一个高性能、符合标准的 C 语言 HTTP/2 实现库和工具集,以推动 HTTP/2 的普及和应用。它成功地扮演了参考实现、性能基准和基础构建块的角色,对 HTTP/2 在整个互联网的成功部署起到了至关重要的作用。
nginx等主流服务器与nghttp2的关系
nghttp2 在生态中扮演了至关重要的角色。Nginx 使用了自己实现的 HTTP/2 协议栈,而不是直接利用 nghttp2 的库。 Apache httpd则集成了 nghttp2。
1. Nginx:自研实现
Nginx 从其 1.9.5 版本开始支持 HTTP/2,它的实现方式是 从头编写了自己的 HTTP/2 协议处理模块,名为 ngx_http_v2_module。
为什么 Nginx 选择自研?
- 架构融合与性能:Nginx 以其高性能、事件驱动的异步架构闻名。自研协议栈可以确保 HTTP/2 的处理深度集成到其核心的事件模型、连接池、内存管理机制中。这种深度集成能带来极致的性能和资源利用效率。直接使用外部库可能无法做到如此无缝的融合。
- 控制力和灵活性:自己实现意味着对代码有完全的控制权。可以更容易地修复bug、进行深度优化、并根据Nginx特有的功能(如负载均衡、缓存、反向代理)来定制HTTP/2的行为。
- 依赖最小化:Nginx 作为一个基础软件,倾向于尽可能减少外部依赖,以简化部署、增强稳定性和安全性。使用自己的实现可以避免因外部库的更新而带来潜在的兼容性问题。
所以,当你编译 Nginx 并加上 --with-http_v2_module 配置参数时,你启用的是 Nginx 团队自己编写的 HTTP/2 模块。
2. Apache httpd:利用 nghttp2
与 Nginx 形成鲜明对比的是 Apache HTTP Server (httpd)。
Apache 通过其 mod_http2 模块来提供 HTTP/2 支持。而这个模块的底层,正是使用了 nghttp2 库作为其核心协议引擎。
为什么 Apache 选择使用 nghttp2?
- 成熟度和正确性:当 Apache 开始实现 HTTP/2 时,nghttp2 已经是一个非常成熟、经过充分测试且严格符合标准的实现。直接使用这个高质量的库可以大大缩短开发时间,并确保协议的互操作性。
- 模块化架构:Apache 的模块化架构本身就鼓励集成外部的、专业的库(例如 OpenSSL for TLS)。将 HTTP/2 这种复杂的协议处理委托给一个专门的库,是符合其设计哲学的。
- 开发效率:无需重复造轮子。nghttp2 项目已经解决了协议解析、帧处理、状态机管理等所有底层难题,Apache 团队可以专注于如何将 HTTP/2 功能集成到其自身的请求处理流程中。
3. 其他软件与 nghttp2 的关系
nghttp2 的核心价值在于它是一个 库。它的主要客户并不是最终用户,而是其他软件开发者。
- curl / libcurl:最著名的网络传输工具和库。当你使用支持 HTTP/2 的 curl 时,它通常就是通过集成
libnghttp2来实现的。你可以选择在编译时将其链接进去。 - 各种编程语言的绑定:许多编程语言(如 Python, Node.js, Rust等)的 HTTP/2 客户端或服务器实现,其底层可能是对 nghttp2 C 库的封装。
- 测试和调试工具:如前面提到的,nghttp2 项目提供的
nghttp客户端和h2load压力测试工具,被广泛用于测试 所有 HTTP/2 服务器(包括 Nginx 和 Apache)的正确性和性能。
总结对比
| 软件 | HTTP/2 实现方式 | 理由 |
|---|---|---|
| Nginx | 自研 | 追求极致的性能、架构融合、控制力和最小依赖。 |
| Apache httpd | 使用 nghttp2 库 | 利用成熟方案、符合模块化哲学、提高开发效率。 |
| curl | 使用 nghttp2 库 | 作为客户端,集成一个专业、标准的库是最佳选择。 |
- Nginx 是自己实现的 HTTP/2,没有使用 nghttp2 库。
- nghttp2 并非“唯一”的实现,而是一个被广泛采用的、高质量的“参考实现”和“基础库”。
- 选择自研还是使用 nghttp2,是一个在 性能/控制力 和 开发效率/成熟度 之间的权衡。像 Nginx 这样对性能有极致追求且拥有强大底层开发能力的项目,倾向于自研;而其他许多项目则乐于使用 nghttp2 这个优秀的现成方案。