Skip to content

缓存击穿

某一个热点数据失效的一瞬间,大量请求同时访问数据库。

什么是热点数据?

例如:

商品 1001 是一个秒杀商品,每天要承受100万次访问。

Redis goods:1001 缓存 30分钟

正常情况

用户

Redis

返回

数据库几乎没压力。

但,当某一时刻 goods:1001 过期了 TTL = 0 这时 10000个请求同时到了

流程:

请求1 → Redis没有
请求2 → Redis没有
请求3 → Redis没有
...
请求10000 → Redis没有

于是这10000个请求都访问了数据库,数据库瞬间压力暴涨。

这就是

缓存击穿

为什么叫击穿?

正常:

请求

Redis

数据库

Redis 像一堵墙。而热点 Key 过期后:

大量请求

穿透这一点

数据库

就像是墙上被打了一个洞。

举个栗子

腾讯云特价服务器每天 10 点有秒杀。

如果这个服务器的Redis正好在十点失效了,而这时大量的请求同时发送,结果就是数据库瞬间访问暴涨,甚至可能挂掉。

解决方案

  • 互斥锁
  • 分布式锁
  • 逻辑过期
  • 热点数据永不过期

方案1:互斥锁(最常见)

流程:

Redis没有

抢锁

只有一个线程成功获取到锁,其他线程阻塞等待。

假如 线程A 抢到了锁,那么它接下来:

查数据库

写Redis

释放锁

其他线程等待,直到 线程A 释放锁后,他们会重查 Redis。

流程:

10000个请求

Redis没有

竞争锁

A线程获得锁

查数据库

写Redis

释放锁


其它9999线程

重新查Redis

直接返回

在这个流程下,数据库只查了1次。

JAVA示例

java
synchronized (key.intern()) {

    User user = redis.get(key);

    if (user != null) {
        return user;
    }

    user = mapper.selectById(id);

    redis.set(key, user);

    return user;
}

逻辑过期

一般大型系统可能会用

缓存:

json
{
    "data": {...},
    "expireTime":"2026-06-24 12:00:00"
}

即使过期也先返回旧数据,用户得到旧数据,后台线程更新缓存。

优点:不会大量请求数据库

缺点:短时间数据不一致