php empty null 缓存穿透、缓存击穿、缓存雪崩

php empty null 缓存穿透、缓存击穿、缓存雪崩

一、缓存穿透(Cache )定义:

大量请求查询 根本不存在的数据(如恶意攻击或参数错误),导致每次请求都绕过缓存直接打到数据库,造成 DB 压力剧增甚至崩溃。

示例:

// 用户查询 ID = -1 的订单
Order order = cache.get("order:-1"); // null
if (order == null) {
    order = db.queryById(-1); // DB 返回 null
    // 若不缓存 null,下次同样请求仍会查 DB
}

应对方案:1.缓存空值(Null )

String key = "order:" + id;
Order order = redis.get(key);
if (order != null) {
    return order; // 包括空值标记
}
order = db.getOrder(id);
if (order == null) {
    redis.setex(key, 60, EMPTY_PLACEHOLDER); // 如 "NULL"
} else {
    redis.setex(key, 3600, serialize(order));
}

️ 注意:需防止恶意构造海量不同无效 key 导致 Redis 内存爆炸(见下一点)。

2.布隆过滤器(Bloom )前置拦截

// 初始化时加载所有有效 ID 到 BloomFilter
BloomFilter validIds = BloomFilter.create(Funnels.longFunnel(), 1_000_000, 0.01);
// 查询时先判断
if (!validIds.mightContain(id)) {
    throw new IllegalArgumentException("Invalid ID");
}
// 否则继续走缓存/DB 流程

优点:内存占用小,查询 O(1)

缺点:存在误判(false ),不能删除元素(可用 Bloom 改进)

3.接口层校验 + 限流二、缓存击穿(Cache )定义:

某个 热点 key 在缓存过期瞬间,大量并发请求同时发现缓存失效,全部打到 DBphp empty null,造成瞬时压力高峰。

与穿透不同:击穿是 真实存在的热点数据,只是缓存刚好失效。

php empty null

应对方案:1.互斥锁(Mutex Lock)重建缓存

public Order getOrder(Long id) {
    String key = "order:" + id;
    Order order = redis.get(key);
    if (order != null && !isEmptyPlaceholder(order)) {
        return order;
    }
    // 尝试获取分布式锁(如 Redis SETNX)
    String lockKey = "lock:order:" + id;
    boolean locked = redis.setnx(lockKey, "1", 10); // 10s 过期防死锁
    if (locked) {
        try {
            // Double Check:可能其他线程已加载
            order = redis.get(key);
            if (order == null || isEmptyPlaceholder(order)) {
                order = db.getOrder(id);
                if (order != null) {
                    redis.setex(key, 3600, serialize(order));
                } else {
                    redis.setex(key, 60, EMPTY_PLACEHOLDER);
                }
            }
        } finally {
            redis.del(lockKey); // 释放锁
        }
    } else {
        // 等待一小段时间后重试(或直接返回旧数据/降级)
        Thread.sleep(50);
        return getOrder(id); // 递归重试(注意次数限制)
    }
    return order;
}

优点:保证只有一个线程查 DB

缺点:增加延迟php empty nullphp empty null 缓存穿透、缓存击穿、缓存雪崩,高并发下可能大量线程阻塞

2.逻辑过期( ) + 后台刷新

{
  "data": { ... },
  "expireTime": 1712345678
}

此方案避免了锁竞争,但实现稍复杂。

3.热点 key 永不过期(慎用)三、缓存雪崩(Cache )定义:

大量 缓存 key 在同一时间失效(如 Redis 宕机重启、批量设置相同 TTL),导致所有请求瞬间打到 DB,引发 DB 雪崩。

应对方案:1.TTL 随机化()

int baseTTL = 3600; // 1小时
int jitter = new Random().nextInt(300); // ±5分钟
redis.setex(key, baseTTL + jitter, value);

简单有效,推荐默认使用。

