Envoy HTTP/3 架构与实战指南Downstream/Upstream 的 QUIC 接入、广告、监控与回退机制【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoyHTTP/3 基于 QUICUDP协议能够显著降低连接建立延迟并改善弱网环境下的传输体验。本文以 Envoy 官方架构文档 http3.rst 为核心骨架结合仓库内的示例配置与 proto 定义系统讲解 Envoy 如何开启 HTTP/3 下游downstream监听、如何通过alt-svc对外广告 HTTP/3 能力、如何在多 worker 线程下利用 BPF 提升性能、如何监控 QUIC/UDP 关键指标以及如何配置 HTTP/3 上游upstream转发包括显式与自动协议选择。读完本文你将掌握一套可复制、可落地的 Envoy HTTP/3 双向接入方案并理解其底层行为与回退机制。HTTP/3 在 Envoy 中的总体支持范围从 http3.rst 可以看到Envoy 对 HTTP/3 的支持分为两个方向Downstream下游作为入口网关接收客户端的 HTTP/3 请求通过 UDP 监听器 QUIC 传输套接字对外提供服务Upstream上游作为转发代理向上游服务器发起 HTTP/3 连接既支持数据中心场景下的显式强制 HTTP/3也支持面向公网的自动 HTTP/3根据上游的alt-svc广告自动选择。两种方向均基于 Google QUICHE 实现对 Google QUIC 与 IETF QUICRFC 9000 系列的支持这一实现细节记录在传输套接字的 proto 定义 quic_transport.proto 的注释中。HTTP/3 Downstream开启条件与配置开启 HTTP/3 的三个必要条件根据文档启用 Envoy HTTP/3 下游支持需要同时满足三个条件在 UDP 监听器的 udp_listener_config 中增加quic_options字段确保下游传输套接字transport socket使用QuicDownstreamTransport将 HTTP 编解码器codec设置为 HTTP/3。其中quic_options是QuicProtocolOptions类型。从 udp_listener_config.proto 的注释可知该字段为空时 QUIC 不会在该监听器上启用设置为默认对象quic_options: {}即可在不调整任何附加参数的情况下启用 QUIC。这一点正是官方示例配置的用法。完整示例配置解析仓库中提供了完整的下游 HTTP/3 示例配置 envoyproxy_io_proxy_http3_downstream.yaml它同时包含一个 TCP 监听器和一个 UDP 监听器TCP 监听器通过alt-svc响应头对外广告 HTTP/3 能力整体拓扑为客户端 → EnvoyHTTP/3 或 HTTPS→ www.envoyproxy.ioTCP。TCP 监听器负责常规 HTTPS并广告 HTTP/3listeners: - name: listener_tcp address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 10000 filter_chains: - transport_socket: name: envoy.transport_sockets.tls typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_certificates: - certificate_chain: filename: certs/servercert.pem private_key: filename: certs/serverkey.pem filters: - name: envoy.filters.network.http_connection_manager typed_config: type: type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager codec_type: HTTP2 stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: local_service response_headers_to_add: - header: key: alt-svc value: h3:10000; ma86400, h3-29:10000; ma86400 domains: [*] routes: - match: prefix: / route: host_rewrite_literal: www.envoyproxy.io cluster: service_envoyproxy_io http3_protocol_options: http_filters: - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.filters.http.router.v3.Router该监听器的关键点通过response_headers_to_add在响应中注入alt-svc: h3:10000; ma86400, h3-29:10000; ma86400响应头告知支持 HTTP/3 的客户端如 Chrome可以在同一端口UDP 10000上尝试 HTTP/3。其中ma86400表示该广告的最大有效期Max-Age为 86400 秒。UDP 监听器真正承载 HTTP/3 流量- name: listener_udp address: socket_address: protocol: UDP address: 0.0.0.0 port_value: 10000 udp_listener_config: quic_options: {} downstream_socket_config: prefer_gro: true filter_chains: - transport_socket: name: envoy.transport_sockets.quic typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicDownstreamTransport downstream_tls_context: common_tls_context: tls_certificates: - certificate_chain: filename: certs/servercert.pem private_key: filename: certs/serverkey.pem filters: - name: envoy.filters.network.http_connection_manager typed_config: type: type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager codec_type: HTTP3 stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: local_service domains: [*] routes: - match: prefix: / route: host_rewrite_literal: www.envoyproxy.io cluster: service_envoyproxy_io http3_protocol_options: http_filters: - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.filters.http.router.v3.RouterUDP 监听器的关键点地址协议为UDP端口与 TCP 监听器保持一致10000这是alt-svc广告语义的前提h3 服务与 https 服务同端口部署udp_listener_config.quic_options: {}即启用 QUICdownstream_socket_config.prefer_gro: true开启 UDP 收包 GROGeneric Receive Offload优化。从 udp_listener_config.proto 的注释看prefer_gro对监听器套接字的默认值为false文档建议当从少量来源接收大量数据报时经性能测试后再考虑开启传输套接字使用envoy.transport_sockets.quic即QuicDownstreamTransportHCM 的codec_type设置为HTTP3这是 downstream HTTP/3 的第三个必要条件。QuicDownstreamTransport 的字段语义QuicDownstreamTransport的完整定义位于 quic_transport.proto第 2342 行除了必填的downstream_tls_context下游 TLS 上下文外还提供两个可选调优字段enable_early_dataBoolValue控制 QUIC 0-RTT 早数据。默认值为true允许客户端在握手完成前发送请求但当DownstreamTlsContext.require_client_certificate被设置时早数据永远不会被使用且该字段默认变为false。这是因为 0-RTT 与客户端证书校验存在语义冲突。enable_resumptionBoolValue控制 TLS session ticket 的签发与接受。默认true但设置require_client_certificate时默认变为false。proto 注释给出了一个重要安全提示QUIC 在会话恢复时不会重新校验客户端证书——恢复的连接会复用首次握手时对证书的判定结果直至 ticket 过期因此证书吊销、过期或校验上下文变更都不会被重新检查。在需要客户端证书的 filter chain 上将此字段设为true是以安全性换取更廉价握手的一种权衡。QuicProtocolOptionsUDP 监听器的 QUIC 行为调优若默认的quic_options: {}不够用可在 quic_config.proto 中找到全部可调字段QuicProtocolOptions共 14 个可用字段常用参数及默认值整理如下字段作用默认值 / 约束idle_timeout连接无网络活动时的最大存活时长未指定为 300000ms5 分钟小于 1ms 时按 1ms 处理crypto_handshake_timeout加密握手完成前的连接超时未指定为 20000ms小于 5000ms 时按 5000ms 处理packets_to_read_to_connection_count_ratio每个事件循环内按连接数比例读取的数据包数如默认 32 表示 N 个连接每次读取 32×N 个包用于在吞吐与不让 TCP/其他 UDP 套接字饥饿、以及控制事件循环时长之间取得平衡默认 32最小值 1且无论该值多大单次读取总数上限为 6000 个包enabled运行时开关控制监听器是否启用未指定时默认启用crypto_stream_config选择quic::QuicCryptoClientStreamBase的实现未指定用 QUICHE 默认CryptoServerStreamConfigproof_source_config选择quic::ProofSource实现证书证明源未指定用默认ProofSourceConfigconnection_id_generator_config选择quic::ConnectionIdGeneratorInterface实现未指定用默认确定性 Connection ID 生成器server_preferred_address_config配置服务器偏好地址以便客户端迁移支持 v4/v6 各一个QUICHE 会根据客户端初始连接的地址族只广告其中一个未指定则不广告任何偏好地址send_disable_active_migration是否发送 RFC 9000 的disable_active_migration传输参数默认false不发送connection_debug_visitor_config附加quic::QuicConnectionDebugVisitor调试访问器未指定则不附加save_cmsg_config指定要通过QuicReceivedPacket传递给 listener filter 的 UDP cmsg最多 1 条level 与 type 必须同时指定未指定则不保存 cmsgreject_new_connections为true时在 QUIC 层拒绝建立连接的数据包向客户端回复空的版本协商包默认falsemax_sessions_per_event_loop每个事件循环最多创建的 QUIC session 数等价于 TCP 监听器的max_connections_to_accept_per_socket_event默认 16热重启Hot restart限制文档明确提示HTTP/3 目前尚未优雅支持热重启hot restart。因此在规划 Envoy 平滑升级/重启流程时需要将 HTTP/3 监听器纳入特殊考虑例如接受重启瞬间的连接中断或在设计中对 HTTP/3 流量单独处理。HTTP/3 广告Advertisement何时需要与如何配置在局域网或受控环境内部署时如果客户端是显式配置使用 HTTP/3 的则无需广告。但面向公网部署时TCP 仍是默认协议且诸如 Chrome 之类的浏览器只会在服务器显式广告 HTTP/3 时才尝试使用它。因此广告机制是公网场景下让客户端自动升级到 HTTP/3 的关键。Envoy 的实现方式并不特殊——它就是在 HTTP 响应中注入标准的alt-svc响应头HTTP Alternative ServicesRFC 7838如示例配置中的alt-svc: h3:10000; ma86400, h3-29:10000; ma86400这意味着客户端若支持可尝试在 UDP 端口 10000 上以 HTTP/3h3即 IETF QUIC 的最终版本或 h3-29早期 IETF QUIC draft-29 版本协议访问同一服务ma86400是该替代服务宣告的有效期。实际生产环境通常应只保留当前稳定版本标识如h3是否需要兼容旧版标识取决于客户端覆盖面。BPF 使用多线程下的性能关键文档对 BPFBerkeley Packet Filter的定位非常明确示例配置默认使用内核 UDP 支持但在多 worker 线程multiple worker threads运行时强烈建议为生产性能使用 BPF。其行为与权限要求如下当配置了多个 worker 线程时Envoy 在 Linux 上默认会尝试使用 BPF使用 BPF 可能需要 root 权限或至少需要具备相应权限的sudo例如执行sudo setcap cap_bpfep为可执行文件授予cap_bpf能力如果平台不支持 BPF或尝试加载 BPF 失败且同时配置了多 worker 线程Envoy 会在启动时记录一条警告日志。该警告日志可以作为诊断线索如果生产环境配置了多线程 HTTP/3 却未真正用上 BPF启动日志中应当能看到相关告警此时需要检查进程权限或内核/发行版对 BPF 的支持情况。Downstream 监控必须关注的 QUIC 与 UDP 指标HTTP/3 基于 UDP 承载其监控视角与 TCP 时代有显著差异。文档建议重点监控以下两类指标UDP 监听器丢包指标downstream_rx_datagram_droppedUDP listener 统计该值非零说明内核 UDP 监听套接字的接收缓冲区不够大。在 Linux 上可以通过监听器的socket_options进行调优在SOL_SOCKET级别设置 prebinding socket optionSO_RCVBUF以扩大内核接收缓冲。其配置位于config.listener.v3.Listener.socket_options字段中。QUIC 连接错误码与流重置错误码文档引用了 QUIC 连接错误码和流重置错误码的统计口径per-listener HTTP/3 统计并指出每个错误码的具体含义可参考 QUICHE 的quic_error_codes.hquic/core/quic_error_codes.h例如各类连接错误版本协商失败、TLS 握手错误、传输参数错误等与流错误应用层重置、流量控制违规等的编码定义。在实际排障时将 Envoy 统计中出现的错误码与 QUICHE 的错误码定义对应起来即可快速定位是客户端行为、网络问题还是配置问题。HTTP/3 Upstream显式与自动两种接入方式Envoy 的 HTTP/3 上游支持已经实现并同时覆盖两种场景显式 HTTP/3面向数据中心与自动 HTTP/3面向公网。两者的配置入口均为 cluster 上的typed_extension_protocol_options中的envoy.extensions.upstreams.http.v3.HttpProtocolOptions详见 http_protocol_options.proto。显式 HTTP/3适用于 UDP 不会被封锁的受控环境如果你处于受控环境如数据中心内网可以确信 UDP 不会被网络设备封锁则直接在HttpProtocolOptions中将 HTTP/3 配置为显式协议。仓库示例 google_com_http3_upstream_proxy.yaml 演示了完整的接收 HTTP/1 请求、以 HTTP/3 转发到 Google的配置clusters: - name: service_google connect_timeout: 30s type: LOGICAL_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN load_assignment: cluster_name: service_google endpoints: - lb_endpoints: - endpoint: address: socket_address: address: www.google.com port_value: 443 typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http3_protocol_options: {} common_http_protocol_options: idle_timeout: 1s transport_socket: name: envoy.transport_sockets.quic typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicUpstreamTransport upstream_tls_context: sni: www.google.com这里有两个要点explicit_http_config.http3_protocol_options将上游协议强制锁定为 HTTP/3不再协商 HTTP/1、HTTP/2传输套接字必须切换为envoy.transport_sockets.quic对应的QuicUpstreamTransport并在upstream_tls_context中指定 SNI。与下游不同QuicUpstreamTransport在 quic_transport.proto 中仅有一个必填字段upstream_tls_context无需额外配置。自动 HTTP/3面向公网的 alt-svc 驱动选择对于公网场景如果对上游是否支持 HTTP/3 没有把握则应使用auto_configHttpProtocolOptions.AutoHttpConfig并配合http3_protocol_options配置。此时 Envoy 只会对通过alt-svc响应头显式广告了 HTTP/3 支持的端点尝试使用 HTTP/3。从 connection_pooling.rst 可知使用 auto-http HTTP/3 还必须配置备选协议缓存alternate_protocols_cache_options——Envoy 依赖该缓存记录上游的 alt-svc 广告信息。若上游没有广告Envoy 会退而使用 HTTP/2 或 HTTP/1.1。仓库中另有面向公网的自动 HTTP/3 示例 google_com_auto_http3_upstream_proxy.yaml 可供参考。自动模式下的 QUIC/TCP 竞争机制自动 HTTP/3 的核心行为文档原文描述是Envoy 会先尝试建立 QUIC 连接若短延迟后 QUIC 握手仍未完成则同时发起 TCP 连接最终使用先建立成功的那条连接。结合 connection_pooling.rst 的细化描述实际时序是Envoy 先尝试 QUIC 连接300ms 后若 QUIC 尚未建立则并行尝试 TCP 连接两者谁先完成握手就用谁的连接承载首个请求如果 TCP 与 QUIC 都建立成功QUIC 最终会被优先采用。HTTP/3 连接池行为从 connection_pooling.rst 可以了解 HTTP/3 连接池的完整语义它与 HTTP/2 高度类似单条 HTTP/3 连接上可多路复用多个请求上限受QuicProtocolOptions.max_concurrent_streams与 cluster 的max_requests_per_connection共同约束连接池按需建立连接无限制时通常只有一条连接收到 GOAWAY 帧或达到单连接请求数上限时连接池会排空drain受影响的连接连接达到最大并发流限制后会被标记为 busy直到有流释放只要有待处理请求且没有可派发的连接就会新建连接受 circuit breaker 连接数上限约束。另外每个 host 在每个 cluster 下会维护一个或多个连接池多协议如同时支持 HTTP/1 与 HTTP/2/HTTP/3的 cluster 会按协议分别建池且每个 worker 线程各自维护自己的连接池。这意味着若 Envoy 有两个 worker 线程且 cluster 同时支持 HTTP/1 与 HTTP/2至少会有 4 个连接池。自动 HTTP/3 的 Happy Eyeballs 类似机制文档还描述了 HTTP/3 具备有限的类 Happy Eyeballs 支持当使用auto_config且 QUIC 需要 TCP 回退时Envoy 会尽力尝试两个地址族address family。与 TCP Happy Eyeballs 一致Envoy 给首次 HTTP/3 尝试 300ms 的时间窗口若连接显式失败或 300ms 超时且 DNS 解析出的前两个地址分属不同地址族Envoy 会用第二个地址族再建一个 HTTP/3 连接池并尝试连接。此场景下只有在 TCP 连接已建立且两个 HTTP/3 尝试都失败时HTTP/3 才会被标记为不可用broken。注意事项与限制汇总本文涉及的 HTTP/3 使用限制便于规划落地热重启未优雅支持HTTP/3 监听器目前无法通过 hot restart 无缝迁移重启会伴随连接中断UDP 可能被封锁HTTP/3 运行于 QUICUDP不少网络设备会封锁 UDP 流量从而间接封锁 HTTP/3公网自动模式下这类被封锁的连接会自然回退到 HTTP/2/HTTP/1自动 HTTP/3 的代码路径仍标记为 alpha文档明确该路径在获得大量生产环境验证前仍视为 alpha但已认为可投入使用BPF 依赖权限多线程 BPF 需要 root 或cap_bpf能力否则只能回退到内核 UDP 路径并产生启动警告监控不能沿用 TCP 思路必须额外盯住 UDP 接收缓冲丢包downstream_rx_datagram_dropped与 QUIC 错误码二者是 HTTP/3 排障的一线信息源。综上Envoy 的 HTTP/3 能力已经从可用走向面向生产调优阶段下游通过quic_optionsQuicDownstreamTransport HTTP/3 codec 三要素开启配合alt-svc广告与 BPF 加速面向公网提供服务上游通过显式或自动配置对接 HTTP/3 源站并依靠 alt-svc 广告缓存、QUIC/TCP 竞争机制与类 Happy Eyeballs 逻辑在复杂公网环境中保持可用性。结合本文给出的示例配置与 http3.rst、connection_pooling.rst、quic_transport.proto 等一手资料你可以据此搭建并持续观测自己的 HTTP/3 接入链路。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考