HTTP2协议-nghttp2项目的简介

93 阅读9分钟

摘要:本文介绍了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)。

它的主要目标和定位是:

  1. 提供一个 C 库 (libnghttp2):这是核心。提供一个底层、高效、可嵌入的 C 库,用于实现 HTTP/2 协议帧的组包、解包、状态机管理等。其他高级语言或应用程序可以基于这个库来构建自己的 HTTP/2 功能。比如,著名的 curl 项目就使用 libnghttp2 作为其 HTTP/2 后端之一。

libnghttp2 是核心库,而 nghttp2 是建立在它之上的工具集和项目名称

Tatsuhiro Tsujikawa 将 nghttp2 集成为 curl 支持 HTTP/2 的其中一个后端(也是最常用、最功能完整的一个后端)。在这个过程中,nghttp2 库本身也在 curl 的实战使用中不断得到打磨和优化。

  1. 提供一个命令行工具:项目提供了一系列实用的命令行工具,其中最著名的是:

    • nghttp:一个功能强大的 HTTP/2 客户端。可以用来测试、调试 HTTP/2 服务器,查看协议交互细节。
    • nghttpd:一个简单的 HTTP/2 服务器。用于测试和演示。
    • h2load:一个高性能的 HTTP/2 基准测试工具,类似于 ab(Apache Bench),但专门为 HTTP/2 设计,支持多路复用和压力测试。
  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 选择自研?

  1. 架构融合与性能:Nginx 以其高性能、事件驱动的异步架构闻名。自研协议栈可以确保 HTTP/2 的处理深度集成到其核心的事件模型、连接池、内存管理机制中。这种深度集成能带来极致的性能和资源利用效率。直接使用外部库可能无法做到如此无缝的融合。
  2. 控制力和灵活性:自己实现意味着对代码有完全的控制权。可以更容易地修复bug、进行深度优化、并根据Nginx特有的功能(如负载均衡、缓存、反向代理)来定制HTTP/2的行为。
  3. 依赖最小化: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?

  1. 成熟度和正确性:当 Apache 开始实现 HTTP/2 时,nghttp2 已经是一个非常成熟、经过充分测试且严格符合标准的实现。直接使用这个高质量的库可以大大缩短开发时间,并确保协议的互操作性。
  2. 模块化架构:Apache 的模块化架构本身就鼓励集成外部的、专业的库(例如 OpenSSL for TLS)。将 HTTP/2 这种复杂的协议处理委托给一个专门的库,是符合其设计哲学的。
  3. 开发效率:无需重复造轮子。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 这个优秀的现成方案。