首页
文章
留言
首页
文章
留言
Redis缓存击穿、穿透、雪崩
2016 年 12 月 03 日
后端
运维
Redis
#### 一、缓存穿透 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,这时的用户很可能是攻击者,攻击会导致数据库压力过大。 **解决方案:** 1、接口层增加校验,如用户鉴权校验,id 做基础校验,id<=0 的直接拦截。 2、从缓存取不到的数据,在数据库中也没有取到,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个 id 暴力攻击。 缓存空对象会有两个问题: 第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。 第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。 #### 二、缓存击穿 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),在高并发下,对一个特定的值进行查询,但是这个时候缓存正好过期了,缓存没有命中,导致大量请求直接落到数据库上。 **解决方案:** 1、加互斥锁。 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待。 业界比较常用的做法,是使用 `mutex`。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去读数据库,而是先使用缓存工具的某些带成功操作返回值的操作(比如 Redis 的 SETNX 或者 Memcache 的 ADD)去 `set` 一个 `mutex` key,当操作返回成功时,再进行读数据库的操作并回设缓存;否则,就重试整个 `get` 缓存的方法。 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。 2、缓存永远不过期 这里的 “永远不过期” 包含两层意思: (1) 从缓存上看,确实没有设置过期时间,这就保证了,不会出现热点 key 过期问题,也就是 “物理” 不过期。 (2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在 key 对应的 value 里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是 “逻辑” 过期. 从实战看,这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,但是对于一般的互联网功能来说这个还是可以忍受。 3、布隆过滤( Bloom filter) 对所有可能查询的参数以 `hash` 形式存储,在控制层先进行校验,不符合则丢弃。还有最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。 #### 三、缓存雪崩 如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。 这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。 **解决方案:** 1、加互斥锁。 2、取一定范围内随机数作为缓存时间。 3、缓存永远不过期。 4、做二级缓存,或者双缓存策略。 A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。
7
相关文章
PHP常用函数总结
Nginx常用配置说明
Redis基本使用总结
PHP使用Kafka
Linux命令总结
全部分类
前端
后端
运维
架构
算法
数据库
移动应用
桌面应用
程序开发
热门标签
爬虫
Qt
Elasticsearch
Kubernetes
NoSQL
Sphinx
Kafka
GUI
Composer
CSS
Objective-C
MongoDB
多线程
HTML
Python
Docker
Linux
macOS
Supervisor
C++
CentOS
Nginx
Git
MySQL
OpenResty
Lua
JavaScript
Redis
iOS
Android
PHP
Shell
热门文章
Redis、MemCache、MongoDB比较
macOS常用命令
Nginx常用配置说明
OpenResty+Lua+Kafka收集日志
Elasticsearch详解
Supervisor使用总结
Git使用总结
CentOS常用命令总结
Qt实现TCP通讯
HTML5常用特性总结