结果缓存
约 1328 字大约 4 分钟
2025-05-08
结果缓存是 访问加速
常见的手段, 同时也是对后端服务容量的一种保护. 那么, 请求结果缓存, 都需要具备哪些能力呢?
缓存能力分析
缓存是否可用
缓存是否可用包含两个维度的控制:
- 缓存总开关是否开启, 未开启则全局禁用缓存
- 全局开关开启, 并且配置了缓存实例, 也配置了缓存策略, 但是不代表当前请求满足结果缓存的条件, 所以,
需要具备显示判断当前请求是否允许缓存
缓存时长
数据缓存必须设置有效期, 便于过去自动淘汰, 如果认为接口返回数据变化频率极低, 也要设置有效期, 可以将时间设置为一个较大值
缓存Key
缓存Key的生成是一个很 核心的逻辑
, 同时也是一个极其敏感的逻辑, 生成策略不合理,轻则无法命中缓存,重则读取到错误的缓存数据
无法命中缓存
在实际开发中, 经常会遇到某些接口会要求传递一个 时间戳参数
, 服务端通过计算服务端收到请求的时间与客户端传入的请求时间, 来判断请求是否有效. 如果将时间戳也参与缓存key的计算, 因为时间戳变化速度很快, 缓存的命中率基本等于0.
读取错误结果
读取到错误结果是一个 致命问题
, 一旦出现, 不可接受, 比如: 仅使用请求的接口作为缓存key, 无论什么查询条件, 都命中相同的缓存, 会导致数据混乱, 进而引发业务崩盘。
如何计算缓存key
首先, 这里只是一种建议策略, 仅是可行策略的一种. 可以使用如下格式:
Md5({{request_method}}_{{request_url}}_{{request_query}})
通过对 : 请求方法_请求地址_query数据 做md5值作为缓存key , 这里 默认只有读请求会涉及缓存, 所以只对query进行处理, 如果涉及写请求缓存, 需要特事特办
设置缓存值
上方已经归还了获取缓存时长与生成缓存key的方法, 基于选择的数据缓存的中间件服务, 直接将数据写入即可.
获取缓存值
在请求发送之前, 根据缓存key获取缓存的数据, 如果数据已存在直接将缓存数据返回即可.
缓存预热
缓存预热在实际业务开发中, 很少看到有使用, 对于单一业务系统还好, 但是网关理论上结果所有业务接口, 可能包含很多路径访问到同一个接口, 加之其本身流量很大, 此时缓存预热就有意义了, 尽最大可能保证了热点接口每次访问均是通过缓存读取数据, 加快访问速度, 同时也大大降低后端服务的访问压力
缓存剩余时长
缓存剩余时长是用来获取缓存还有多长时间过期, 单位: s, 用于判断当前缓存是否需要预热, 以及预热的频率.
预热配置
预热配置的整体是为了计算出一个数值, 该数值的含义是: 缓存剩余有效时长低于多少时, 触发预热
, 预热配置的数据结构如下:
// CachePreHeatConfig 缓存预热配置, MinPercent / MinTTL 同时配置, 则任意一个满足, 均进行预热
type CachePreHeatConfig struct {
Enable bool `json:"enable"` // 缓存预热是否可用
MinPercent int64 `json:"min_percent"` // 最小百分比, 剩余有效期低于此百分比进行预热
MinTTL int64 `json:"min_ttl"` // 最小剩余生命周期, 低于此百分比进行预热
Force bool `json:"force"` // 启用预热的情况下, 强制预热, 会忽略 MinPercent / MinTTL 的配置
}
预热锁
在缓存将过期未过期时, 会存在大量请求访问, 在已经对外返回数据之后, 相关请求均会触发缓存预热。但是, 实际上, 缓存预热策略仅触发一次即可
, 因此需要有一把锁来控制, 保证仅有锁的持有者有权限预热缓存.
预热锁的生成规则复用 CacheKey 的规则, 具体规则为: {{CACHE_KEY}}_LOCK, 明确设置为某个缓存key加锁
接口约束
// ICache 缓存定义
type ICache interface {
// Enable 是否启用缓存(总开关)
Enable() bool
// CacheTime 缓存时长, 单位 : s , 默认 1800, 最小值 90, 设置失效时间, 会上下波动60s, 避免缓存集中失效
CacheTime() int64
// IsAllow 针对当前请求数据和状态, 是否允许缓存
IsAllow(reqCfg *define.Request, response *define.Response) bool
// GetKey 获取缓存key
GetKey(reqCfg *define.Request) string
// GetValue 获取缓存值
GetValue(cacheKey string) string
// SetValue 设置缓存
SetValue(cacheKey string, cacheValue string) error
// TTL 缓存剩余生命周期(单位: s)
TTL(cacheKey string) int64
// PreHeatConfig 缓存预热配置
PreHeatConfig() *define.CachePreHeatConfig
// Lock 设置缓存时加锁
Lock(lockKey string) error
// Unlock 完成缓存设置时, 释放锁
Unlock(lockKey string) error
}