缓存击穿的解决方案

1.加锁

互斥锁

java 复制代码
// 缓存不存在
if (cache == null) {
    // 尝试获取分布式锁,比如setnx
    if (lock("lock:goods:1001")) {
        try {
            // 查DB
            data = db.query();
            // 回写缓存
            redis.set(key, data, expire);
            return data;
        } finally {
            unlock();
        }
    } else {
        // 没抢到锁,短暂休眠后重试
        sleep(50ms);
        return getGoodsFromCache();
    }
}

区分 互斥锁 & X锁

这里的互斥锁指在redis加分布式锁:

复制代码
SET lock:goods:1001 唯一标识 NX EX 过期时间

这里边的lock()是包装了redis里面加锁的命令

解锁不能随便解锁随便DEL,必须 Lua 脚本原子校验 + 删除:

Lua 复制代码
-- 判断value是自己的,才删
if redis.call('get',KEYS[1]) == ARGV[1] then
    return redis.call('del',KEYS[1])
else
    return 0
end

2.逻辑过期

物理上不设置 TTL,在 value 里存逻辑过期时间,后台异步更新

java 复制代码
CacheItem item = redis.get(key);
if (item == null) {
    // 兜底,初始化
    if (lock()) {
        data = db.query();
        redis.set(key, new CacheItem(data, now+30s));
        unlock();
    }
    return redis.get(key).data;
}
// 判断逻辑过期
if (item.expireTime < now) {
    if (tryLock()) {
        // 异步线程更新,主线程直接返回旧值
        threadPool.submit(() -> {
            newData = db.query();
            redis.set(key, new CacheItem(newData, now+30s));
            unlock();
        });
    }
}
return item.data;

3.提前刷新

定时任务提前刷新

适合:热点固定、能提前预知的 key(首页爆款商品)

缺点:资源占用高;热点不固定时很难覆盖

4.限流(不推荐:单纯延长过期时间,只能缓解,不能根治,依然有击穿风险)

对该热点接口加单机 / 分布式限流,一旦检测到缓存失效,限制 QPS,保护数据库。一般配合上面方案一起用,不作为主方案。

相关推荐
code2cat1 天前
【随笔】KV缓存卸载:逐层预取能藏住多少传输时间
人工智能·缓存·大语言模型
AI技术新视界2 天前
LLM 提示词缓存(Prompt Caching)的秘密
人工智能·缓存·llm·prompt
lsc_blog3 天前
年底还在招的岗位,先确认缺口和到岗要求
git·缓存·ci/cd·职场和发展·github
xixiaoyunya3 天前
Redis缓存三大问题实战:穿透、击穿、雪崩,我用一个电商秒杀场景讲清楚
数据库·redis·缓存
我不会起名字3223 天前
Redis 从 0 到 1(二十三):一个热 key 打到 10 万 QPS——hotkey 与本地缓存的 Go 实现
redis·缓存·go·qps·hotkey
真上帝的左手4 天前
30. 技术专题-‌应用框架组件-缓存-Redis
数据库·redis·分布式·缓存·中间件
bksczm4 天前
C++Redis开发(Ubuntu 22.04)
数据库·redis·缓存