首页
文章
留言
首页
文章
留言
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
相关文章
Linux命令总结
PHP常用函数总结
Redis基本使用总结
Redis、MemCache、MongoDB比较
Kafka使用总结
全部分类
前端
后端
运维
架构
算法
数据库
移动应用
桌面应用
程序开发
热门标签
MongoDB
PHP
Lua
Kubernetes
HTML
Sphinx
NoSQL
Python
Composer
CSS
OpenResty
iOS
GUI
CentOS
多线程
MySQL
Nginx
Android
Linux
Redis
Objective-C
Elasticsearch
JavaScript
Git
Qt
macOS
Shell
Docker
爬虫
Supervisor
Kafka
C++
热门文章
C/C++基础知识总结
10种常见的软件架构模式
Git使用总结
Kubernetes介绍
macOS常用命令
OpenResty+Lua+Kafka收集日志
Elasticsearch详解
Nginx常用配置说明
Supervisor使用总结
Docker使用总结