Envoy HTTP Cache 过滤器(Cache Filter)实战指南:配置、语义与存储后端
2026/9/13 21:20:27 网站建设 项目流程

Envoy HTTP Cache 过滤器(Cache Filter)实战指南:配置、语义与存储后端

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

HTTP Cache 过滤器是 Envoy 原生实现 RFC 7234 缓存语义的 HTTP 过滤器,负责判定请求/响应是否可缓存、计算新鲜度(freshness lifetime)、并在内存或磁盘后端中存储与检索缓存对象。本文基于当前仓库的 cache_filter.rst 文档及其 API 定义与源码实现,完整讲解该过滤器的配置方法、请求/响应两侧的缓存判定规则、CacheConfig全部可用字段,以及SimpleHttpCache(内存)与FileSystemHttpCache(磁盘 LRU)两种内置存储后端的接入方式。读完本文,你将能够在一个真实 Envoy 静态配置中落地 HTTP 缓存,并理解缓存键、Vary 处理与过滤链语义背后的底层机制。

一、过滤器定位与基本约束

HTTP Cache 过滤器通过 HTTP 过滤器链(http_filters)接入,其 v3 配置类型为:

type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig

完整字段定义见 cache.proto,存储后端配置见 SimpleHttpCacheConfig 与 FileSystemHttpCacheConfig。

使用该过滤器时需要明确以下几点约束:

  • 不支持 virtual host 级别的配置:缓存配置只能挂在 HTTP 过滤器链上,不能针对某个虚拟主机单独开关。
  • 过滤链语义特殊:当缓存启用后,可缓存(cacheable)的请求只会经过upstream_http_filters链(即 Router.upstream_http_filters 中定义的过滤器),而不会经过普通过滤器链中位于 Cache 过滤器更上游(further upstream)的其他过滤器;不可缓存的请求则照常走完整的监听器过滤器链。
  • 推荐放置位置:为了保证两条路径行为一致,官方文档明确建议——在监听器过滤器链中,Cache 过滤器更上游的位置只应放置 router 过滤器。换言之,典型排布是... -> cache -> router,避免可缓存请求绕过中间过滤器而产生语义差异。

二、请求侧缓存语义

对于进入的 HTTP 请求,Cache 过滤器遵循以下判定逻辑(对应源码source/extensions/filters/http/cache/cacheability_utils.cc中的可缓存性判断):

  • 尊重请求的Cache-Control指令:例如请求携带Cache-Control: no-store时,该请求不会被缓存。唯一的例外是当CacheConfig.ignore_request_cache_control_header被置为true,此时过滤器将忽略这类指令。
  • 不缓存 HEAD 请求:HTTP Cache 不会存储 HEAD 请求(HEAD 通常用于探测资源是否存在,其响应体为空且不应污染缓存条目)。

此外,从 cache.proto 的注释可以看出,默认情况下请求中的cache-control: no-cachepragma: no-cache头会导致缓存即使命中也会回源(upstream)做校验(revalidation);设置ignore_request_cache_control_header = true可跳过这一行为。

三、响应侧缓存语义

对于上游返回的 HTTP 响应,Cache 过滤器只会存储满足以下全部条件的对象:

  1. 足以计算新鲜度生命周期的响应:过滤器的缓存判定以 RFC 7234 的新鲜度计算 为准——响应中必须携带足够的信息(如Cache-Control: max-ageExpiresLast-Modified等)来推导 freshness lifetime,否则不缓存。

  2. 尊重上游的Cache-Control指令:例如状态码 200、携带Cache-Control: max-age=60且没有vary头的响应会被缓存;而携带no-storeno-cache等指令的响应则按指令语义处理。

  3. 状态码在白名单内:只缓存以下状态码的响应:

    200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 451, 501

    可以看出白名单同时覆盖了成功类(200/203/204/206)、重定向类(300/301/308)以及错误类(404/405/410/414/451/501)响应,但排除了例如 500、502 等 5xx 服务端错误与 401/403 等需要按用户区分的响应。

  4. Vary 头允许列表allowed_vary_headersStringMatcher列表)在插入阶段充当白名单——如果响应的vary头中提及了任何未被allowed_vary_headers规则匹配的请求头名称,该响应将不被缓存;在查找阶段,它又决定了哪些请求头会被传给缓存存储后端用于命中判定。这在处理内容协商(如Accept-EncodingAccept-Language)响应时尤其关键。

四、CacheConfig 配置字段详解

