HTTP 连接管理

HTTP 是现代面向服务的架构中如此重要的组成部分,以至于 Envoy 实现了大量的 HTTP 特定功能。Envoy 具有一个内置的网络级过滤器,称为 HTTP 连接管理器

此过滤器将原始字节转换为 HTTP 级别消息和事件(例如,接收到的标头、接收到的主体数据、接收到的尾部等)。

它还处理所有 HTTP 连接和请求共有的功能,例如 访问日志记录请求 ID 生成和跟踪请求/响应标头操作路由表 管理和 统计信息

提示

请参阅 HTTP 连接管理器 配置protobuf 部分以获取参考文档。

HTTP 协议

Envoy 的 HTTP 连接管理器原生支持 HTTP/1.1HTTP/2HTTP/3,包括 WebSockets

Envoy 的 HTTP 支持设计之初就旨在成为一个 HTTP/2 多路复用代理。在内部,HTTP/2 术语用于描述系统组件。例如,HTTP 请求和响应在“流”上进行。

编解码器 API 用于将不同线路协议转换为流、请求、响应等的协议无关形式。

在 HTTP/1.1 的情况下,编解码器将协议的串行/流水线功能转换为看起来像 HTTP/2 的东西,供更高级别使用。这意味着大多数代码不需要了解流是源自 HTTP/1.1、HTTP/2 还是 HTTP/3 连接。

HTTP 生命周期

请求的代理在以下流下游 HTTP 编解码器成功解码请求标头映射时开始。

代理完成和流被销毁的点取决于上游协议以及是否启用了独立的半关闭。

如果启用了独立的半关闭,并且上游协议是 HTTP/2 或 HTTP/3 协议,则流在请求和响应都完成后(即达到各自的流结束)被销毁,通过在两个方向上接收尾部或带有流结束设置的标头/主体,并且响应具有成功(2xx)状态代码。

对于 HTTP/1 上游协议或如果禁用了独立的半关闭,则在响应完成并到达其流结束时(即当接收带有流结束设置的尾部或响应标头/主体时)销毁流,即使请求尚未完成。如果请求在响应完成时不完整,则流将被重置。

请注意,当发生错误或超时,或者当对等方重置 HTTP/2 或 HTTP/3 流时,代理可能会提前停止。

HTTP 标头清理

HTTP 连接管理器执行各种 标头清理 操作,以确保安全。

路由表配置

每个 HTTP 连接管理器过滤器 都有一个关联的 路由表,它可以通过以下两种方式之一指定

  • 静态。

  • 通过 RDS API 动态。

重试插件配置

通常,在重试期间,主机选择遵循与原始请求相同的过程。重试插件可用于修改此行为,它们分为两类

主机谓词

这些谓词可用于“拒绝”主机,这将导致主机选择被重新尝试。可以指定任意数量的这些谓词,并且如果任何谓词拒绝主机,则主机将被拒绝

Envoy 支持以下内置主机谓词

PreviousHostsPredicate

这将跟踪先前尝试过的主机,并拒绝已经尝试过的主机。

OmitCanaryHostsPredicate

这将拒绝任何标记为金丝雀主机的主机。主机通过为端点的过滤器元数据中的 envoy.lb 过滤器设置 canary: true 来标记。有关更多详细信息,请参阅 LbEndpoint

OmitHostMetadataConfig

这将根据预定义的元数据匹配条件拒绝任何主机。有关更多详细信息,请参阅下面的配置示例。

优先级谓词

这些谓词可用于调整在为重试尝试选择优先级时使用的优先级负载。只能指定一个优先级谓词

Envoy 支持以下内置优先级谓词

PreviousPrioritiesConfig

这将跟踪先前尝试过的优先级,并调整优先级负载,以便在后续重试尝试中将目标指向其他优先级。

主机选择将继续进行,直到配置的谓词接受主机或可配置的 最大尝试次数 已达上限。

这些插件可以组合起来影响主机选择和优先级负载。Envoy 也可以扩展自定义重试插件,类似于添加自定义过滤器的机制。

重试配置示例

PreviousHostsPredicate

例如,要配置重试以优先考虑尚未尝试过的主机,可以使用内置的 PreviousHostsPredicate

24              routes:
25              - match:
26                  prefix: "/"
27                route:
28                  cluster: cluster_0
29                  retry_policy:
30                    retry_host_predicate:
31                    - name: envoy.retry_host_predicates.previous_hosts
32                      typed_config:
33                        "@type": type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
34                    host_selection_retry_max_attempts: 3
35
36  clusters:

这将拒绝先前尝试过的主机,最多重试主机选择 3 次。对尝试次数的限制对于处理无法找到可接受的主机(没有主机满足谓词)或不太可能找到可接受的主机(唯一合适的主机具有非常低的相对权重)的情况是必要的。

OmitHostMetadataConfig

要根据主机的元数据拒绝主机,可以使用 OmitHostMetadataConfig

24              routes:
25              - match:
26                  prefix: "/"
27                route:
28                  cluster: cluster_0
29                  retry_policy:
30                    retry_host_predicate:
31                    - name: envoy.retry_host_predicates.omit_host_metadata
32                      typed_config:
33                        "@type": type.googleapis.com/envoy.extensions.retry.host.omit_host_metadata.v3.OmitHostMetadataConfig
34                        metadata_match:
35                          filter_metadata:
36                            envoy.lb:
37                              key: value
38
39  clusters:

这将拒绝其元数据中具有匹配(键、值)的任何主机。

PreviousPrioritiesConfig

