什么是缓存
缓存 (cache) 是计算机中的⼀个经典的概念. 在很多场景中都会涉及到.
核⼼思路就是把⼀些常⽤的数据放到触⼿可及(访问速度更快)的地⽅, ⽅便随时读取。
Redis 缓存是使用 Redis 作为内存中的数据存储系统,用于临时存放经常访问的数据,以减少对后端数据库的访问次数,提高应用程序的响应速度和整体性能。以下是 Redis 缓存的一些关键概念和特点:
-
内存存储
Redis 将所有数据存储在内存中,这使得数据的读写速度极快。由于内存的访问速度远快于磁盘,使用 Redis 作为缓存可以显著提高数据访问效率。 -
数据结构多样性
Redis 不仅仅是一个简单的键值存储系统。它支持多种数据结构,如字符串、列表、集合、散列、有序集合等,这使得 Redis 在处理各种不同需求的缓存数据时非常灵活。 -
过期策略
Redis 允许为存储的每个键设置过期时间。这意味着数据可以在设定的时间后自动删除,这对于管理缓存数据的生命周期非常有用。当缓存数据过期后,Redis 会自动清理这些数据,从而释放内存空间。 -
持久性选项
尽管 Redis 是一个基于内存的系统,但它提供了多种数据持久化选项(如 RDB 快照和 AOF 日志),可以将内存中的数据定期保存到磁盘。这样即使系统重启,也能从磁盘恢复数据。 -
高可用性和扩展性
通过使用 Redis 集群,可以实现数据的自动分片和复制,这不仅提高了 Redis 环境的可用性,还可以通过增加更多节点来水平扩展系统的容量和性能。 -
应用场景
Redis 缓存广泛应用于需要高速读写的场景,如:
网页缓存:存储网页的HTML内容,减少页面生成时间。
会话缓存(Session Cache):存储用户会话信息,提高用户交互响应速度。
数据库查询缓存:缓存数据库查询结果,减少对数据库的查询频率和负载。
实时应用:如游戏、聊天应用等,利用 Redis 的发布/订阅功能处理实时消息传递。
通过使用 Redis 缓存,可以显著减少后端服务的压力,提高数据处理速度和用户体验。这使得 Redis 成为现代Web应用、大数据处理和云服务中不可或缺的工具之一。
缓存策略
如何知道redis中应该存储哪些数据?
如何知道哪些数据是热点数据呢?
定期生成
每隔⼀定的周期(⽐如⼀天/⼀周/⼀个⽉), 对于访问的数据频次进⾏统计. 挑选出访问频次最⾼的前 N%的数据.
举个例子
⽤⼾在搜索引擎中会输⼊⼀个 “查询词”, 有些词是属于⾼频的, ⼤家都爱搜(鲜花, 蛋糕, 同城交
友, 不孕不育…). 有些词就属于低频的, ⼤家很少搜.
搜索引擎的服务器会把哪个⽤⼾什么时间搜了啥词, 都通过⽇志的⽅式记录的明明⽩⽩. 然后
每隔⼀段时间对这期间的搜索结果进⾏统计 (⽇志的数量可能⾮常巨⼤, 这个统计的过程可能
需要使⽤ hadoop 或者 spark 等⽅式完成). 从⽽就可以得到 “⾼频词表” .
具体的流程如下:
1.完成统计热词的过程。
2.根据热词,找到搜索的结果。
3.把得到的缓存数据同步到缓存服务器上。
4.控制这些缓存服务器自动重启。
优点:操作简单,过程更加可控,方便排查问题。
缺点:实时性不够,如果出现突发性情况,不能及时更新。
实时生成
先给缓存设定容量上限(可以通过 Redis 配置⽂件的 maxmemory 参数设定).
接下来把⽤⼾每次查询:
- 如果在 Redis 查到了, 就直接返回.
- 如果 Redis 中不存在, 就从数据库查, 把查到的结果同时也写⼊ Redis.
但是这里我们如果不停的写redis,就会使得redis的内存占用越来越多,就是逐渐会达到内存上限,此时我们就要解决上述情况,就引入了内存淘汰机制。
通⽤的淘汰策略主要有以下⼏种:
- FIFO (First In First Out) 先进先出
把缓存中存在时间最久的 (也就是先来的数据) 淘汰掉. - LRU (Least Recently Used) 淘汰最久未使用的
记录每个 key 的最近访问时间. 把最近访问时间最⽼的 key 淘汰掉. - LFU (Least Frequently Used) 淘汰访问次数最少的
记录每个 key 最近⼀段时间的访问次数. 把访问次数最少的淘汰掉 - Random 随机淘汰
从所有的 key 中抽取幸运⼉被随机淘汰掉.
为了让你 理解上述⼏种淘汰策略,我举个例子
在一个遥远的数据国度里,存在一个名为“缓存城”的城堡,用以储存国王宝贵的资源和信息。随着时间的推移和资源的增加,这个城堡开始面临存储空间的挑战。为了解决这个问题,国王邀请了四位智者,每位智者代表一种独特的淘汰策略来管理城堡的存储空间。
首先,有着年长白发的智者FIFO。他提议,按照“先进先出”的原则管理城堡的资源。在他的策略下,最先进入城堡的资源,无论其价值和用途,都将是第一个被移出去的。这就像一个老式的面包店,每天早上烤出的面包,也是当天最先卖出的。
接着,穿着时尚眼镜的智者LRU提出了另一个策略。他认为应该淘汰“最久未使用”的资源。在他的管理下,每个资源都有一个标签,记录上一次被使用的时间。长时间没人问津的资源将会被清理出城堡,确保只留下常被使用的重要资源。这有点像一个图书馆,书籍如果长时间未被借阅,就会被存放到较不显眼的位置或清出图书馆。
然后,年轻的智者LFU提出了“最少频繁使用”策略。他注意到有些资源虽然不常用,但每次使用时都非常关键。因此,他提议记录每个资源的使用频率,频率最低的资源将被清除。这类似于一个商店清理仓库,销量最差的商品会被淘汰以腾出空间。
最后,神秘的智者Random提出了一个截然不同的想法:随机淘汰。在他的指导下,城堡的资源将通过抽签来决定哪些被淘汰。这种方法虽然看似公平,但有时候也可能意外地淘汰掉一些比较重要的资源。这就像是一场宴会上的抽奖,每个人都有可能中奖,不论是王公贵族还是平民百姓。
随着时间的推移,国王观察到这些策略在不同情况下的效果,最终决定根据城堡的具体需求灵活运用这些智者的策略。每一种策略都有其独特的优势和局限性,适当的选择和运用可以使得“缓存城”始终运行在最佳状态。
Redis 内置的淘汰策略如下:
缓存的使用注意事项
缓存预热
为什么要预热?
因为redis服务器收齐接入之后,服务器是没有数据的,客户端就会先查询redis,如果没查到,就再查一次mysql。查到之后就会把数据写入redis中。但是这里是有问题的,这代表所有的请求都要推送给mysql,随着时间的推移,redis的数据是越来越多的。
怎么解决这个问题呢?
进行缓存预热,把实时生成和定时生成节后起来。
具体步骤如下:
1.通过离线的方式,先把热点数据找到一批,存入redis。
2.随着时间的推移,导入的这批热点数据就能帮mysql承担很大压力了。
缓存穿透
什么是缓存穿透?
访问的 key 在 Redis 和 数据库中都不存在. 此时这样的 key 不会被放到缓存上, 后续如果仍然在访问该key, 依然会访问到数据库.
这就会导致数据库承担的请求太多, 压⼒很⼤。
为什么会出现缓存穿透?
- 业务设计不合理. 比如缺少必要的参数校验环节, 导致⾮法的 key 也被进⾏查询了.
- 开发/运维误操作. 不小心把部分数据从数据库上误删了.
- ⿊客恶意攻击.
怎么解决缓存穿透呢? - 针对要查询的参数进⾏严格的合法性校验. ⽐如要查询的 key 是⽤⼾的⼿机号, 那么就需要校验当前
key 是否满⾜⼀个合法的⼿机号的格式 - 针对数据库上也不存在的 key , 也存储到 Redis 中, ⽐如 value 就随便设成⼀个 “”. 避免后续频繁访
问数据库. - 使⽤布隆过滤器先判定 key 是否存在, 再真正查询.
缓存雪崩
什么是缓存雪崩?
短时间内⼤量的 key 在缓存上失效, 导致缓存命中率下降,导致数据库压⼒骤增, 甚⾄直接宕机。
为什么会出现缓存雪崩?
大规模 key 失效, 可能性主要有两种:
- Redis 挂了.
- Redis 上的⼤量的 key 同时过期
怎么解决缓存雪崩?
- 部署⾼可⽤的 Redis 集群, 并且完善监控报警体系.
- 不给 key 设置过期时间 或者 设置过期时间的时候添加随机时间因⼦.
缓存击穿
- 什么是缓存击穿?
相当于缓存雪崩的特殊情况. 针对热点 key , 突然过期了, 导致⼤量的请求直接访问到数据库上, 甚⾄引起数据库宕机. - 为什么会出现缓存击穿?
- 热点 Key 失效:缓存击穿指的是当缓存中某个高访问频率(热点)的数据项突然过期失效时,大量的请求突然转到数据库上,这时数据库会接收到大量的请求压力。如果缓存没有正确地处理这种情况,就会导致数据库的过载甚至崩溃。
- 高并发场景:在高并发的环境下,多个客户端可能同时请求同一个热点 Key。如果这个 Key 正好在这时过期或被删除,所有的请求都会穿透缓存,直接请求数据库来获取这个数据,从而造成数据库的短时间高负载。
- 缺乏同步更新机制:如果系统中缓存的更新和数据库的更新不是同步进行的,或者更新策略处理不当,也可能导致缓存数据过期的瞬间发生缓存击穿。
怎么解决缓存击穿?
- 基于统计的⽅式发现热点 key, 并设置永不过期.
- 进⾏必要的服务降级. 例如访问数据库的时候使⽤分布式锁, 限制同时请求数据库的并发数.