在面向公众的业务线中,一篇关于特定心理健康话题的热门科普文章,往往会在短时间内迎来巨大的访问流量。如果后端系统仅依靠传统的 SQL 语句直连数据库(例如 SELECT * FROM article WHERE id = X)来提供服务,底层关系型数据库很容易在瞬间的读请求高峰下达到性能瓶颈。
为了缓解数据库压力,开发人员通常会在架构中引入 Redis 作为中间缓存层。然而,在面对高并发请求时,简单的缓存读写逻辑容易暴露出系统脆弱的一面。应对缓存雪崩、穿透与击穿等典型高可用问题,需要后端工程师进行更加细致的防御设计。
随机过期策略应对缓存雪崩
在批量初始化或预热热门心理文章缓存时,如果使用统一的固定过期时间,例如:redisTemplate.set(articleKey, data, 3600, TimeUnit.SECONDS);
这将导致大量文章的缓存在未来的同一时刻集体失效。此时,庞大的并发请求会发现缓存未命中,进而全部转向底层 MySQL 数据库发起查询。这种瞬间的流量洪峰被称为“缓存雪崩”,极易造成数据库资源耗尽甚至宕机。
在基础过期时间上增加随机偏移,有助于分散批量失效,但仍需监控回源压力,并为缓存整体故障准备限流与降级。
布隆过滤器阻断缓存穿透
不存在的文章ID如果不缓存空结果,可能反复触发数据库查询。可先检查参数,再按业务设置短时空值缓存;同时注意新增内容与空值缓存的一致性。
为了防范此类资源消耗攻击,在网关层或 Redis 之前引入布隆过滤器(Bloom Filter)是一种高效的解决方案。系统启动时,将已有真实文章的 ID 经过多次哈希运算映射到位图(BitMap)中。当接到访问请求时,布隆过滤器能快速计算并验证该 ID 的合法性。如果判定 ID 绝对不存在,则直接拦截请求并返回 404 响应,有效切断了恶意请求对后端数据库的扫描。
互斥锁控制缓存击穿
当某篇拥有极高访问量的现象级文章刚好到达缓存过期时间的临界点,可能存在数以千计的并发请求在同一时刻发现 Redis 缓存为空。这些线程如果同时回源查询数据库,试图获取最新数据并回填缓存,会造成瞬间的局部过载,这便是典型的“缓存击穿”问题。
一种控制热点回源的设计,是为同一缓存键设置互斥锁。取得锁后先再次检查缓存,再查询并回填;锁应设置合理租期与唯一持有者标识,释放时验证归属。未取锁的请求采用有上限的等待或降级,避免无限重试。效果仍需通过并发和故障测试验证。
