---
# System prepended metadata

title: 緩存穿透、緩存雪崩
tags: [infrastructure]

---

---
title: 緩存穿透、緩存雪崩
---

# 緩存穿透、緩存雪崩
###### tags: `infrastructure`

## 一、緩存穿透
缓存穿透是指，缓存和数据库都没有的数据，被大量请求，比如订单号不可能为-1，但是用户请求了大量订单号为-1的数据，由于数据不存在，缓存就也不会存在该数据，所有的请求都会直接穿透到数据库。
如果被恶意用户利用，疯狂请求不存在的数据，就会导致数据库压力过大，甚至垮掉。

那对于这种情况，我们该如何解决呢？

1. 將DB搜尋過的數據緩存，設置TTL。 過程中可以利用互斥鎖令相同的請求等待將完成緩存後解鎖。 如果是热点数据，那么可以考虑设置永远不过期。
2. 另外一个常见的方法，则是针对数据库与缓存都没有的数据，对空的结果进行缓存，但是过期时间设置得较短，一般五分钟内。而这种数据，如果数据库有写入，或者更新，必须同时刷新缓存，否则会导致不一致的问题存在。
3. 接口增加业务层级的Filter，进行合法校验，这可以有效拦截大部分不合法的请求。
4. 常见的是使用布隆过滤器，针对一个或者多个维度，把可能存在的数据值hash到bitmap中，bitmap证明该数据不存在则该数据一定不存在，但是bitmap证明该数据存在也只能是可能存在，因为不同的数值hash到的bit位很有可能是一样的，hash冲突会导致误判，多个hash方法也只能是降低冲突的概率，无法做到避免。 bloom filter [可參考這篇實作](https://hackmd.io/So7yJIlXTi2nDfMJqY2lhQ#Bloom)

## 二、緩存雪崩
缓存雪崩是指缓存中有大量的数据，在同一个时间点，或者较短的时间段内，全部过期了，这个时候请求过来，缓存没有数据，都会请求数据库，则数据库的压力就会突增，扛不住就会宕机。

针对这种情况，一般我们都是使用以下方案：

1. 如果是热点数据，那么可以考虑设置永远不过期。
2. 缓存的过期时间除非比较严格，要不考虑设置一个波动随机值，比如理论十分钟，那这类key的缓存时间都加上一个1~3分钟，过期时间在7~13分钟内波动，有效防止都在同一个时间点上大量过期。
3. 方法1避免了有效过期的情况，但是要是所有的热点数据在一台redis服务器上，也是极其危险的，如果网络有问题，或者redis服务器挂了，那么所有的热点数据也会雪崩（查询不到），因此使用redis cluster也可以有效减少这种情况。
4. 也可以考虑双缓存的方式，数据库数据同步到缓存A和B，A设置过期时间，B不设置过期时间，如果A为空的时候去读B，同时异步去更新缓存，但是更新的时候需要同时更新两个缓存。