Skip to content

二级缓存

二级缓存(L2)扩展了一级内存缓存的能力,通过 Redis 实现跨实例的分布式缓存。启用 L2 后,多个数据墙DBW 实例可以共享缓存结果,容器重启后仍可从 Redis 恢复缓存,避免冷启动导致的数据库压力。

IMPORTANT

L2 需要在全局配置中显式启用 Redis 连接。如果全局未启用 L2,即使实体配置了 "level": "L1L2",实际行为也会退化为纯 L1。

全局启用 L2

runtime.cache 中配置二级缓存连接:

json
{
  "runtime": {
    "cache": {
      "enabled": true,
      "ttl-seconds": 30,
      "level-2": {
        "enabled": true,
        "provider": "redis",
        "connection-string": "localhost:6379",
        "partition": "prod-api"
      }
    }
  }
}
字段必需说明
level-2.enabled启用二级缓存
level-2.provider当前仅支持 "redis"
level-2.connection-stringRedis 实例的连接地址
level-2.partition缓存命名空间分区,隔离不同环境或应用

L1L2 请求流程

当实体配置为 "level": "L1L2" 时,一次查询请求的缓存查找路径为:

text
请求 → 检查 L1(进程内存)
  ├── L1 命中 → 直接返回
  └── L1 未命中 → 检查 L2(Redis)
        ├── L2 命中 → 回写 L1 → 返回
        └── L2 未命中 → 查询数据库
              ├── 回写 L2 → 回写 L1 → 返回

这个三层查找策略的意义:

  • L1 命中:进程内内存读取,延迟极低(< 1ms),适用于同一实例的重复请求。
  • L2 命中:Redis 网络读取,延迟较低(< 5ms),适用于不同实例的首次请求或重启后恢复。
  • 数据库查询:仅在前两级都未命中时发生,触发后将结果回填到 L2 和 L1。

实际场景举例

场景:三个数据墙DBW 实例通过负载均衡对外服务,L2 已启用。

  1. 实例 A 收到 GET /api/Product?$first=20,L1 和 L2 都未命中,查询数据库,结果回写 L2 → L1。耗时 50ms。
  2. 实例 A 再次收到相同请求,L1 命中。耗时 < 1ms。
  3. 实例 B 收到相同请求,L1 未命中,L2 命中,回写实例 B 的 L1。耗时 < 5ms。
  4. 实例 A 重启,L1 清空。收到请求后 L1 未命中,L2 命中,回写 L1。不会触发数据库查询。

Redis 配置

基本连接

json
{
  "level-2": {
    "provider": "redis",
    "connection-string": "localhost:6379"
  }
}

带密码认证

json
{
  "level-2": {
    "provider": "redis",
    "connection-string": "localhost:6379,password=your_redis_password"
  }
}

或使用 @env() 避免在配置文件中写入连接信息:

json
{
  "connection-string": "@env('REDIS_CONN_STR')"
}

NOTE

Redis 连接字符串使用 StackExchange.Redis 标准格式,常见参数包括 passwordsslabortConnect 等。完整格式参考:host:port,password=xxx,ssl=true,abortConnect=false

Redis 生产部署建议

建议说明
使用独立 Redis 实例不要与业务 Redis 混用,避免键冲突和资源争抢
启用持久化(RDB/AOF)Redis 重启后可以恢复缓存,减少数据库冷启动压力
配置内存上限设置 maxmemory 和淘汰策略(建议 allkeys-lru
监控内存使用跟踪 Redis 内存使用量,确保不超过实例容量
高可用生产环境建议使用 Redis Sentinel 或 Cluster

分区(Partition)

partition 参数用于在同一个 Redis 实例中隔离不同环境或应用的缓存空间:

json
{
  "level-2": {
    "partition": "prod-api"
  }
}

分区作为 Redis 键前缀生效。只有配置了相同 partition 值的数据墙DBW 实例才会共享缓存。典型用途:

场景分区值
生产环境和测试环境用同一 Redis"prod-api" / "test-api"
多租户 SaaS,每个租户的数据墙DBW 实例"tenant-a" / "tenant-b"
同一应用的不同微服务"service-orders" / "service-products"

L1 vs L1L2 选择

维度纯 L1L1L2
部署复杂度最低,无外部依赖需要 Redis 实例
读取延迟< 1msL1 命中 < 1ms,L2 命中 < 5ms
多实例共享不支持支持
重启恢复不支持,冷启动支持,L2 命中可避免数据库查询
适合场景单实例、低流量多实例、水平扩展、频繁部署

缓存失效与 L2

L2 的失效机制与 L1 相同——当实体发生写操作时,该实体在 L1 和 L2 中的所有缓存条目同时失效。数据墙DBW 通过 Redis 的 Pub/Sub 机制在实例间同步失效事件:

  1. 实例 A 收到 POST /api/Book,执行写入。
  2. 实例 A 清除自己的 L1 缓存,并向 Redis 发布失效消息。
  3. 实例 B、C 通过 Redis Pub/Sub 接收到失效消息,清除各自的 L1 缓存。
  4. L2 中的该实体缓存条目被实例 A 清除。

这个机制确保在多实例场景下,一个实例的写入能及时让所有实例的缓存失效,避免返回过时数据。

L2 降级

如果 Redis 不可用(网络故障、Redis 宕机),数据墙DBW 不会拒绝请求——L2 未命中时直接查询数据库,但不回写 L2。服务继续正常运行,退化为纯 L1 行为。Redis 恢复后,L2 功能自动恢复。

下一步

数据墙DBW 产品文档与开发指南。