4. 缓存键与路由策略:缓存键生成规则、基于路由的缓存策略、Vary头部对缓存的影响
缓存键(Cache Key)是Envoy缓存系统的核心标识,它决定了请求是否命中缓存。路由策略则控制哪些请求进入缓存、哪些绕过。Vary头部进一步细化了缓存键的维度。三者共同构成了Envoy缓存命中率的底层逻辑。
4.1 缓存键(Cache Key)生成规则
Envoy默认使用请求的URL(路径+查询参数)作为缓存键。但在生产环境中,仅靠URL远远不够——同一个URL可能因不同的请求头(如Accept-Encoding、Authorization)返回不同的响应。Envoy通过cache_key配置允许你自定义缓存键的组成。
4.1.1 默认缓存键结构
| 组件 | 说明 | 示例 |
|---|---|---|
| Scheme | 协议(http/https) | https |
| Host | 请求的Host头部 | api.example.com |
| Path | URL路径 | /v1/users |
| Query | URL查询参数(按字母排序) | ?id=123&lang=zh |
关键认知:Envoy默认会对查询参数进行字母排序后再生成缓存键。这意味着
?lang=zh&id=123 和 ?id=123&lang=zh 会被视为同一个缓存键,避免因参数顺序不同导致缓存分裂。
4.1.2 自定义缓存键:包含请求头
通过allowed_vary_headers和cache_key_query_parameters可以精细控制缓存键的组成。以下是一个典型的自定义缓存键配置:
static_resources:
listeners:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match:
prefix: "/api"
route:
cluster: backend_cluster
max_stream_duration:
max_stream_duration: 0s
typed_per_filter_config:
envoy.filters.http.cache:
"@type": type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig
cache_key:
allowed_vary_headers:
- exact: "accept-encoding"
- exact: "accept-language"
cache_key_query_parameters:
- string_match:
exact: "id"
- string_match:
exact: "lang"
配置要点:
allowed_vary_headers:指定哪些请求头参与缓存键计算。只有列出的头部才会影响缓存键。cache_key_query_parameters:指定哪些查询参数参与缓存键。未列出的参数将被忽略,避免无关参数(如utm_source)导致缓存碎片。- 如果某个请求头或参数未在列表中,Envoy会将其排除在缓存键之外,从而提升缓存命中率。
4.1.3 缓存键生成流程(SVG)
4.2 基于路由的缓存策略
Envoy允许在路由级别控制缓存行为。这意味着你可以为不同的API路径、不同的域名甚至不同的请求头设置差异化的缓存策略。这是实现“精细缓存控制”的关键手段。
4.2.1 路由缓存策略配置
以下配置展示了如何在路由级别启用/禁用缓存,并设置不同的缓存TTL:
route_config:
name: local_route
virtual_hosts:
- name: api_host
domains: ["api.example.com"]
routes:
# 静态资源:长缓存
- match:
prefix: "/static"
route:
cluster: static_cluster
typed_per_filter_config:
envoy.filters.http.cache:
"@type": type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig
cache_enabled: true
cache_key:
allowed_vary_headers:
- exact: "accept-encoding"
ttl:
default_ttl: 86400s # 24小时
# 用户信息:短缓存,且区分语言
- match:
prefix: "/api/v1/users"
route:
cluster: user_cluster
typed_per_filter_config:
envoy.filters.http.cache:
"@type": type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig
cache_enabled: true
cache_key:
allowed_vary_headers:
- exact: "accept-language"
ttl:
default_ttl: 60s # 1分钟
# 动态数据:禁用缓存
- match:
prefix: "/api/v1/orders"
route:
cluster: order_cluster
typed_per_filter_config:
envoy.filters.http.cache:
"@type": type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig
cache_enabled: false
4.2.2 路由缓存策略对比
| 策略类型 | 适用场景 | TTL建议 | 缓存键注意事项 |
|---|---|---|---|
| 长缓存(静态资源) | 图片、CSS、JS、字体 | 24h ~ 7d | 仅包含 accept-encoding,避免缓存分裂 |
| 短缓存(用户数据) | 用户信息、配置、公共列表 | 30s ~ 5min | 包含 accept-language、authorization(需谨慎) |
| 禁用缓存 | 订单、支付、实时数据 | N/A | N/A |
| 条件缓存 | 基于请求头或查询参数动态决定 | 动态 | 使用 match_headers 或 match_query_parameters 做路由匹配 |
常见陷阱:在路由级别禁用缓存时,务必确认该路由下的所有请求都不应被缓存。如果某个路由同时匹配了“禁用缓存”和“启用缓存”的规则,Envoy会以更具体的匹配规则为准。建议使用
prefix 或 regex 做精确匹配,避免规则冲突。
4.3 Vary头部对缓存的影响
Vary是HTTP响应头部,它告诉缓存系统:这个响应依赖于哪些请求头。Envoy会严格遵循Vary头部来调整缓存键的生成。这是缓存系统中最容易引发问题的环节之一。
4.3.1 Vary头部的工作原理
当后端返回Vary: Accept-Encoding, Accept-Language时,Envoy会将Accept-Encoding和Accept-Language的值追加到缓存键中。这意味着:
- 同一个URL,如果
Accept-Language不同,会被视为不同的缓存条目。 - 缓存键膨胀:每个不同的
Vary头部值组合都会产生一个新的缓存条目。 - 命中率下降:如果
Vary头部包含高基数的请求头(如User-Agent),缓存命中率会急剧下降。
4.3.2 Vary头部与缓存键的交互
| 场景 | 后端返回的Vary | Envoy缓存键行为 | 对命中率的影响 |
|---|---|---|---|
| 无Vary | 无 | 仅使用URL作为缓存键 | 最高 |
| Vary: Accept-Encoding | Vary: Accept-Encoding |
缓存键包含 Accept-Encoding 值 |
中等(通常只有gzip/br/deflate几种) |
| Vary: Accept-Language | Vary: Accept-Language |
缓存键包含 Accept-Language 值 |
中等(通常只有zh/en/ja等少数语言) |
| Vary: User-Agent | Vary: User-Agent |
缓存键包含 User-Agent 值 |
极低(User-Agent基数极高) |
| Vary: * | Vary: * |
缓存键包含所有请求头 | 几乎为0(缓存完全失效) |
4.3.3 优化Vary头部的策略
最佳实践:
- 最小化Vary头部:后端只返回真正影响响应内容的请求头。避免返回
Vary: *或Vary: User-Agent。 - 使用规范化值:如果后端需要根据
Accept-Language返回不同内容,建议在客户端或网关层将语言值规范化(如只保留前两个字符zh、en),减少缓存键的基数。 - 在Envoy层覆盖Vary:通过
response_headers_to_remove移除不必要的Vary头部,或通过response_headers_to_add添加更精确的Vary。 - 监控Vary头部:在巡检中,定期检查后端返回的
Vary头部,发现高基数Vary时及时告警。
4.3.4 Vary头部与缓存键的交互流程(SVG)
4.4 缓存键与路由策略的协同优化
在实际的灾备缓存巡检中,缓存键和路由策略需要协同工作。以下是几个关键的优化方向:
- 避免缓存键膨胀:在路由级别限制
allowed_vary_headers的数量,只包含必要的头部。 - 路由粒度与缓存键匹配:对于需要细粒度缓存的路由(如用户信息),确保缓存键包含
authorization或x-user-id;对于公共资源,则尽量简化缓存键。 - 使用缓存键前缀:在
cache_key配置中,可以通过cache_key_prefix为不同路由的缓存键添加前缀,避免不同路由之间的缓存键冲突。 - 监控缓存键分布:通过Envoy的统计指标(如
cache.cache_key_count)监控缓存键的数量,发现异常增长时及时排查。
巡检建议:在灾备切换演练中,重点关注缓存键的变化。如果灾备集群的缓存键数量与主集群差异超过20%,说明缓存策略可能存在问题。此时应检查
Vary 头部、路由匹配规则以及 allowed_vary_headers 配置是否一致。