目录
一.Redis性能管理
1.Info Memory——查看Redis内存使用
2.内存碎片率
3. 内存使用率
4.内存回收key
二.缓存的穿透,击穿和雪崩
1.缓存的穿透
1.1 问题描述
1.2 缓存穿透发生的条件
1.3 缓存穿透发生的原因
1.4 解决方案
2 缓存的击穿
2.1 问题描述
2.2 缓存击穿的现象
2.3 解决方案
3 缓存雪崩
3.1 问题描述
3.2 解决方案
三.总结
一.Redis性能管理
1.Info Memory——查看Redis内存使用
2.内存碎片率
- 操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存总量值 used_memory 计算得出。
- 内存值 used_memory_rss 表示该进程所占物理内存的大小,即为操作系统分配给 Redis 实例的内存大小。
- 除了用户定义的数据和内部开销以外,used_memory_rss 指标还包含了内存碎片的开销, 内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)。
举例来说:Redis 需要分配连续内存块来存储 1G 的数据集。如果物理内存上没有超过 1G 的连续内存块, 那操作系统就不得不使用多个不连续的小内存块来分配并存储这 1G 数据,该操作就会导致内存碎片的产生
跟踪内存碎片率对理解Redis实例的资源性能是非常重要的。
●内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低,也说明 Redis 没有发生内存交换。
●内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。需要在redis-cli工具上输入shutdown save 命令,让 Redis 数据库执行保存操作并关闭 Redis 服务,再重启服务器。
●内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少 Redis 内存占用。
3. 内存使用率
redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换。
避免内存交换发生的方法
- 针对缓存数据大小选择安装 Redis 实例
- 尽可能的使用Hash数据结构存储
- 设置key的过期时间
4.内存回收key
内存清理策略,保证合理分配redis有限的内存资源。
当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除。
配置文件中修改 maxmemory-policy 属性值:
vim /etc/redis/6379.conf
sed -n '598p' /etc/redis/6379.conf
maxmemory-policy noenviction
- volatile-lru:使用LRU算法从已设置过期时间的数据集合中淘汰数据(移除最近最少使用的key,针对设置了TTL的key)
- volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰(移除最近过期的key)
- volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰(在设置了TTL的key里随机移除)
- allkeys-lru:使用LRU算法从所有数据集合中淘汰数据(移除最少使用的key,针对所有的key)
- allkeys-random:从数据集合中任意选择数据淘汰(随机移除key)
- noenviction:禁止淘汰数据(不删除直到写满时报错)
二.缓存的穿透,击穿和雪崩
1.缓存的穿透
1.1 问题描述
key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源(数据库),从而可能压垮数据源。比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
1.2 缓存穿透发生的条件
- 应用服务器压力变大
- redis 命中率降低
- 一直查询数据库,使得数据库压力太大而压垮
1.3 缓存穿透发生的原因
黑客或者其他非正常用户频繁进行很多非正常的 url 访问,使得 redis 查询不到数据库。
1.4 解决方案
①对空值缓存
- 如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
②设置可访问的名单(白名单)
- 使用 bitmaps 类型定义一个可以访问的名单,名单 id 作为 bitmaps 的偏移量,每次访问和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问。
③采用布隆过滤器
- 布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量 (位图) 和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
④进行实时监控
- 当发现 Redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
2 缓存的击穿
2.1 问题描述
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮。
2.2 缓存击穿的现象
数据库访问压力瞬时增加,数据库崩溃 redis 里面没有出现大量 key 过期 redis 正常运行 缓存击穿发生的原因:redis 某个 key 过期了,大量访问使用这个 key(热门 key)
2.3 解决方案
key 可能会在某些时间点被超高并发地访问,是一种非常 “热点” 的数据。
①预先设置热门数据
- 在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长。
②实时调整
- 现场监控哪些数据热门,实时调整 key 的过期时长。
③使用锁
- 就是在缓存失效的时候(判断拿出来的值为空),不是立即去 load db。 先使用缓存工具的某些带成功操作返回值的操作(比如 Redis 的 SETNX)去 set 一个 mutex key。 当操作返回成功时,再进行 load db 的操作,并回设缓存,最后删除 mutex key;当操作返回失败,证明有线程在 load db,当前线程睡眠一段时间再重试整个 get 缓存的方法。
3 缓存雪崩
3.1 问题描述
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮。
缓存雪崩与缓存击穿的区别在于这里针对很多 key 缓存,前者则是某一个 key 正常访问。
3.2 解决方案
①构建多级缓存架构
- nginx 缓存 + redis 缓存 + 其他缓存(ehcache 等)。
②使用锁或队列
- 用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上,该方法不适用高并发情况。
③设置过期标志更新缓存
- 记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际 key 的缓存。
④将缓存失效时间分散开
- 比如可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
三.总结
缓存问题 | 产生原因 | 解决方案 |
---|---|---|
缓存雪崩 | 大量缓存失效,导致数据库过载 | 1. 分散缓存失效时间 2. 多级缓存 3. 缓存高可用 4. 服务降级限流 |
缓存穿透 | 查询不存在的数据,导致数据库过载 | 1. 布隆过滤器 2. 空值缓存 |
缓存击穿 | 热点数据失效,导致数据库过载 | 1. 热点数据永不过期 2. 使用互斥锁 |