Apache 模块 mod_http2

Description:支持 HTTP/2 传输层
Status:Extension
Module Identifier:http2_module
Source File:mod_http2.c
Compatibility:在版本 2.4.17 和更高版本中可用

Summary

该模块为 Apache HTTP Server 提供 HTTP/2(RFC 7540)支持。

此模块依靠libnghttp2提供核心的 http/2 引擎。

您必须通过Protocols启用 HTTP/2 才能使用本文档中描述的功能。 HTTP/2 协议不需要使用加密,因此有两种方案可用:h2(基于 TLS 的 HTTP/2)和h2c(基于 TCP 的 HTTP/2)。

两种有用的配置方案是:

HTTP/2 in a VirtualHost context (TLS only)

Protocols h2 http/1.1

允许在安全的<VirtualHost>中通过 TLS ALPN 进行 HTTP/2 协商(h2)。默认情况下,h2禁用 HTTP/2 前同步码检查(直接模式,请参见H2Direct)。

HTTP/2 in a Server context (TLS and cleartext)

Protocols h2 h2c http/1.1

允许通过 TLS ALPN 进行 HTTP/2 协商(h2),以实现安全<VirtualHost>。允许从初始 HTTP/1.1 连接或通过 HTTP/2 前导码检查(直接模式,请参阅H2Direct)升级 HTTP/2 明文协商(h2c)。

如果对协议有任何疑问,请参考官方的HTTP/2 FAQ

工作原理

HTTP/2 Dimensioning

在 Apache 服务器上启用 HTTP/2 会对资源消耗产生影响,如果站点繁忙,则可能需要仔细考虑其含义。

启用 HTTP/2 之后的第一件事是服务器进程将启动其他线程。原因是 HTTP/2 将接收到的所有请求发送给自己的* Worker *线程进行处理,收集结果并将其流式传输到 Client 端。

在当前的实现中,这些工作程序使用与您可能熟悉的 MPM 工作程序不同的线程池。这就是现在的情况,并非永远如此。 (不过,对于 2.4.x 版本,它可能永远存在.)因此,HTTP/2 工作程序或更短的 H2Workers 不会出现在mod_status中。也不会将它们计入ThreadsPerChild之类的指令。但是,如果您尚未通过H2MinWorkersH2MaxWorkers配置其他功能,则它们将ThreadsPerChild作为默认值。

要注意的另一件事是内存消耗。由于 HTTP/2 在服务器上保留更多状态来 Management 所有打开的请求,它们的优先级和它们之间的依赖关系,因此与 HTTP/1.1 处理相比,它总是需要更多的内存。有三个指令可控制 HTTP/2 连接的内存占用:H2MaxSessionStreamsH2WindowSizeH2StreamMaxMemSize

H2MaxSessionStreams限制了 Client 端可以在 HTTP/2 连接上进行的并行请求的数量。这取决于您的站点应允许多少个。默认值为 100,这足够了,除非您遇到内存问题,否则我将保持这种方式。浏览器发送的大多数请求都是没有主体的 GET,因此它们仅占用一点内存,直到开始实际处理为止。

H2WindowSize控制在 await 服务器鼓励更多请求之前,允许 Client 机作为请求的主体发送多少。或者,相反,它是服务器需要能够缓冲的请求主体数据量。这是每个请求。

最后但并非最不重要的一点,H2StreamMaxMemSize控制应缓冲多少响应数据。该请求位于 H2Worker 线程中并正在生成数据,HTTP/2 连接尝试将其发送给 Client 端。如果 Client 端读取速度不够快,连接将缓冲此数据量,然后挂起 H2Worker。

多个主机和错误的请求

许多站点将相同的 TLS 证书用于多个虚拟主机。证书具有通配符名称(例如“ * .example.org”)或带有多个备用名称。使用 HTTP/2 的浏览器将识别出这种情况,并为这些主机重新使用已经打开的连接。

尽管这对于性能而言非常重要,但要付出一定的代价:此类虚拟主机在配置方面需要格外小心。问题是您将在同一 TLS 连接上对多个主机有多个请求。面对 HTTP/2 标准,禁止重新协商。

