架构师修行录

缓存设计规范

鹿Sir上线,见字如面。

在高并发系统中,缓存是提升性能的“王牌武器”——它能将数据库的毫秒级查询压缩到微秒级,轻松扛住流量洪峰。但不少团队在使用缓存时,常会踩中雪崩、穿透、击穿的“深坑”,甚至因缓存滥用导致系统OOM。

今天我们就从实战角度,梳理缓存设计的核心逻辑、使用规范及避坑技巧。

Image

0x1

缓存该用在什么场景?

不是所有数据都适合放缓存,盲目使用反而会增加系统复杂度。以下5类场景是缓存的“最佳阵地”,覆盖90%的业务需求:

  1. 静态数据:字典表、配置项等“一成不变”的数据这类数据几乎不发生变更,缓存命中率能达到100%。比如系统中的字典表(性别、学历枚举)、地区行政区划数据、固定的业务配置(如折扣比例阈值)。建议直接用本地缓存+分布式缓存的二级缓存架构,最大化提升性能。

  2. 准静态数据:变化频率极低的数据比静态数据多了“偶尔变更”的特性,比如部门组织架构、用户角色权限(通常按天更新)。这类数据可设置较长的过期时间,配合“变更时主动更新缓存”的策略,既保证性能又兼顾一致性。

  3. 中间状态数据:可复用的计算结果、临时副本复杂业务逻辑的中间计算结果,若多次复用可缓存减少重复计算。比如大数据报表的中间统计结果、配置中心的本地副本(减少远程拉取次数)。这类数据需关注有效期,避免因源数据变更导致计算结果失效。

  4. 热数据:短时间内被高频访问的数据高并发场景的核心诉求,比如大促时的爆款商品信息、热门活动页面数据。建议用“本地缓存拦截高频请求+分布式缓存兜底”的模式,本地缓存设置秒级过期时间,防止缓存不一致。

  5. 读写比极高的数据:读频率远大于写频率缓存的核心优势是提升读性能,若写操作过于频繁,缓存维护成本会超过收益。典型场景如商品详情页(读:写≈1000:1)、用户个人资料(读:写≈100:1);反例如订单表(读写比接近1:1),不适合缓存。

禁忌场景提醒:1. 变动频率高的数据(如实时交易金额):缓存与数据库一致性难维护,易引发业务错误; 2. 一致性要求高的数据(如支付状态):必须依赖数据库事务,缓存无法保证强一致。

0x2

缓存有效性的5个核心指标

缓存上线后不是“一劳永逸”,需通过监控及时发现问题。以下5个指标是缓存健康度的“体温计”:

  1. 命中率:缓存有效性的核心指标计算公式:命中率=缓存命中次数/(缓存命中次数+缓存未命中次数)。命中率越高,缓存价值越大——静态字典表需达到100%,热数据建议≥95%。若命中率过低,需排查是否场景选错(如写频过高)或key设计不合理(如key粒度太细)。

  2. 读写比:判断缓存性价比的关键计算公式:读写比=读请求次数/写请求次数。建议读写比≥10:1再使用缓存,否则写操作带来的缓存更新成本(如删除/刷新)会抵消读性能收益。

  3. 过期时间:控制缓存规模的“阀门”除静态数据外,绝大部分缓存需设置过期时间,防止缓存无限增长导致OOM。长期有效的数据(如字典表),建议用定时任务定时刷新或事件触发更新,避免永久缓存堆积。

  4. 占用空间:避免资源耗尽的“红线”上线前需预估缓存空间,运维据此分配资源;上线后关注单key平均大小和总占用。重点警惕Redis集合对象(map、list等)和本地缓存的key数量——本地缓存若用集合对象存value,即使限制了key数,也可能因value过大导致OOM。

  5. 读写耗时:警惕缓存成为新瓶颈正常缓存读写耗时应在几毫秒级,若超过10毫秒需紧急排查:Redis可能存在bigkey阻塞、网络延迟过高,或本地缓存锁竞争严重。

0x3

缓存三大核心问题解决方案

缓存雪崩、击穿、穿透是高并发场景的“老三样”问题,一旦发生可能导致系统雪崩。以下是经过实战验证的解决方案:

1
缓存雪崩:大量缓存同时过期导致数据库压垮

场景:大促零点,大量商品缓存同时过期,所有请求直达数据库,导致数据库连接耗尽。

解决方案:

  1. 过期时间打散:设置过期时间时加随机值,比如基础过期时间30分钟,再加0-5分钟随机值,避免大量key同时过期。代码示例:expireTime = 30*60 + Random.nextInt(300)。

  2. 加锁防重复回源:缓存未命中时,用分布式锁(如Redis的setNx)控制只有一个请求去数据库回源,其他请求等待缓存更新后再读取。注意加锁后先检查缓存是否已存在,避免拿到锁后重复回源。

  3. 热点数据永不过期:对核心热点数据(如大促爆款)设置永不过期,通过后台定时任务刷新或数据变更时主动更新,避免过期触发回源。

2
缓存击穿:热点数据过期导致单点压力

场景:某爆款商品缓存过期瞬间,数万请求同时查询该商品,直达数据库导致单表查询压力骤增。

解决方案:

  1. 热点数据特殊处理:设置热点数据过期时间为业务低峰期(如凌晨3-5点),或直接设置永不过期,通过主动更新维持一致性。

  2. 互斥锁+短暂兜底:缓存未命中时,加锁回源并设置临时缓存(如10秒过期),其他请求先返回临时缓存,避免同时冲击数据库。

