单个键访问过于集中和单个值过大,是不同的压力来源,处理方式不能混用。
本文使用Redis 3.0 与 Java 应用,代码为协议命令或流程示意。缓存保存的是可重建视图还是关键状态,决定了失效和故障时的处理。本文先以数据库为权威来源,不把缓存命中等同于业务事实已经确认。
1. 从现象推到机制
热键主要聚集请求与带宽,大值则增加传输、序列化和某些操作的阻塞成本。平均键大小或总体命中率可能掩盖极少数异常键。应用本地副本能分摊读取,但又引入独立失效和内存管理。
图中的四个节点分别表示访问分布、数据体积、成本分解、优化选择。顺着实线检查输入如何变成输出,再沿虚线核对反馈条件。图示表达的是本文讨论的关系,不是实测曲线或现场截图。
2. 最小实现与输入条件
按键类别记录访问频率和字节数,避免在高负载实例上执行全量重扫描。先抽样定位,再评估拆分、压缩或本地短缓存。
1
2
3
4
5
6
measure per category:
operations_per_second
response_bytes
serialization_time
value_size_distribution
# 不把全部真实键名写入公共报告
在独立实例准备演示键,观察命中、过期和数据库回源次数。键包含必要的业务作用域,日志与指标避免记录完整敏感值,缓存故障路径也要能验证。
3. 用对照区分原因
下表列出需要主动改变的条件。预期行为来自机制分析,复现时还需记录运行环境和原始输出,不能将预期当作已经测得的结果。
| 改变的条件 | 需要验证的行为 |
|---|---|
| 值很小但请求极多 | 瓶颈可能在集中访问与网络 |
| 单值很大且偶尔访问 | 仍可能造成较长传输和处理 |
| 加入本地缓存 | 需要单独处理失效与容量 |
对照 1:值很小但请求极多
瓶颈可能在集中访问与网络。观察时记录频率和总传输量。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。
对照 2:单值很大且偶尔访问
仍可能造成较长传输和处理。观察时记录单次字节数与操作耗时。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。
对照 3:加入本地缓存
需要单独处理失效与容量。观察时记录本地命中和陈旧窗口。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。
4. 适用条件与取舍
优化先保留业务粒度。随意拆分一个需要原子读取的值,会增加多次读取和一致性问题,不能只按字节大小判断。
一次正常运行只覆盖了这组输入。继续扩展前,应把上面的异常对照保留下来,尤其关注“加入本地缓存”这一分支。后续方案若改变了图中任意一处依赖,原来的判断就要重新验证,不能仅凭界面相似或返回值相同沿用结论。