因此,如果您有多个使用相同证书的虚拟主机,并且想对它们使用 HTTP/2,则需要确保所有虚拟主机具有完全相同的 SSL 配置。您需要相同的协议,密码和设置来进行 Client 端验证。

如果混合使用,Apache httpd 将对其进行检测,并向 Client 端返回特殊的响应代码 421 Misdirected Request。

Environment Variables

可以将该模块配置为向 SSI 和 CGI 命名空间以及自定义日志配置中提供 HTTP/2 相关信息作为附加环境变量(请参见%{VAR_NAME}e)。

Variable Name:Value Type:Description:
HTTP2flag正在使用 HTTP/2.
H2PUSHflag对此连接启用了 HTTP/2 服务器推送,并且 Client 端也支持。
H2_PUSHflagH2PUSH的备用名称
H2_PUSHEDstring为服务器推送的请求为空或PUSHED
H2_PUSHED_ONnumber触发此请求推送的 HTTP/2 流号。
H2_STREAM_IDnumber此请求的 HTTP/2 流号。
H2_STREAM_TAGstringHTTP/2 进程唯一流标识符,由连接 ID 和由-分隔的流 ID 组成。

H2CopyFiles Directive

Description:确定响应中的文件处理
Syntax:H2CopyFiles on|off
Default:H2CopyFiles off
Context:服务器配置,虚拟主机,目录,.htaccess
Status:Extension
Module:mod_http2
Compatibility:在版本 2.4.24 和更高版本中可用。

该指令影响响应中文件内容的处理方式。使用默认的off时,文件句柄从请求处理传递到主连接,并使用通常的 Apache setaside 处理来 Management 文件的生存期。

设置为on时,将在仍在处理请求的同时复制文件内容,并将缓冲的数据传递到主连接。如果第三方模块将具有不同生存期的文件注入响应中,则更好。

这样的模块的一个示例是mod_wsgi,它可以将 Python 文件句柄放入响应中。当 Python 认为处理完成时,这些文件将关闭。在完成mod_http2之前,可能还不错。

H2Direct Directive

Description:H2 直接协议交换机
Syntax:H2Direct on|off
Default:H2Direct on for h2c, off for h2 protocol
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2

该指令切换 HTTP/2 直接模式的用法。应该在<VirtualHost>部分中使用它来为该虚拟主机启用直接 HTTP/2 通信。

直接通信意味着,如果服务器在连接上接收到的第一个字节与 HTTP/2 前同步码匹配,则 HTTP/2 协议将立即切换为无需进一步协商。 RFC 7540 中针对明文(h2c)情况定义了此模式。它在标准未要求的 TLS 连接上使用。

当服务器/虚拟主机未通过Protocols启用 h2 或 h2c 时,将永远不会检查连接的 HTTP/2 前导。 H2Direct没关系。这对于使用可能无限期挂起初始读取的协议的连接(例如 NNTP)非常重要。

对于具有有关支持 h2c 的服务器的带外知识的 Client 端,直接 HTTP/2 可以使 Client 端不必执行 HTTP/1.1 升级,从而获得更好的性能,并且避免了对请求正文的升级限制。

当可以信任连接或通过其他方式保护连接时,直接 h2c 对于服务器到服务器的通信也很有吸引力。

Example

H2Direct on

H2EarlyHints Directive

Description:确定发送 103 状态码
Syntax:H2EarlyHints on|off
Default:H2EarlyHints off
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在版本 2.4.24 和更高版本中可用。

此设置控制是否将 HTTP 状态 103 临时响应转发给 Client 端。默认情况下,当前情况并非如此,因为许多 Client 仍然对意外的临时响应感到麻烦。

当设置为on时,用H2PushResource声明的 PUSH 资源将在最终响应之前触发临时 103 响应。 103 响应将带有LinkHeaders,这些 Headers 向preload提供此类资源的建议。

H2MaxSessionStreams Directive

Description:每个 HTTP/2 会话的最大活动流数。
Syntax:H2MaxSessionStreams n
Default:H2MaxSessionStreams 100
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2

