Redis 进阶(七)—— 缓存

6. Redis 作缓存

6.1 引入

redis 最主要用途:1. 存储数据------内存型数据库;2. 作缓存(redis 最常用的场景);3. 做消息队列。

这里要提到这样一个定律 ------ 二八定律,即 20% 的热点数据,能够支持 80% 的请求。

通常使用 redis 作数据库的缓存(如 mysql)。

一方面redis 是内存型数据库,速度比 mysql 快的多,性能好;

另一方面,mysql 等数据库的效率较低,所能接受的并发量就有限,一旦请求数量多了,压力倍增,很可能会挂。将一些访问量高的数据存在 redis 里面,请求现在redis 中找,找不到再在 mysql 中找。就像前面的二八定律,让 redis 承担更多请求,减少 mysql 的压力,避免请求太多,mysql 处理的又慢,导致 mysql 崩了。

为什么 关系型数据库性能不高?

硬件方面:

  1. 数据存在硬盘上,硬盘的 IO 速度慢,尤其是随机访问
  2. 如果查询不能命中索引,就要遍历表,硬盘IO 次数大增
    软件方面:
  3. 关系型数据库对于 一些 sql 的执行会做一系列的解析,校验,优化工作
  4. 如果是一些复杂查询,比如联合查询,需要进行笛卡尔积操作,效率会降低更多

那如何知道应该向 redis 中存放哪些数据呢?且看 6.2 小节

6.2 缓存更新策略

redis 更新缓存的方式分为两种:① 定期生成;② 实时生成。

6.2.1 定期生成

定期生成,即 将访问的数据,以日志的形式记录,通过日志,对一定时间内(一天,一周,一月......)的数据出现的频率进行统计,将所得数据的出现频率降序排列,取前 20% 的数据,这些数据就可以认为是 "热点数据"。之后,将这些数据放入 redis 即可。

日志数量很大,肯定不是人工一点一点的统计。一般都会用 shell,python 等写一个脚本,通过定时任务来触发。流程大致这样:1)统计热词 ;2)根据热词找到对应请求结果的数据;3)数据同步到缓存服务器;4)重启服务器。

优点:实现简单,过程更可控(缓存中有什么比较固定),排查问题方便。

缺点:实时性不够,对于突发热点数据,处理不好,肯能给数据库带来较大压力。例如:911这种震惊世界的事,当时如果网络像现在这样,绝对会是热搜榜首事件,但在事件发生前这根本不可能在热点数据里。

6.2.2 实时生成

如果 redis 中查到了该数据,就直接返回;如果没有查到,就从数据库中查,并同时写入 redis。

