实现二级缓存
数据墙DBW长期以来一直支持一级(L1)内存缓存,以及与缓存相关的 HTTP 请求头(例如 no-store、no-cache 和 only-if-cached)来影响缓存行为。
二级(L2)缓存通过添加分布式缓存层,将缓存扩展到本地进程之外。启用 L2 后,缓存结果可以在多个数据墙DBW实例之间复用,并且能够在单个容器重启后继续保留,从而让无状态部署在正确的地方“看起来没那么无状态”。
二级缓存的收益
在以下场景下适合使用二级缓存:
- 在横向扩展后的多个数据墙DBW实例之间共享缓存结果
- 减少重复读取操作对数据库的往返请求
- 在容器回收或重新部署后,仍保持无状态容器的“热启动”体验
- 提升读多写少工作负载的性能
- 使用分区来对缓存参与范围做命名空间隔离
配置运行时缓存设置
二级缓存是在 runtime.cache 下做全局配置的。运行时缓存块会启用缓存、设置默认 TTL,并配置分布式缓存提供程序。
{
"runtime": {
"cache": {
"enabled": true,
"ttl-seconds": 30,
"level-2": {
"enabled": true,
"provider": "redis",
"connection-string": "localhost:6379",
"partition": "prod-api"
}
}
}
}运行时属性
| 属性 | 说明 |
|---|---|
enabled | 全局启用缓存支持。 |
ttl-seconds | 设置默认缓存生存时间(秒)。 |
level-2.enabled | 打开分布式缓存层。 |
level-2.provider | 选择分布式缓存提供程序。当前仅支持 redis。 |
level-2.connection-string | Redis 实例的连接字符串。 |
level-2.partition | 可选的 Redis 键和 backplane 通道命名空间。只有使用同一分区的容器才会共享同一个分布式缓存空间。 |
配置实体级缓存行为
实体可以覆盖全局缓存行为。使用实体上的 cache 块启用缓存、设置自定义 TTL,并选择缓存级别。
{
"entities": {
"Products": {
"source": "dbo.Products",
"cache": { "enabled": true, "ttl-seconds": 120, "level": "L1L2" }
},
"Orders": {
"source": "dbo.Orders",
"cache": { "enabled": true, "level": "L1" }
}
}
}cache.level 属性
使用 cache.level 控制实体要使用哪些缓存层级。
| 值 | 说明 |
|---|---|
L1 | 仅内存缓存。速度快,并且仅存在于当前数据墙DBW进程内。 |
L1L2 | 内存缓存加分布式缓存。这是启用缓存实体的默认级别。 |
如果全局没有启用 L2,那么配置为 L1L2 的实体会退化为 L1 行为。
L1L2 的工作方式
TIP
一句话版本:L1L2 = Request -> L1 -> L2 -> database -> L2 -> L1 -> Response
默认情况下,只要实体启用了缓存,就会使用 L1L2 级别。
L1是进程级的内存缓存L2是分布式缓存层(当前为 Redis),并带有用于跨实例一致性的 backplane
在 L1L2 模式下,请求会先检查 L1。如果 L1 未命中,则在全局已启用且已正确配置二级缓存时,再检查 L2。如果两个层级都没有命中,数据墙DBW才会执行数据库查询。查询结果随后会同时写入 L1 和 L2。
这意味着:
- 同一实例上的后续请求会直接从本地
L1命中 - 其他实例上的请求可以从
L2读取结果,并把该结果提升到它们自己的L1 - 如果某个容器重启,虽然它本地的
L1会丢失,但只要L2命中,仍然可以避免再次访问数据库
这种组合方式为横向扩展或频繁回收的实例提供了一个“温热”的分布式缓存层。
Redis 支持
Redis 是当前二级缓存的实现提供程序。它很适合该场景,因为它支持:
- 多个数据墙DBW实例之间共享访问
- 基于 TTL 的键过期机制
- 高吞吐读写
- 实例之间的 backplane 协调
分区化缓存空间
使用可选的 partition 设置可隔离分布式缓存活动。数据墙DBW会使用该分区值为 Redis 键和 backplane 通道添加命名空间。只有共享同一个分区值的容器才会参与同一个分布式缓存空间。
在以下情况下,这个设置很有用:
- 将生产与非生产流量分离
- 隔离不同租户或不同环境
- 防止无关服务共享缓存项