该指令设置服务器允许的每个 HTTP/2 会话(例如连接)的最大活动流数。根据 RFC 7540,如果流不是idleclosed,则该流是活动的。

Example

H2MaxSessionStreams 20

H2MaxWorkerIdleSeconds Directive

Description:h2 工作人员保持空闲直到关闭的最大秒数。
Syntax:H2MaxWorkerIdleSeconds n
Default:H2MaxWorkerIdleSeconds 600
Context:server config
Status:Extension
Module:mod_http2

该指令设置了 h2 worker 可以关闭直到关闭自身的最大秒数。仅在 h2 工作人员的数量超过H2MinWorkers时发生。

Example

H2MaxWorkerIdleSeconds 20

H2MaxWorkers Directive

Description:每个子进程使用的最大工作线程数。
Syntax:H2MaxWorkers n
Context:server config
Status:Extension
Module:mod_http2

该指令设置每个子进程为 HTTP/2 处理生成的最大工作线程数。如果不使用此伪指令,则mod_http2将选择一个适合加载的mpm模块的值。

Example

H2MaxWorkers 20

H2MinWorkers Directive

Description:每个子进程使用的工作线程数最少。
Syntax:H2MinWorkers n
Context:server config
Status:Extension
Module:mod_http2

该指令设置每个子进程为 HTTP/2 处理生成的最小工作线程数。如果不使用此伪指令,则mod_http2将选择一个适合加载的mpm模块的值。

Example

H2MinWorkers 10

H2ModernTLSOnly Directive

Description:要求 HTTP/2 连接仅是“现代 TLS”
Syntax:H2ModernTLSOnly on|off
Default:H2ModernTLSOnly on
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在 2.4.18 版和更高版本中可用。

该指令在 TLS 模式(https :)下切换对 HTTP/2 连接的安全检查。可以在整个服务器范围内使用,也可以用于特定的<VirtualHost>

安全检查要求 TSL 协议至少为 TLSv1.2,并且不使用 RFC 7540 附录 A 中列出的密码。一旦新的安全要求到位,这些检查将得到扩展。

该名称源自 mozilla 的安全/服务器端 TLS定义,其中定义了“现代兼容性”。 Mozilla Firefox 和其他浏览器要求 HTTP/2 连接具有现代兼容性。作为 OpSec 中的所有内容,这是一个不断 Developing 的目标,可以预见在将来会不断 Developing。

mod_http2中进行这些检查的目的之一是对所有连接(不仅是来自浏览器的连接)强制实施此安全级别。另一个目的是防止在不满足要求的情况下将 HTTP/2 作为协议进行协商。

最终,TLS 连接的安全性由mod_ssl的服务器配置指令确定。

Example

H2ModernTLSOnly off

H2Padding Directive

Description:确定添加到有效载荷帧的填充字节的范围
Syntax:H2Padding numbits
Default:H2Padding 0
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在版本 2.4.39 和更高版本中可用。

默认值为 0 时,没有填充字节添加到任何有效负载帧,例如 HEADERS,DATA 和 PUSH_PROMISE。这是以前版本的行为。这意味着在某些条件下,网络流量的观察者可以看到 TLS 流中这些帧的长度。

当配置 1-8 的位数时,会将[0,2 ^ numbits]范围内的随机数添加到每个帧中。为模块发送回 Client 端的每个帧独立选择随机值。

尽管更多的填充字节可以更好地混淆消息长度,但它们也是额外的流量。因此,最佳数量取决于服务器承载的 Web 流量的类型。

默认值为 0,例如选择无填充,以实现最大的向后兼容性。在某些部署中,填充字节是有害的或有害的。最可能的原因是实施有故障的 Client 端。

H2Push Directive

Description:H2 服务器按键开关
Syntax:H2Push on|off
Default:H2Push on
Context:服务器配置,虚拟主机,目录,.htaccess
Status:Extension
Module:mod_http2
Compatibility:在 2.4.18 版和更高版本中可用。

此伪指令切换 HTTP/2 服务器推送协议功能的用法。