但是这样一直写,就会导致 redis 的内存占用越来越多,逼近上限(不一定是机器内存上限,redis 中可以配置最大使用多少内存 maxmemory 参数

为解决该问题,redis 引入了 内存淘汰策略 (经典面试题)。

通用的内存淘汰机制主要有以下几种:

  1. FIFO(First In First Out)先进先出
    淘汰缓存中存在时间最长的
  2. LRU(Least Recently Used)淘汰最久未访问的
    记录每个 key 的最近访问时间,把访问时间最早的淘汰
  3. LFU (Least Recently Used)淘汰访问次数最少的
    记录每个 key 最近一段时间的访问次数,把访问次数最少的淘汰
  4. Random 随机淘汰
    顾名思义,随机选一个进行淘汰

redis 中有一个相关配置项,可以设置采用哪种策略,具体采用哪种策略,要结合实际分析。

Reds 内置的淘汰策略如下:

  • volatile-lru 内存不足以容纳新数据时,从设置了过期时间的 key 中使用 LRU 算法进行淘汰
  • allkeys-lru 上面那个是针对设置了过期时间的key,这个是所有 key

这两个可以对应前面 LRU 淘汰机制

  • volatile-lfu 4.0 版本新增,内存不足以容纳新数据时,在设置了过期时间的 key 中使用 LFU 算法进行淘汰
  • allkeys-lfu 不在局限于设置了过期时间的 key,针对所有 key

这两个对应前面的 LFU 淘汰机制

  • volatile-random 内存不足以容纳新数据时,在设置了过期时间的 key 中随机淘汰
  • allkeys-random 不在局限于设置了过期时间的 key,针对所有 key

这两个对应前面的 Random 淘汰机制

  • noveiction 默认 策略,内存不足以容纳新数据时,新写入操作会报错,这是默认选项,不适于实时更新。

6.3 缓存使用注意事项

主要有四个注意方面:① 缓存预热;② 缓存穿透;③ 缓存雪崩;④ 缓存击穿

6.3.1 缓存预热 (Cache preheating)

在前面我们知道 redis 缓存更新策略分为:定期生成和实时生成。

其中 定期生成 不涉及预热,而实时生成会涉及到预热。

采用实时生成时,redis 服务首次接入时,里面是没有数据的,要随着时间,数据才会逐渐积累,这个期间,如果这段时间数据来了许多,那么 mysql 所受压力就很大了。

解决措施: 定期生成和实时生成结合,先通过离线的方式,统计一下,在 redis 里面先放一批热点数据,这样就能帮 mysql 承担不少压力,后面随着时间推移,新的热点数据就替换旧的。

6.3.2 缓存穿透(Cache penetration)

查询某个 key 的时候,在 redis 中没有找到,在 MySQL

中也没有找到,这样该 key 就不会被更新 redis 中。

如果这样的数据,存在很大,且反复查询,一样会给 mysql 带来很大的压力。

导致这样的原因可以能有以下几种:

  1. 业务设计不合理,如缺少必要的参数校验,导致非法 key 也进行查询
  2. 开发/运维错误操作,不小心将数据给误删了
  3. 黑客恶意攻击

解决措施:

改进业务设计,加强监控告警......这些属于是亡羊补牢都方法。

更靠谱的方案(主要是降低问题严重性)① 如发现 key 在 redis 和 MySQL 中都不存在,就将该 key 写入 redis 并将 value 设置为一个非法值,例如 "";② 引入 布隆过滤器。每次查询 redis / mysql 前都先判定 key 是否在 布隆过滤器 上存在(把所有的 key 都插入到 布隆过滤器 中) ,布隆过滤器 本质是 hash + bitmap 的结合,只能判定有没有,不知数据内容。它能以较小的空间开销,较快的时间速度,实现对 key 是否存在的判定。

6.3.3 缓存雪崩(Cache avalanche)

短时间内,redis 上大量 key 失效,导致缓存命中率陡然下降,mysql 压力迅速上升,甚至直接宕机。

原因:

1)redis 直接挂了 ------ redis 宕机 / redis 集群模式下大量节点宕机

2)redis 正常工作,但是之前短时间内设置了大量过期时间相同的 key。(在 redis 中设置 key 作缓存时,有时为了考虑时效性,就会设置过期时间(和 redis 内存淘汰机制,配合使用的)

解决措施:

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

2)不给 key 设置过期时间 / 设置 过期时间时添加随机因子,避免同一时刻过期

6.3.4 缓存击穿(Cache breakdown)

缓存雪崩的特殊情况,针对 热点 key,突然过期了,大量请求打到了 mysql,甚至引起数据库宕机,因为热点数据访问频率高。

解决措施:

1)基于统计的方式发现热点 key,并设置为永不过期

2)进行必要的服务降级,例如访问数据库时使用分布式锁,限制同时请求数据库的并发数(服务降级:例如原本有十个功能,在特定情况下,适当关闭一些不重要的功能,只保留核心功能正常工作,类似手机的超级省电模式,只能看时间,打电话)

相关推荐
claem9 小时前
Mac搭建postgreSQL 一些基础命令与注意事项
数据库·postgresql
程序猿20239 小时前
MySQL的逻辑存储结构
java·数据库·mysql
2301_8002561110 小时前
第九章:空间网络模型(空间网络查询、数据模型、Connected、with Recursive、pgRouting)
网络·数据库·算法·postgresql·oracle
霖霖总总11 小时前
[小技巧19]MySQL 权限管理全指南:用户、角色、授权与安全实践
数据库·mysql·安全
heartbeat..16 小时前
Spring AOP 全面详解(通俗易懂 + 核心知识点 + 完整案例)
java·数据库·spring·aop
麦聪聊数据18 小时前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
AC赳赳老秦18 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
YMatrix 官方技术社区19 小时前
YMatrix 存储引擎解密:MARS3 存储引擎如何超越传统行存、列存实现“时序+分析“场景性能大幅提升?
开发语言·数据库·时序数据库·数据库架构·智慧工厂·存储引擎·ymatrix
辞砚技术录20 小时前
MySQL面试题——索引2nd
数据库·mysql·面试