深入探讨redis:缓存

目录

什么是缓存

使用redis作为mysql的缓存

缓存的更新策略

定期生成

实时生成

缓存预热

缓存穿透

缓存雪崩

缓存击穿(瘫痪)


什么是缓存

缓存的核新思路就是把⼀些常用的数据放到触手可及(访问速度更快)的地方,方便随时读取

比如我们一般都把钱存在银行,并且会拿出一部分出来放在自己的钱包里用来日常开销,那么这个钱包就相当于银行的缓存,我们为了不每次用钱的时候都去银行取,所以用个钱包在钱包里放一部分钱要使用的时候直接从钱包里拿(不考虑电子支付)。

对计算机来说,速度往往和存储空间是成反比的,访问速度越快存储空间越小,redis是读内存的访问速度要比Mysql快但空间也比mysql小很多,所以一般缓存里只会放一些(热点数据)会频繁访问的数据。虽然只放一些热点数据,但是也已经能应付大部分的情况了。

二八定律

这是一个经验规律,就是20%的热点数据能够应付80%的访问场景,所以只需要把少量热点数据用缓存存储起来,就可以应对大多数场景了。

使用redis作为mysql的缓存

像mysql这样的关系型数据库,虽然功能强大但是效率一般不高,处理并发能力也较弱因为

  1. 数据库会把数据存储在硬盘,存硬盘的访问速度要远小于存内存
  2. 如果查询不能命中索引,就要进行表遍历,大大增肌IO次数。
  3. 关系型数据库会对sql的执行做一系列的解析,校验,优化等。
  4. 一些联合查询比如需要进行笛卡尔积的操作,更是会降低效率

如果某一时刻并发量太大超过了数据库所能承担的极限,那么数据库的压力就会很大就容易出问题。想要提高数据库的并发量有两种方法

  • 开源:引入更多的机器
  • 节流:引入缓存,把一些热点数据放在缓存上分别查询。

而redis就具有很好的处理缓存的功能因为,redis的数据保存在内存上访问速度较快,而且redis只是简单的键值对存储,不会涉及复杂的查询规则,将redis用作mysql的缓存就可以很好的帮助mysql分担很大一部分并发量。

缓存的更新策略

定期生成

策略:每隔一定的周期(一天/一周/...),对于访问的数据的频率进行一个统计,挑选出前N%频率的数据作为热点数据保存在缓存中。

可以使用shell或python写一个脚本通过定时任务来触发

  1. 完成统计热热点数据
  2. 根据热点数据,找到对应的结果
  3. 把得到的缓存同步到缓存服务器上
  4. 控制这些缓存服务器重启

这种方法的优点就是,操作比较简单过程更为可控(缓存中有什么是比较固定的),方便排查问题

缺点就是,实时性不够,如果遇到一些突发事件,有一些数据突然变成热点数据,那么新的热点数据就有可能给数据库造成较大压力。

实时生成

策略:如果在redis中查到了就直接返回,如果没有查到,就从数据库中查,然后再把查到的结果也写入redis中。

虽然这种方法的实时性比定期生成好,但是不断的向redis中写入数据,就会让内存空间越来越小最后达到上限 (redis的空间上限不一定就是内存空间,可以通过设置maxmemory属性来决定给redis分配多少内存空间)。

所以针对上述问题,就需要进行内存空间的淘汰给一些不需要的数据淘汰掉。

淘汰的策略有以下几种:

  • FIFO(First In FirstOut)先进先出:记录每个key的最近访问时间.把最近访问时间最老的key淘汰掉。
  • **LRU(Least Recently Used)淘汰最久未使用的:**记录每个key的最近访问时间.把最近访问时间最老的key淘汰掉
  • LFU(Least Frequently Used)淘汰访问次数最少的:记录每个key最近⼀段时间的访问次数.把访问次数最少的淘汰掉
  • Random随机淘汰:从所有的key中抽取幸运儿被随机淘汰掉

这些淘汰策略并不局限于redis,其他缓存也可以这样展开