HTTP/2 协议允许服务器在请求特定资源时将其他资源推送到 Client 端。如果这些资源以某种方式连接并且可以期望 Client 端仍然要求它,这将很有帮助。这样,推送就节省了 Client 端请求资源本身所花费的时间。另一方面,推送 Client 端不再需要或已经拥有的资源会浪费带宽。

通过检查响应的LinkHeaders 来检测服务器推送(有关规范,请参见 https://tools.ietf.org/html/rfc5988)。当这样指定的链接具有rel=preload属性时,它将被视为要推送的资源。

响应中的链接头可以由应用程序设置,也可以通过H2PushResource或使用mod_headers配置为:

mod_headers example

<Location /index.html>
    Header add Link "</css/site.css>;rel=preload"
    Header add Link "</images/logo.jpg>;rel=preload"
</Location>

如示例所示,可以将多个链接头添加到响应中,从而导致触发多次推送。该模块中没有检查,以避免将同一资源两次或多次推送到一个 Client 端。小心使用。

默认情况下,启用 HTTP/2 服务器推送。在服务器或虚拟主机上,您可以为与主机的任何连接启用/禁用此功能。此外,您可以禁用目录/位置中的一组资源的 PUSH。这控制哪些资源可能导致“推”,而不控制哪些资源可能通过“推”发送。

Example

H2Push off

最后但并非最不重要的一点是,只有在 Client 表示愿意接受推送时,才会进行推送。大多数浏览器都支持,某些浏览器(如 Safari 9)却不支持。同样,推送也只会发生在与原始响应具有相同“权限”的资源上。

H2PushDiarySize Directive

Description:H2 服务器推送日志大小
Syntax:H2PushDiarySize n
Default:H2PushDiarySize 256
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在 2.4.19 及更高版本中可用。

该指令切换每个 HTTP/2 连接记住的最大 HTTP/2 服务器推送次数。可以在<VirtualHost>部分中使用它来影响到该虚拟主机的所有连接的数量。

推送日志记录了推送资源(其 URL)的摘要(当前使用 64 位数字),以避免在同一连接上重复推送。这些值不会保持不变,因此打开新连接的 Client 端将再次经历已知的推送。有正在进行的工作使 Client 端能够公开其已经拥有的资源的摘要,因此日记可以由 Client 端在每个连接设置上初始化。

如果达到最大大小,则较新的条目将替换最旧的条目。日记条目使用 8 个字节,让具有 256 个条目的默认日记消耗大约 2 KB 的内存。

大小为 0 将有效地禁用推送日记。

H2PushPriority Directive

Description:H2 服务器推送优先级
Syntax:H2PushPriority mime-type [after|before|interleaved] [weight]
Default:H2PushPriority * After 16
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在 2.4.18 版和更高版本中可用。为了产生效果,需要使用 nghttp2 库 1.5.0 或更高版本。

该指令根据响应的 Content Type 定义推送响应的优先级处理。这通常是根据服务器配置定义的,但也可能出现在虚拟主机中。

HTTP/2 服务器推送始终与 Client 端请求相关。每个这样的请求/响应对或* streams 具有依赖性和权重,共同定义了流的 priority *。

当一个流依赖另一个流时,例如 X 依赖 Y,则 Y 在获得 X 之前获得所有带宽。请注意,这并不意味着 Y 将阻止 X。如果 Y 没有要发送的数据,则 X 可以使用分配给 Y 的所有带宽。

当流具有多个从属关系时,例如 X1 和 X2 都取决于 Y,* weight *决定带宽分配。如果 X1 和 X2 具有相同的权重,则它们都将获得可用带宽的一半。如果 X1 的权重是 X2 的两倍,则 X1 的带宽是 X2 的两倍。

最终,每个流都依赖于* root *流,它获得所有可用带宽,但从不发送任何内容。因此,其所有带宽均按权重在其子级之间分配。它们要么具有数据发送带宽,要么将带宽分配给自己的孩子。等等。如果所有子级都没有要发送的数据,则根据相同规则将该带宽分配到其他地方。

该优先级系统的目的是始终利用可用带宽,同时允许将优先级和权重赋予特定的流。通常,由于所有流都是由 Client 端启动的,因此设置这些优先级的也是流。

仅当此类流导致 PUSH 时,才让服务器决定此类推送流的“初始”优先级是多少。在以下示例中,X 是 Client 端流。它取决于 Y,服务器决定将流 P1 和 P2 推入 X。

默认优先级规则为:

默认优先级规则

H2PushPriority * After 16

读为“根据权重为 16 的 Client 端流发送任何 Content Type 的推送流”。因此,P1 和 P2 将在 X 之后发送,并且由于它们具有相等的权重,因此它们之间平均共享带宽。

交错优先规则

H2PushPriority text/css Interleaved 256

读为“以与 Client 端流相同的依赖关系和权重发送任何 CSS 资源”。如果 P1 的 Content Type 为'text/css',则它将取决于 Y(X 也是如此),并且其有效权重将被计算为P1ew = Xw * (P1w / 256)。当 P1w 为 256 时,这将使有效权重与 X 的权重相同。如果 X 和 P1 都有要发送的数据,则带宽将被均等地分配给两者。

如果将 Pw 指定为 512,则推送的交错流将获得 X 的权重的两倍。使用 128 时,只有一半的权重。请注意,有效权重始终限制为 256.

优先规则之前

H2PushPriority application/json Before

这表示 Content Type 为'application/json'的任何推送流都应在 X 之前发送出去。这使 P1 依赖于 Y,X 依赖于 P1.因此,只要 P1 有要发送的数据,X 就会停止。有效权重是从 Client 端流继承的。不允许指定重量。

请注意,优先级规范的效果受到可用服务器资源的限制。如果服务器没有可用于推送流的工作程序,则仅当其他流完成后,该流的数据才可能到达。

最后但并非最不重要的一点是,此指令中使用了一些语法细节:

  • “ *”是唯一与所有其他内容匹配的特殊 Content Type。 “图像/ *”将不起作用。

  • 默认依赖项为“之后”。

  • 还有默认权重:“之后”为 16,“交错”为 256.

优先 Sequences 较短

H2PushPriority application/json 32         # an After rule
H2PushPriority image/jpeg before           # weight inherited
H2PushPriority text/css   interleaved      # weight 256 default

H2PushResource Directive

Description:声明资源以尽早推送给 Client
Syntax:H2PushResource [add] path [critical]
Context:服务器配置,虚拟主机,目录,.htaccess
Status:Extension
Module:mod_http2
Compatibility:在版本 2.4.24 和更高版本中可用。

当添加到目录/位置时,将对通过此伪指令添加的所有路径尝试 HTTP/2 PUSH。该指令可以在同一位置多次使用。

该指令比通过mod_headers添加LinkHeaders 更早地推送资源。 mod_http2在对 Client 端的103 Early Hints临时响应中宣布这些资源。这意味着不支持 PUSH 的 Client 端仍将获得早期的预加载提示。

与通过mod_headers设置Link响应头相反,此指令仅对 HTTP/2 连接有效。

通过将critical添加到这样的资源,服务器将给予处理它更多的优先级,并在可用之前在其发送来自主请求的数据之前发送其数据。

H2SerializeHeaders Directive

Description:序列化请求/响应处理开关
Syntax:H2SerializeHeaders on|off
Default:H2SerializeHeaders off
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2

该指令切换是将 HTTP/2 请求以 HTTP/1.1 格式序列化以由httpd内核处理,还是将接收到的二进制数据直接传递到request_rec

序列化会降低性能,但是在自定义过滤器/钩子需要它的情况下会提供更多的向后兼容性。

Example

H2SerializeHeaders on

H2StreamMaxMemSize Directive

Description:每个流缓冲的最大输出数据量。
Syntax:H2StreamMaxMemSize bytes
Default:H2StreamMaxMemSize 65536
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2

该伪指令设置活动流在内存中缓冲的最大输出数据字节数。不会按流分配此内存。即将完成分配时,将根据此限制进行计数。当达到限制时,流处理将冻结,并且仅在将缓冲的数据发送到 Client 端后,流处理才会 continue。

Example

H2StreamMaxMemSize 128000

H2TLSCoolDownSecs Directive

Description:在缩小写入之前,在 TLS 上配置空闲时间的秒数
Syntax:H2TLSCoolDownSecs seconds
Default:H2TLSCoolDownSecs 1
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在 2.4.18 版和更高版本中可用。

此伪指令设置 TLS 连接上的空闲时间的秒数,直到 TLS 写大小变小(~1300 字节)。可以在整个服务器范围内使用,也可以用于特定的<VirtualHost>

有关 TLS 预热的说明,请参见H2TLSWarmUpSizeH2TLSCoolDownSecs反映了这样一个事实,对于空闲的连接,连接也会随着时间的流逝而恶化(并且 TCP 流量会调整)。在几秒钟之内没有发送任何数据后,退回到预热阶段对整体性能是有益的。

在可以认为连接可靠的部署中,可以通过将该计时器设置为 0 来禁用此计时器。

以下示例将秒设置为零,从而有效地禁用任何冷却。热身的 TLS 连接保持最大记录大小。

Example

H2TLSCoolDownSecs 0

H2TLSWarmUpSize Directive

Description:在进行最大写入之前配置 TLS 连接上的字节数
Syntax:H2TLSWarmUpSize amount
Default:H2TLSWarmUpSize 1048576
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2
Compatibility:在 2.4.18 版和更高版本中可用。

此伪指令设置在 TLS 小记录(~1300 字节)中发送的字节数,直到在 https:HTTP/2 连接上进行最大大小的写入(16k)为止。可以在整个服务器范围内使用,也可以用于特定的<VirtualHost>

谷歌性能实验室的测量表明,如果初始记录大小保持在 MTU 级别以下,则 TLS 连接将达到最佳性能,以使完整记录适合 IP 数据包。

当 TCP 调整其流控制和窗口大小时,更长的 TLS 记录可能会卡在队列中或丢失并需要重新传输。对于所有分组当然都是如此。但是,TLS 需要整个记录才能对其进行解密。最后任何丢失的字节将使接收到的字节的使用停止。

成功发送足够数量的字节后,连接的 TCP 状态将稳定,并且可以使用最大 TLS 记录大小(16 KB)以获得最佳性能。

在本地访问服务器或仅通过可靠连接访问的部署中,如果将 0 禁用所有预热阶段,则可能会降低该值。

以下示例将大小设置为零,从而有效地禁用了任何预热阶段。

Example

H2TLSWarmUpSize 0

H2Upgrade Directive

Description:H2 升级协议交换机
Syntax:H2Upgrade on|off
Default:H2Upgrade on for h2c, off for h2 protocol
Context:服务器配置,虚拟主机,目录,.htaccess
Status:Extension
Module:mod_http2

该指令切换了使用 HTTP/1.1 升级方法切换到 HTTP/2 的用法。应该在<VirtualHost>部分中使用它来为该虚拟主机启用升级到 HTTP/2.

这种切换协议的方法在 HTTP/1.1 中定义,并使用“ Upgrade”Headers(因此为名称)来宣布愿意使用其他协议。这可能在 HTTP/1.1 连接的任何请求上发生。

根据 RFC 7540 的要求,默认情况下,此协议切换方法在明文(潜在的 h2c)连接上启用,而在 TLS(潜在的 h2)上禁用。

请注意,升级仅适用于不包含正文的请求。具有内容的 POST 和 PUT 将永远不会触发升级到 HTTP/2.有关升级的替代方法,请参见H2Direct

仅当通过Protocols启用 h2 或 h2c 时,此模式才有效。

Example

H2Upgrade on

H2WindowSize Directive

Description:上游数据的流窗口的大小。
Syntax:H2WindowSize bytes
Default:H2WindowSize 65535
Context:服务器配置,虚拟主机
Status:Extension
Module:mod_http2

此伪指令设置用于从 Client 端到服务器的流控制的窗口的大小,并限制服务器必须缓冲的数据量。一旦达到限制,Client 端将停止在流上发送,直到服务器宣布有更多可用空间(因为它已处理了一些数据)。

此限制仅影响请求正文,而不影响其元数据(例如 Headers)。而且,它对响应主体没有影响,因为响应主体的窗口大小由 Client 端 Management。

Example

H2WindowSize 128000