--- 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,同时异步去更新缓存,但是更新的时候需要同时更新两个缓存。