3. Envoy 缓存模块概述:HTTP 缓存过滤器、缓存配置结构、缓存键生成规则
在 Envoy 的七层代理架构中,HTTP 缓存过滤器(HTTP Cache Filter) 是实现灾备缓存命中巡检的核心组件。它位于 HTTP 连接管理器(HCM)的过滤器链中,负责拦截上游响应并将其缓存到后端存储,同时在下游请求到达时提供缓存命中服务。本章将深入剖析该过滤器的内部机制、配置结构以及缓存键的生成规则,为后续的性能调优奠定基础。
3.1 HTTP 缓存过滤器:架构定位与工作流
Envoy 的缓存过滤器遵循 RFC 7234(HTTP 缓存规范)标准,支持 GET 和 HEAD 方法的缓存,并严格遵循 Cache-Control、Expires、ETag 等头部指令。其核心工作流分为 请求路径 和 响应路径 两个阶段:
- 请求路径(Lookup):下游请求到达时,过滤器根据缓存键查询后端存储。若命中且未过期,直接返回缓存响应(
X-Cache: HIT);若未命中或过期,将请求转发给上游,并标记为X-Cache: MISS。 - 响应路径(Store):上游响应返回时,过滤器根据
Cache-Control等头部判断是否可缓存。若可缓存,则将响应体与元数据写入后端存储,并设置 TTL。
关键指标:Envoy 的缓存过滤器在 Lookup 阶段支持
conditional request(条件请求),即当缓存过期时,可携带 If-None-Match 或 If-Modified-Since 向上游验证,若上游返回 304,则复用缓存并刷新 TTL。这一机制在灾备场景下可显著减少上游回源压力。
3.2 缓存配置结构:从 Filter 到 Backend
Envoy 的缓存配置采用 分层结构,从 HTTP 连接管理器(HCM)的过滤器配置,到底层缓存后端存储的详细参数。以下是一个典型的缓存过滤器配置示例:
http_filters:
- name: envoy.filters.http.cache
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig
cache_service:
name: my_cache_service
typed_config:
"@type": type.googleapis.com/envoy.extensions.cache.simple.v3.SimpleCacheConfig
max_size: 268435456 # 256 MB
default_ttl: 300s # 默认 TTL 5 分钟
allowed_vary_headers:
- "Accept-Encoding"
- "Authorization"
cache_key_config:
- host_and_path: true
query_parameters: ["q", "lang"]
headers: ["X-Custom-Key"]
配置结构的关键层级如下表所示:
| 配置层级 | 字段 | 说明 | 典型值 |
|---|---|---|---|
| Filter 层 | cache_service |
指定缓存后端存储实现(如 SimpleCache、Redis、Memcached) | envoy.extensions.cache.simple.v3.SimpleCacheConfig |
| Backend 层 | max_size |
缓存存储的最大容量(字节),超出后按 LRU 淘汰 | 268435456 (256 MB) |
| TTL 层 | default_ttl |
当上游响应未携带 Cache-Control: max-age 时的默认 TTL |
300s |
| Vary 层 | allowed_vary_headers |
允许的 Vary 响应头部列表,用于区分缓存变体 |
Accept-Encoding, Authorization |
| Key 层 | cache_key_config |
自定义缓存键生成规则(见 3.3 节) | host_and_path, query_parameters |
性能陷阱:
max_size 设置过小会导致频繁的 LRU 淘汰,降低缓存命中率;设置过大则可能耗尽内存,触发 OOM Killer。建议根据实际流量模型,通过 缓存命中率监控 动态调整,初始值可设为节点可用内存的 10%-20%。
3.3 缓存键生成规则:从 URL 到唯一标识
Envoy 的缓存键(Cache Key)是缓存查找和存储的唯一标识符。默认情况下,缓存键由 Scheme + Host + Path + Query Parameters 组成,但通过 cache_key_config 可以高度自定义。缓存键的生成规则直接影响缓存粒度和命中率:
- 默认规则:
http://example.com/api/v1/users?page=1的缓存键为http|example.com|/api/v1/users|page=1。 - 自定义规则:通过
host_and_path、query_parameters、headers三个子配置控制键的组成部分。
以下是一个缓存键生成的详细示例:
# 请求 URL: https://api.example.com/search?q=envoy&lang=zh&page=2
# 配置:
cache_key_config:
- host_and_path: true
query_parameters: ["q", "lang"]
headers: ["X-Custom-Key"]
# 生成的缓存键:
# "https|api.example.com|/search|q=envoy&lang=zh|X-Custom-Key=value"
缓存键生成规则的关键参数对比:
| 参数 | 类型 | 作用 | 对命中率的影响 |
|---|---|---|---|
host_and_path |
bool | 是否包含 Host 和 Path | 开启后不同路径独立缓存,粒度更细 |
query_parameters |
string[] | 指定参与键生成的查询参数列表 | 只包含关键参数可提升聚合命中率 |
headers |
string[] | 指定参与键生成的请求头部列表 | 用于多租户或 A/B 测试场景 |
scheme |
bool (隐式) | 是否包含 http/https 协议 | 默认包含,避免协议混用导致缓存失效 |
3.4 缓存键优化策略:提升命中率的关键
在灾备缓存场景中,缓存键的粒度直接决定了命中率。以下是一些经过生产验证的优化策略:
- 精简查询参数:只将影响响应内容的参数(如
q、lang)加入键,忽略utm_source、session_id等无关参数。可通过query_parameters_exclude配置排除。 - 规范化路径:对路径进行大小写归一化、去除尾部斜杠,避免同一资源因路径格式不同导致缓存分裂。
- 头部白名单:仅将必要的请求头部(如
Accept-Encoding)加入键,避免因Cookie或User-Agent等高频变化头部导致缓存碎片化。 - 使用 Vary 头部:当上游响应携带
Vary: Accept-Encoding时,Envoy 会自动为不同编码生成缓存变体,无需手动配置头部到键中。
实战案例:某电商平台在灾备切换后发现缓存命中率从 85% 骤降至 30%。经排查,原因是
session_id 被默认加入了缓存键。通过配置 query_parameters: ["product_id", "category"] 并排除 session_id,命中率恢复至 78%。这一优化在灾备场景下减少了 60% 的上游回源流量。