缓存穿透

  • 描述 向服务器端查询一个不存在的数据,redis缓存和数据库层均不能命中,导致每次请求都需要去数据库层去查询。
  • 解决方案
    • 缓存空对象
    • 布隆过滤器(存在时不一定存在,不存在时一定不存在) 先由布隆过滤器过滤一遍,基本可以解决缓存穿透问题。

缓存雪崩

  • 描述 大量缓存同一时间失效,有可能会导致大量请求同时穿透缓存去查询数据库,使数据库压力过大。
  • 解决方案 将缓存失效时间设置成 固定时间+随机时间, 比如: 100ms + random(100)

缓存击穿

  • 描述 数据存在于数据库中,但不存在于缓存中,通常是因为缓存中的那份数据已经过期。
  • 解决方案
    • 设置热点数据永远不过期
    • 加互斥锁

热key问题

  • 描述 抢购场景下(比如小道消息获取到商品值得购买),大量请求同时访问同一数据,因缓存不存在,请求直接访问到数据库层。
  • 解决方案 使用redis的分布式锁解决, 只允许一个线程去重建缓存。
# 伪代码
public String getData(String key) {
    String data = getCache(key);
    if (null == data) {
        if (getLock(key)) {
            data = queryDB(key);
            saveCache(data);
            freeLock(key);
        } else {
            sleep(20);
            data = getData(key);
        }
    }
    return data;
}

缓存和数据库双写不一致

  • 两种情况:

caseA caseB

  • 解决方案(需要强一致性)
    • 使用读写锁
    • 使用canal监听数据库的binlog及时修改缓存

bigkey问题

  • 描述 指value占用的内存空间比较大。字符串类型最大为512m,其他数据类型最多存储2^32 - 1个元素。 字符串大小大于10Kb或者其他数据类型元素个数超过5000就认为是bigkey
  • 危害
    • 造成redis阻塞
    • 网络拥塞
    • 过期删除时会导致redis阻塞, 采用渐进式(hscan, sscan, zscan)删除。