CacheConfig目前共 7 个字段位(#next-free-field: 7),其中部分已实现、部分在 proto 中标注为#not-implemented-hide:。逐项说明如下:

字段类型状态说明
typed_configgoogle.protobuf.Any✅ 已实现缓存存储后端的嵌套配置,通过扩展类别envoy.http.cache选定实现。除非disabled为 true,否则该字段为必填。
allowed_vary_headersrepeated StringMatcher✅ 已实现定义允许的Vary头规则,同时控制插入白名单与查找时传给后端的请求头集合,详见上文第三节。
key_creator_paramsKeyCreatorParams⚠️ 未实现计划用于定制缓存键(是否排除 scheme/host、包含或排除哪些 query 参数),proto 中已预留结构但标注not-implemented-hide
max_body_bytesuint32⚠️ 未实现计划限制写入缓存的响应体大小,0 表示不限制(存储后端仍可能有自身限制)。
disabledgoogle.protobuf.BoolValue✅ 已实现为 true 时过滤器退化为 no-op(空操作)。典型用途是与 ECDS(扩展配置发现服务)配合实现在线开关。
ignore_request_cache_control_headerbool✅ 已实现默认 false;置 true 后忽略请求中的cache-control: no-cachepragma: no-cache,避免每次命中都强制回源校验。

KeyCreatorParams子消息(当前仅用于预留)包含exclude_schemeexclude_hostquery_parameters_includedquery_parameters_excluded四个字段,其中 query 参数匹配复用config.route.v3.QueryParameterMatcher,说明未来的缓存键定制将支持精确到 query 参数粒度的包含/排除。

五、架构与扩展点:HttpCache 接口

Envoy 的 HTTP 缓存体系被拆分为两个可独立扩展的层次:

  • HTTP Cache 过滤器(扩展名envoy.filters.http.cache,类别envoy.filters.http)——通过CacheConfig配置,负责实现 HTTP 缓存的全部语义判定(可缓存性、新鲜度、命中/未命中决策等)。
  • 缓存存储后端(扩展类别envoy.http.cache)——过滤器将对象的存储与检索委托给后端实现。后端通过CacheConfig.typed_config嵌套选定。

从源码结构看,存储抽象由 http_cache.h 中的HttpCache接口承担,各实现需要提供查找(lookup)与插入(insert)两条上下文路径;过滤器主体位于 cache_filter.cc,可缓存性判定与新鲜度逻辑集中在 cacheability_utils.cc,缓存键结构定义在 key.proto。

这种"语义内核 + 可插拔存储"的设计使得后端可以覆盖持久化、性能、分布式的任意组合点:从本地 RAM 缓存到全局分布式持久化缓存,既可以是完全自研的实现,也可以是本地或远端开源/商业缓存的包装器(wrapper/adaptor)。内置后端目前有两个:

  • SimpleHttpCacheConfig——内存实现,简单快速,适合单实例、小规模或测试场景;
  • FileSystemHttpCacheConfig——磁盘持久化实现,默认采用 LRU(最近最少使用)逐出策略,适合跨重启保留缓存的大规模场景。

六、示例一:SimpleHttpCache(内存缓存)

以下配置来自仓库示例 http-cache-configuration.yaml,展示了在http_filters链中挂载内存缓存后端的完整写法:

static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 8000 filter_chains: - 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: AUTO stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "*" routes: - match: prefix: "/service/1" route: cluster: service1 - match: prefix: "/service/2" route: cluster: service2 http_filters: - name: "envoy.filters.http.cache" typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig" typed_config: "@type": "type.googleapis.com/envoy.extensions.http.cache.simple_http_cache.v3.SimpleHttpCacheConfig" - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: service1 type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: service1 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service1 port_value: 8000 - name: service2 type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: service2 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service2 port_value: 8000

要点拆解:

  • 过滤器名必须为envoy.filters.http.cache,其typed_config类型为CacheConfig
  • CacheConfig.typed_config内再嵌套一层后端类型SimpleHttpCacheConfig。从 config.proto 可以看到该消息体目前是空的——内存后端无需任何额外参数;
  • 过滤器链中 Cache 位于router 之前,即上文第一节约束中推荐的排布;路由规则将/service/1/service/2分别指向两个 STRICT_DNS 集群。

七、示例二:FileSystemHttpCache(磁盘 LRU 缓存)

需要跨重启持久化缓存时,改用磁盘后端。以下配置来自仓库示例 http-cache-configuration-fs.yaml:

static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 8000 filter_chains: - 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: AUTO stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "*" routes: - match: prefix: "/service/1" route: cluster: service1 - match: prefix: "/service/2" route: cluster: service2 http_filters: - name: envoy.filters.http.cache typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig typed_config: "@type": type.googleapis.com/envoy.extensions.http.cache.file_system_http_cache.v3.FileSystemHttpCacheConfig manager_config: thread_pool: thread_count: 2 cache_path: /var/cache/envoy max_cache_size_bytes: 1073741824 - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: service1 type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: service1 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service1 port_value: 8000 - name: service2 type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: service2 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service2 port_value: 8000

FileSystemHttpCacheConfig的字段在 file_system_http_cache.proto 中定义,完整参数语义如下:

字段示例值说明
manager_configthread_pool.thread_count: 2必填(validate 规则为required: true)。异步文件管理器配置,指定如何以异步方式使用文件系统。
cache_path/var/cache/envoy缓存文件存储路径,同时充当缓存唯一标识:不同路由可共享同一cache_path的缓存,不同路径则各自独立。若多个CacheConfig使用相同cache_path,其余配置必须一致,且共享同一缓存实例。
max_cache_size_bytes1073741824(1 GiB)缓存总大小上限(按文件大小之和计,包含 header/trailer/元数据,不含文件系统开销与块填充)。达到上限触发逐出;不设置则仅受文件系统容量限制。
max_individual_cache_entry_size_bytes未设置单个缓存条目大小上限,超限响应不缓存;不设置则无限制(当前标注未实现)。
max_cache_entry_count未设置缓存条目数量上限,达到上限触发逐出;不设置则无限制。
cache_subdivisions未设置(默认 1)将缓存细分为多个子目录的数量。对于单目录大量 inode 会拖慢性能的文件系统,可设为sqrt(期望条目数)来提升性能;inode 友好的文件系统建议保持默认 1(当前标注未实现)。
evict_fraction未设置(默认 0)每次逐出时清理的比例。例如上限 10 MB、evict_fraction=0.2,超限后会逐出至 ≤ 8 MB;为 0 则只逐出至 ≤ 10 MB。逐出比例越大,逐出线程唤醒频率越低(省 CPU),但额外逐出的条目会带来更多缓存未命中(当前标注未实现)。
max_eviction_period未设置两次逐出扫描的最大间隔。即使没有超限,只要距上次扫描超过该时长也会唤醒逐出线程做一次状态同步——这对多实例并行访问同一缓存很关键(例如两个实例各写入 10 MB 到 15 MB 上限的缓存,彼此不知情,需要同步扫描来发现超限)(当前标注未实现)。
min_eviction_period未设置两次逐出扫描的最小间隔。可减少逐出抖动,代价是缓存可能在max_cache_size_bytes基础上多增长该时段内可写入的量。官方建议min_eviction_periodevict_fraction二选一(当前标注未实现)。
create_cache_path未设置(默认 false)为 true 且cache_path不存在时自动创建(含缺失的父目录),失败则拒绝配置;为 false 且路径不存在时直接拒绝配置(当前标注未实现)。

从源码目录 source/extensions/http/cache/file_system_http_cache/ 看,该后端由 file_system_http_cache.cc 实现主体,另含 cache_eviction_thread.cc(LRU 逐出线程)、cache_file_header.proto(磁盘文件头格式)与 stats.cc(统计指标),实现细节可进一步阅读该目录下的 DESIGN.md。内存后端则非常轻量,主体仅有 simple_http_cache.cc 与对应的头文件。

八、源码级补充:过滤器内部工作流

结合 source/extensions/filters/http/cache/ 目录中的源码组织,可以梳理出 Cache 过滤器内部的职责划分:

  • cache_filter.cc / cache_filter.h:过滤器主逻辑,负责接入 HTTP 解码/编码链路,协调查找、命中回放与未命中回源;
  • cacheability_utils.cc:集中实现请求/响应可缓存性判定,即上文第二、三节的规则所在;
  • cache_headers_utils.cc:解析与计算Cache-ControlExpiresAge等缓存相关头,支撑新鲜度计算;
  • http_cache.h:定义HttpCache存储接口(查找/插入上下文),是接入新存储后端的扩展点;
  • cache_insert_queue.cc:负责插入操作的排队与合并,避免同一资源并发回源时重复写入;
  • upstream_request.cc:管理未命中时向上游发起的请求及其与缓存插入的衔接;
  • range_utils.cc:处理 Range 请求与缓存片段(206 响应)的切片逻辑;
  • filter_state.h:在过滤器与后端之间传递缓存键、命中信息等状态。

这些文件共同印证了文档所述"HTTP Cache 过滤器实现了 HTTP 缓存语义的大部分复杂性"——语义判定全部集中在过滤器内,存储后端只需要实现纯粹的读写接口。

九、进一步学习路径

  • 交互式沙箱:Envoy 提供了 Cache 过滤器逐步实操沙箱,可结合官方 Cache Sandbox 按步骤验证配置效果。
  • V2 版本:仓库同时保留了缓存过滤器的 v2 变体,见 cache_v2 proto 及其存储后端 simple_http_cache v2 与 file_system_http_cache v2;新配置应优先使用 v3。
  • API 现状提示:从 proto 标注可以看出,KeyCreatorParamsmax_body_bytesFileSystemHttpCacheConfig的多个容量/逐出调优字段仍处于not-implemented-hide状态,生产使用时请以当前版本实际生效行为为准。

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询