2.高可用架构3.熔断 & 降级4.预热缓存四、综合防护策略(Java 工程师 )

问题

推荐方案

补充措施

缓存穿透

空值缓存 + 布隆过滤器

参数校验 + 接口限流

缓存击穿

互斥锁重建 / 逻辑过期

php empty null

热点 key 永不过期(谨慎)

缓存雪崩

TTL 随机化 + Redis 高可用

多级缓存 + 熔断降级 + 预热

五、代码结构建议( Boot 示例)

@Service
public class OrderService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderMapper orderMapper;
    private static final String EMPTY = "NULL";
    private static final int CACHE_TTL_BASE = 3600;
    private static final int CACHE_TTL_JITTER = 300;
    public Order getOrder(Long id) {
        if (id == null || id <= 0) throw new IllegalArgumentException("Invalid ID");
        String key = "order:" + id;
        String cached = redisTemplate.opsForValue().get(key);
        if (EMPTY.equals(cached)) {
            return null; // 穿透防护
        }
        if (cached != null) {
            return deserialize(cached);
        }
        // 尝试加锁重建
        String lockKey = "lock:" + key;
        Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", Duration.ofSeconds(10));
        if (Boolean.TRUE.equals(locked)) {
            try {
                // Double-check
                cached = redisTemplate.opsForValue().get(key);
                if (cached == null) {
                    Order order = orderMapper.selectById(id);
                    if (order != null) {
                        int ttl = CACHE_TTL_BASE + new Random().nextInt(CACHE_TTL_JITTER);
                        redisTemplate.opsForValue().set(key, serialize(order), Duration.ofSeconds(ttl));
                        return order;
                    } else {
                        redisTemplate.opsForValue().set(key, EMPTY, Duration.ofSeconds(60));
                        return null;
                    }
                } else {
                    return deserialize(cached);
                }
            } finally {
                redisTemplate.delete(lockKey);
            }
        } else {
            // 短暂等待后重试(或降级)
            try { Thread.sleep(20); } catch (InterruptedException e) {}
            return getOrder(id); // 注意递归深度控制
        }
    }
}

总结

在 Cache-Aside 模式下,缓存穿透、击穿、雪崩 是必须系统性防御的问题。作为 Java 工程师php empty nullphp empty null 缓存穿透、缓存击穿、缓存雪崩,应:

通过组合策略,可在性能、一致性、可用性之间取得良好平衡。

公告:
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299

资源库 - 资源分享下载网 » php empty null 缓存穿透、缓存击穿、缓存雪崩

常见问题FAQ

关于资源售价和售后服务的说明?
本站所有资源的标价均为本站收集资源的辛苦费,不代表资源本身的价值。软件是高智慧高价值的商品,不可能是白菜价。本站资源标价只是赞助费用,收取的赞助费仅用来维持本站的日常运营!毕竟收集整理资料需要投入云计算资源和站长大量的精力。
代码有没有售后服务和技术支持?
由于代码的运行具有不可预见性,本站不保证代码完整可运行,不提供技术支持和售后服务。 本站原创代码都是站长自己开发的,可以有偿提供技术支持服务。 网站里标明【亲测】的代码都是站长亲测过的,其他的代码由于精力有限,没有一一测试,不能保证代码就一定能够使用,更没有技术支持服务,下载前请自行斟酌。
有没有搭建服务?
由于搭建服务比较费时费力,所以本站除了原创代码外均不提供搭建服务。本站分享代码纯属兴趣爱好,不以盈利为目的,请勿咨询有没有搭建服务,谢谢理解。
链接地址失效了怎么办?
请带上资源链接地址联系客服,工作时间内我们看到后将第一时间回复。
关于解压密码
本站资源一般都没有加密,如果发现需要解压密码的,那么就输入 hao.35dc.com 试试。

发表评论

资源库,由老程序员细心甄别、精心筛选,只为提供优质的源码资源

关于我们 联系我们