下面是redis内置的淘汰策略:

  • volatile-lru: 当内存不足以容纳新写入数据时,从设置了过期时间(包括过期时间还没到)的key中使用LRU(最近最少使用)算法进行淘汰。
  • allkeys-lru: 当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
  • volatile-lfu: 4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使⽤LFU算法进行删除key。
  • allkeys-lfu: 4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰。
  • volatile-random: 当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据。
  • allkeys-random: 当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
  • volatile-ttl: 在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰。(相当于FIFO,只不过是局限于过期的key)
  • **noeviction(默认):**当内存不足以容纳新写入数据时,新写入操作会报错(不适合实时更新)。

整体来说Redis提供的策略和我们上述介绍的通策略是基本⼀致的,只不过Redis这里会针对过期

key和全部key做分别处理。

缓存预热

如果缓存中的数据是实时更新,那么当redis服务器首次接入后,里面是没有数据的,所以此时所有请求都会发送给mysql,可能会给mysql带来很大的压力。

缓存预热就是用来解决上述问题

通过把定期生成和实时生成结合,先通过离线的方式,统计一批热点数据,然后导入redis中,这是导入的热点数据就可以帮助mysql承担很多压力了,最后随着时间的推移,刚开始的热点数据慢慢被新的热点数据替代。

缓存穿透

当请求查询某个key时,redis和mysql中都没有,那么这个key也不会被更新到缓存中,所以这种请求都会被打给mysql,如果存在很多这样的请求,就会给mysql带来很大的压力。

引起这种问题的原因可能是:

  • 业务设计不合理,缺少校验key的环节,导致非法的key没有被拦截
  • 不小心把这些数据在数据库上删除了所以访问不到
  • 黑客攻击

解决方法

更改业务逻辑,加强监控捕捉

  • **缓存空对象:**如果发现这个key在redis和mysql上都不存在的话,依然将这个数据保存到redis中,并且给value设置为空,这样再有这个数据请求时就可以再redis上访问到并返回一个空,这种方法虽然简单但是也有缺点,额外的内存消耗,可能造成短期的不一致。
  • **布隆过滤:**引入布隆过滤器,每次查询redis之前,都先判定以下key是否再布隆过滤器上存在,这种方法内存占用较少,没有多余key。但是实现复杂,存在误判可能。

缓存雪崩

由于在短时间内redis上的key大规模失效,或者redis直接宕机,导致缓存命中率下降,导致大量请求到达数据库,带来巨大压力。

key大规模失效的原因可能时之前短时间内给大量的key设置了相同的过期时间

解决方法

  • 部署高可用的Redis集群,并且完善监控报警体系
  • 不给key设置过期时间或者设置过期时间的时候添加随机时间因子

缓存击穿(瘫痪)

缓存击穿也叫热点key问题,相当于缓存雪崩的特殊情况,就是正对热点key突然过期了,而且此时又有大量的请求过来,就会导致这些请求都直接访问到mysql上,给mysql产生极大压力甚至宕机。

解决方法

  • 基于统计的方式发现热点key并且设置过期时间为永不过期
  • 进行必要的服务降级(关闭一些其他功能只保留核心功能),比如访问数据库的时候使用分布式锁,限制同时请求数据库的并发量。
相关推荐
TDengine (老段)16 分钟前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据
码界奇点25 分钟前
KingbaseES一体化架构与多层防护体系如何保障企业级数据库的持续稳定与弹性扩展
数据库·架构·可用性测试
悟乙己1 小时前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
皆过客,揽星河1 小时前
mysql进阶语法(视图)
数据库·sql·mysql·mysql基础语法·mysql进阶语法·视图创建修改删除
tuokuac2 小时前
Redis 的相关文件作用
数据库·redis·缓存
鹧鸪云光伏与储能软件开发3 小时前
投资储能项目能赚多少钱?小程序帮你测算
运维·数据库·小程序·光伏·光伏设计软件·光伏设计
cdcdhj4 小时前
数据库存储大量的json文件怎么样高效的读取和分页,利用文件缓存办法不占用内存
缓存·node.js·json
2301_779503764 小时前
MySQL主从同步--主从复制进阶
数据库·mysql
beijingliushao4 小时前
58-正则表达式
数据库·python·mysql·正则表达式
lingggggaaaa5 小时前
小迪安全v2023学习笔记(七十八讲)—— 数据库安全&Redis&CouchDB&H2database&未授权&CVE
redis·笔记·学习·算法·安全·网络安全·couchdb