要配置重试以在重试期间尝试其他优先级,可以使用内置的 PreviousPrioritiesConfig

24              routes:
25              - match:
26                  prefix: "/"
27                route:
28                  cluster: cluster_0
29                  retry_policy:
30                    retry_priority:
31                      name: envoy.retry_priorities.previous_priorities
32                      typed_config:
33                        "@type": type.googleapis.com/envoy.extensions.retry.priority.previous_priorities.v3.PreviousPrioritiesConfig
34                        update_frequency: 2
35
36  clusters:

这将针对在后续重试尝试中尚未使用的优先级。这 update_frequency 参数决定应多久重新计算一次优先级负载。

组合重试策略

这些插件可以组合起来,这将排除先前尝试过的主机和先前尝试过的优先级。

24              routes:
25              - match:
26                  prefix: "/"
27                route:
28                  cluster: cluster_0
29                  retry_policy:
30                    retry_host_predicate:
31                    - name: envoy.retry_host_predicates.previous_hosts
32                      typed_config:
33                        "@type": type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
34                    host_selection_retry_max_attempts: 3
35                    retry_priority:
36                      name: envoy.retry_priorities.previous_priorities
37                      typed_config:
38                        "@type": type.googleapis.com/envoy.extensions.retry.priority.previous_priorities.v3.PreviousPrioritiesConfig
39                        update_frequency: 2
40
41  clusters:

内部重定向

Envoy 支持在内部处理 3xx 重定向,即捕获可配置的 3xx 重定向响应,合成一个新请求,将其发送到由新路由匹配指定的上游,并将重定向响应作为原始请求的响应返回。原始请求的标头和主体将在重定向到新位置时发送。尾部目前尚不支持。

内部重定向是通过路由配置中的 internal_redirect_policy 字段配置的。当重定向处理开启时,来自上游的任何与 redirect_response_codes 匹配的 3xx 响应将由 Envoy 处理。

如果 Envoy 配置为内部重定向 HTTP 303 并接收 HTTP 303 响应,它将以无正文 HTTP GET 的方式发送重定向,如果原始请求不是 GETHEAD 请求。否则,Envoy 将保留原始 HTTP 方法。有关更多信息,请参见 RFC 7231 第 6.4.4 节

为了成功处理重定向,它 **必须** 通过以下检查:

  1. 具有与 redirect_response_codes 中的某个匹配的响应代码,该代码可以是 302(默认值)或一组 3xx 代码(301302303307308)。

  2. 具有包含有效完整限定 URL 的 location 标头。

  3. 请求必须已由 Envoy 全部处理。

  4. 请求必须小于 per_request_buffer_limit_bytes 限制。

  5. allow_cross_scheme_redirecttrue(默认值为 false)或下游请求的方案和 location 标头的方案相同。

  6. 给定下游请求中以前处理的内部重定向的数量不超过请求或重定向请求所命中路由的 max_internal_redirects

  7. 所有 predicates 都接受目标路由。

任何失败都将导致重定向被传递到下游。

由于重定向请求可能在不同的路由之间弹跳,重定向链中的任何路由,如果…

  • 未启用内部重定向

  • 或, 具有小于或等于重定向链长度的 max_internal_redirects(当重定向链命中它时)

  • 或, 被任何 predicates 禁止

... 将导致重定向被传递到下游。

可以使用两个谓词来创建一个 DAG,该 DAG 定义了重定向链,即 previous_routes 谓词和 allow_listed_routes。具体来说,allow_listed_routes 谓词定义了 DAG 中各个节点的边,而 previous_routes 谓词定义了边的“访问”状态,因此可以避免循环(如果需要)。

第三个谓词 safe_cross_scheme 可用于防止 HTTP -> HTTPS 重定向。

一旦重定向通过了这些检查,将通过以下方式修改发送到原始上游的请求标头:

  1. x-envoy-original-url 标头中添加完整的原始请求 URL。

  2. Location 标头中的值替换 Authority/HostSchemePath 标头。

  3. response_headers_to_copy 中列出的任何标头从重定向响应复制到将在后续请求中使用的标头。

然后,修改后的请求标头将选择一个新的路由,通过一个新的过滤器链,并使用所有正常的 Envoy 请求清理操作发送到上游。

警告

请注意,HTTP 连接管理器清理(例如清除不受信任的标头)只应用一次。每个路由的标头修改将应用于原始路由和第二个路由,即使它们相同,因此请仔细配置标头修改规则以避免重复不希望出现的标头值。

警告

请注意,没有下游过滤器会看到触发内部重定向的响应。如果需要在重定向响应和后续请求之间传递数据,请参见 response_headers_to_copy

示例重定向流程可能如下所示:

  1. 客户端发送 GET 请求以获取 http://foo.com/bar

  2. 上游 1 发送 302,其中包含 location: http://baz.com/eep

  3. Envoy 配置为允许在原始路由上进行重定向,并发送一个新的 GET 请求到上游 2,以使用额外的请求标头 x-envoy-original-url: http://foo.com/bar 获取 http://baz.com/eep

  4. Envoy 将 http://baz.com/eep 的响应数据代理给客户端,作为对原始请求的响应。

超时

各种可配置的超时适用于 HTTP 连接及其组成流。有关重要超时配置的概述,请参见 此常见问题解答条目

HTTP 标头映射设置

Envoy 使用一个链接列表数据结构来维护 HTTP 标头映射中标头(以及以 : 开头的伪标头)的插入顺序,当标头数量很少时,这种方式非常快。