Redis 缓存

文章目录

redis的主要用途:

1)存储数据(内存数据库)

2)缓存(redis最常用的场景)

3)消息队列

1.什么是缓存

缓存的本质是 "用更快的存储设备,暂存慢设备的数据,减少慢设备的访问压力"。生活中最常见的例子就是 "浏览器缓存"------ 把你之前访问过的网页图片、JS 文件存在本地硬盘,下次再打开同一网页时,直接从本地读,不用再从远程服务器下载,加载速度快很多。

在后端系统中,缓存的核心价值是解决 "速度不匹配" 的问题:

  • MySQL 等数据库数据存在硬盘,读写速度约 100-1000 次 / 秒;
  • Redis 数据存在内存,读写速度约 10 万 - 100 万次 / 秒;
  • 当用户请求量达到每秒几万次时,直接访问 MySQL 会瞬间把数据库压垮,而 Redis 能轻松扛住。

所以,Redis 作为 MySQL 的缓存,工作流程很简单:

  1. 客户端查询数据时,先去 Redis 查;
  2. Redis 有数据(命中):直接返回,不碰 MySQL;
  3. Redis 没数据(未命中):去 MySQL 查,查到后把数据存到 Redis,再返回给客户端。

2.缓存更新策略

2.1定期生成

把访问的数据,以日志的形式存储起来,每隔一定的周期(一天/一周/一月)对数据进行统计,选出频次高的数据作为缓存。

比如搜索引擎,就是关注"查询词",通过日志,每天统计一整天每个词出现的频率,根据频率取出前20%的词作为"热点词",放入缓存中。

可以写一套离线的流程来完成(shell/python 写脚本代码)

  • a)完成热点词的统计
  • b)根据热点词,搜索到对应的数据
  • c) 把缓存数据同步到缓存服务器上
  • d)控制缓存服务器自动重启

优点:实现简单,过程可控,方便排查问题

缺点:缺乏实时性,如果突发热点事件,突然出现很多新的热词,可能就会给后面的数据库带来较大的压力。(缓存里还没有这些热词,会直接在数据库中搜索)

2.2 实时生成

查询数据时,先在redis中查询,找到直接返回。

redis中没有,去数据库中找,找到了返回并把结果写入缓存。

这样的话缓存中的数据就会越来越多---》就会引发内存淘汰策略

  • FIFO(First In First Out,先进先出):淘汰缓存中存在时间最久(最先进入缓存)的数据。
  • LRU(Least Recently Used,最近最少使用):记录每个 key 的最近访问时间,淘汰最近访问时间最久的 key。
  • LFU(Least Frequently Used,最不经常使用):记录每个 key 最近一段时间的访问次数,淘汰访问次数最少的 key。
  • Random(随机淘汰):从所有的 key 中随机抽取并淘汰。

redis中有一个配置项,可以设置采取哪种淘汰策略。具体设置哪种还是具体情况具体分析。

  • volatile-lru:内存不足时,从设置了过期时间的 key 中用 LRU(最近最少使用)算法淘汰。
  • allkeys-lru:内存不足时,从所有 key 中用 LRU 算法淘汰。
  • volatile-lfu(4.0 版本新增):内存不足时,从设置了过期时间的 key 中用 LFU 算法删除。
  • allkeys-lfu(4.0 版本新增):内存不足时,从所有 key 中用 LFU 算法淘汰。
  • volatile-random:内存不足时,从设置了过期时间的 key 中随机淘汰。
  • allkeys-random:内存不足时,从所有 key 中随机淘汰。
  • volatile-ttl:在设置了过期时间的 key 中,按过期时间淘汰,越早过期越优先。
  • noeviction(默认策略):内存不足时,新写入操作会报错,且不适合实时更新缓存场景。

3.缓存使用注意事项

3.1缓存预热(cache preheating)

缓存中的数据

1)定期生成(不涉及"预热")

2)实时生成

redis服务器首次接入后,缓存中没有数据,客户端查redis,没有--》继续查MySQL,查到后返回并写入缓存。

一开始缓存中没有数据,数据库的请求就会很多,随着redis上数据积累,MySQL的压力就小了。

措施:

结合定期生成 和 实时生成。先统计一下数据,把热点数据提前导入缓存,减少数据库的压力。--》随时间推移,逐渐新的热点数据就代替旧的热点数据了。

3.2 缓存穿透(cache penetration)

如果某个key,在redis上没有,在数据库中也没有,每次查询时都会访问到数据库,给MySQL带来很大的压力。

措施:

1)如果发现这个key在redis上和MySQL上都不存在,就写入到redis中,value值设置为一个非法值(比如" ")

2)引入布隆过滤器,每次查询时,提前判断存不存在。

3.3 缓存雪崩(cache avalanche)

短时间内,redis上大规模的key失效,导致命中率陡然下降,进而MySQL的压力迅速上升,甚至宕机。

1)redis直接挂了(redis宕机/redis集群中大量节点宕机)

2)redis在运行,可能短时间内设置了很多带过期时间的key,然后这批key同时过期了。(大量key同时过期)---》导致大量访问传送到了数据库上。

解决措施:

1)加强监控报警,加强redis集群可用性的保证

2)不给key设置过期时间/设置过期时间时避免同一时刻

3.4 缓存击穿(cache breakdown)

热点key突然过期,导致大量请求直接访问到数据库上,甚至引起数据库宕机。

解决措施:

1)基于统计方法发现热点key,设置永不过期

2)进行必要的服务降级,使用分布式锁,限制同时请求数据库的并发数。

分布式锁---》限制数据库访问频率

服务降级---》保留核心,关闭一些不重要的功能

4.小结

  1. 选对更新策略:数据固定用 "定期生成",数据多变用 "实时生成 + 内存淘汰";
  2. 必做缓存预热:冷启动前导入热点数据,避免 MySQL 承压;
  3. 防穿透:用 "空值缓存" 或 "布隆过滤器" 拦截无效请求;
  4. 防雪崩:错开过期时间,用 Redis 集群提高可用性;
  5. 防击穿:热点 key 永不过期,或用分布式锁限制并发。
相关推荐
初听于你6 小时前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
恒悦sunsite8 小时前
Ubuntu之apt安装ClickHouse数据库
数据库·clickhouse·ubuntu·列式存储·8123
奥尔特星云大使8 小时前
MySQL 慢查询日志slow query log
android·数据库·mysql·adb·慢日志·slow query log
来自宇宙的曹先生9 小时前
MySQL 存储引擎 API
数据库·mysql
间彧9 小时前
MySQL Performance Schema详解与实战应用
数据库
间彧9 小时前
MySQL Exporter采集的关键指标有哪些,如何解读这些指标?
数据库
weixin_446260859 小时前
Django - 让开发变得简单高效的Web框架
前端·数据库·django
mpHH9 小时前
babelfish for postgresql 分析--todo
数据库·postgresql
zizisuo9 小时前
解决在使用Lombok时maven install 找不到符号的问题
java·数据库·maven