3
缓存穿透:缓存和数据库都无数据导致恶意攻击

场景:黑客用不存在的用户ID批量请求,缓存未命中后直达数据库,导致数据库空查风暴。

解决方案:

  1. 前置校验+风控:接口层增加参数校验(如用户ID格式校验),结合风控系统拦截恶意IP,从源头减少非法请求。

  2. 缓存空值/默认值:数据库查询为空时,缓存空值或默认值(如空对象),并设置较短过期时间(如5分钟),避免缓存空值堆积。数据插入时需主动删除或更新缓存。

  3. 布隆过滤器拦截:将数据库所有存在的key(如用户ID、商品ID)预载入布隆过滤器,请求先经过过滤器判断,不存在则直接返回,无需查询缓存和数据库。布隆过滤器误判率可控制在0.1%以下,且占用空间极小。

0x4

缓存落地细则

不同缓存类型的适用场景和规范不同,以下是本地缓存(如Caffeine)和Redis缓存的强制规范,覆盖90%的业务场景:

1
本地缓存规范:极致性能的“最后一公里”

本地缓存优势是毫秒级响应,缺点是容量小、多节点不一致,需严格控制使用场景和规模。

核心规范

【强制】空间上限控制:必须设置最大元素数量,防止OOM。value禁止使用集合对象或大对象,建议用简单数据类型(如String)。

【推荐】组件统一:全量本地缓存封装通用组件(预加载、定时更新);普通本地缓存用Caffeine,优先用注解实现,禁止重复造轮子。

【推荐】使用场景:小容量不常更新数据(如字典表)、热点数据短时间缓冲(如5秒过期的爆款商品信息),或proxy层减少RPC请求(如组合数据的短缓存)。

2
Redis缓存规范:分布式场景的“标配”

Redis是分布式缓存的核心,但滥用会导致性能问题甚至数据丢失,以下是必须遵守的强制规范:

一、基础原则

  1. 冷热数据分离,禁止将所有数据放入Redis;Redis不做持久化,不能当数据库用,必须有回源数据库的逻辑。

  2. 不同业务用key前缀区分(格式:{业务系统}:{模块}:{标识}),禁止跨业务直接调用缓存,需通过RPC接口中转。正例:system:common:custom-config-list;反例:直接用123当key。

  3. key长度≤100字符,用统一常量文件管理所有key,避免多处书写导致修改遗漏。

  4. 除特殊场景(如热点数据永不过期),所有key必须设置过期时间,无过期时间需组长审核。

二、bigkey治理

bigkey是Redis性能杀手,会导致阻塞、带宽占用过高,以下是判定标准和解决方案:

  • bigkey判定:String类型≥100KB、List/ZSET/HASH成员数≥5000,或HASH成员总大小≥100MB。

  • 解决方案:拆分bigkey——将一个大key拆分为多个小key,用MGET批量获取(注意key的slot分布和MGET数量≤200)。

  • 粉丝列表优化:大V粉丝列表不直接用List/ZSET,拆分为粉丝ID分片(如按用户ID取模),每个分片存部分粉丝ID,粉丝信息单独存储。查询时先分页取ID,再批量查信息。

  • 热点数据分级:仅预加载热点分页数据的前几页,后续数据按需加载,减少缓存体量。

三、命令与组件规范

  1. 禁用高危命令:线上禁止使用KEYS、FLUSHALL、FLUSHDB等阻塞或清数据的命令,扫描key用SCAN渐进式处理。

  2. 组件统一:二级缓存(本地+Redis)用mycache组件;避免循环中操作Redis,改用批量命令(如MGET、HMSET),批量操作key≤200或数据量≤2000KB。

  3. 回源耗时控制:回源逻辑复杂(如复杂SQL)时,延长缓存TTL至30分钟以上,或用“本地缓存+Redis”二级缓存;大促期间禁止回源,通过异步刷新维持缓存。

3
缓存一致性规范
  1. 数据库数据变更时(增删改),必须无条件删除或更新对应缓存,避免缓存脏数据。

  2. 二级缓存(本地+Redis)中,本地缓存TTL设为5-10秒,即使分布式缓存更新消息丢失,也能通过本地缓存过期保证最终一致。

  3. 热key更新用“更新缓存”策略+写入锁;非热key用“删除缓存”策略,查询时回源重建。

  4. 数据库主从分离场景,强一致需求需从主库回源写入缓存,避免从库延迟导致缓存脏数据。

0x5

缓存设计的核心逻辑

缓存设计不是“有缓存就好”,而是“合适的场景用合适的缓存”:

  • 场景优先:先判断数据是否符合“读多写少、热点、非强一致”三大特征,再决定是否用缓存;

  • 监控兜底:命中率、读写比、空间占用三大指标必须监控,提前发现问题;

  • 规范落地:本地缓存控容量、Redis控bigkey和key规范、一致性靠“变更必更缓存”,避免踩坑;

  • 分层防御:雪崩用过期打散+加锁、击穿用热点永不过期、穿透用布隆过滤器,三层防御保障系统稳定。

缓存是高性能系统的“加速器”,但只有遵循规范、精准落地,才能真正发挥其价值,而不是成为系统的“不定时炸弹”。

EOF

Image

关于鹿Sir「微信:Jensvn」

分享架构技术/IT资讯/牛马日常

电商/SaaS架构师/DDD极客,COLA-DDD/DDD4j框架作者

→关注公众号,撩小码鹿「已接入AI」

→加我备注“进群”,进技术大佬群学习