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)

缓存键生成流程 原始请求 提取 Scheme/Host/Path 过滤+排序查询参数 合并 allowed_vary_headers 拼接缓存键字符串 最终缓存键 ⚠ 注意: 未在 allowed_vary_headers 和 cache_key_query_parameters 中列出的头部/参数,将被排除在缓存键之外。

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头部的策略

最佳实践:
  1. 最小化Vary头部:后端只返回真正影响响应内容的请求头。避免返回 Vary: * 或 Vary: User-Agent。
  2. 使用规范化值:如果后端需要根据 Accept-Language 返回不同内容,建议在客户端或网关层将语言值规范化(如只保留前两个字符 zh、en),减少缓存键的基数。
  3. 在Envoy层覆盖Vary:通过 response_headers_to_remove 移除不必要的 Vary 头部,或通过 response_headers_to_add 添加更精确的 Vary。
  4. 监控Vary头部:在巡检中,定期检查后端返回的 Vary 头部,发现高基数Vary时及时告警。

4.3.4 Vary头部与缓存键的交互流程(SVG)

Vary头部对缓存键的影响 请求到达Envoy 有Vary? 仅URL作为缓存键 Vary头部值追加到缓存键 缓存键: URL 缓存键: URL + Vary值 ⚠ Vary头部风险 • Vary: User-Agent → 缓存几乎失效 • Vary: * → 缓存完全失效 • 高基数Vary → 缓存碎片化 • 建议:后端只返回必要的Vary • 建议:在Envoy层规范化Vary

4.4 缓存键与路由策略的协同优化

在实际的灾备缓存巡检中,缓存键和路由策略需要协同工作。以下是几个关键的优化方向:

  • 避免缓存键膨胀:在路由级别限制 allowed_vary_headers 的数量,只包含必要的头部。
  • 路由粒度与缓存键匹配:对于需要细粒度缓存的路由(如用户信息),确保缓存键包含 authorization 或 x-user-id;对于公共资源,则尽量简化缓存键。
  • 使用缓存键前缀:在 cache_key 配置中,可以通过 cache_key_prefix 为不同路由的缓存键添加前缀,避免不同路由之间的缓存键冲突。
  • 监控缓存键分布:通过Envoy的统计指标(如 cache.cache_key_count)监控缓存键的数量,发现异常增长时及时排查。
巡检建议:在灾备切换演练中,重点关注缓存键的变化。如果灾备集群的缓存键数量与主集群差异超过20%,说明缓存策略可能存在问题。此时应检查 Vary 头部、路由匹配规则以及 allowed_vary_headers 配置是否一致。