1. Redis-缓存穿透

缓存穿透是指访问缓存和数据库都不存在的数据,未命中缓存时需要从数据库查询,数据库中也没有对应的数据则也不会写入缓存。这类请求始终都会去数据库查询,如果请求的量过大或存在恶意攻击,会导致数据库压力过大甚至崩溃。

image-20240921002532423

正常来说,用户不会频繁的去访问不存在数据,如果存在这种情况,很有可能是受到了恶意攻击,除了在服务外部做好安全防护外,服务内部也需要做一些处理措施。

2.解决方案

2.1 缓存空对象:

当数据库查询不到数据时,可以将一个空对象或者特定的标记存入缓存,并设置一个较短的过期时间。这样,下次相同请求就可以直接从缓存中获取数据,避免对数据库的访问。例如,在Java中可以使用以下代码实现:

public String getProductInfo(String productId) {
    String cacheKey = "product:" + productId;
    String productInfo = redisTemplate.opsForValue().get(cacheKey);
    if (productInfo != null) {
        return productInfo;
    }
    // 查询数据库
    Product product = productRepository.findById(productId);
    if (product == null) {
        // 数据库中不存在,缓存空值
        redisTemplate.opsForValue().set(cacheKey, "", 60, TimeUnit.SECONDS);
        return null;
    }
    // 存在,缓存数据
    redisTemplate.opsForValue().set(cacheKey, product.toString(), 10, TimeUnit.MINUTES);
    return product.toString();
}

2.2 布隆过滤器:

布隆过滤器是一种数据结构,用于判断一个元素是否在一个集合中。它可以在查询前先判断数据是否存在,如果不存在就直接返回,避免无用的查询。布隆过滤器可以减少内存占用并且提高判断效率,但存在一定的误判率。

2.3 参数校验:

对用户输入进行校验,确保只有合法的请求才会查询数据库。

2.4 限流和降级:

在系统层面对请求进行限流,对数据库进行保护,避免过多无效请求对数据库造成压力。

2.5 使用Redis的分布式锁:

在缓存失效时,使用分布式锁确保只有一个请求去数据库查询数据并回写缓存,其他请求等待或重试。