Redis应用-缓存

目录

什么是缓存

使用redis作为缓存

缓存的更新策略

通用的淘汰策略

redis内置的淘汰策略

缓存预热

缓存穿透

缓存雪崩

缓存击穿


什么是缓存

缓存(cache)是计算机中一个经典的概念,在很多的场景中都会涉及到.

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

对于计算机来说,往往访问速度越快的设备,成本越高,存储空间越小.

因此,缓存是更快了,但是空间上往往是不足的.所以大部分的时候,缓存只存放一些热点数据(频繁访问的数据).

二八定律:20%的热点数据能够应对80%的访问场景,因此只需要把这少量的热点数据缓存起来,就可以应对大多数的场景,从而整体上有明显的性能提升.

使用redis作为缓存

我们通常使用redis来作为数据库(mysql)等的缓存.

数据库是非常重要的组件,在绝大部分商业项目中都会使用到,并且mysql的速度又比较慢,所以就可以使用redis来作为mysql的缓存.

因为mysql等数据库的效率比较低,所以承担的并发量有限,一旦请求的数量多了,数据库的压力就会很大,甚至很容易宕机.
为什么并发量⾼了就会宕机?
服务器每次处理⼀个请求, 都是需要消耗⼀定的硬件资源的. 所谓的硬件资源包括不限于 CPU,
内存, 硬盘, ⽹络带宽...... ⼀个服务器的硬件资源本⾝是有限的. ⼀个请求消耗⼀份资源, 请求多了, ⾃然把资源就耗尽了. 后续的请求没有资源可⽤, ⾃然就⽆法正确处理. 更严重的还会导致服务器程序的代码出现崩溃.


如何让数据库承担更大的并发量,核心思路有两个:开源和节流.

开源:引入更多的机器,部署更多的数据库实例,构成数据库集群.

节流:引入缓存,使用其他的方式保存经常访问的热点数据,从而降低直接访问数据库的请求数量.

redis就是一个用来作为数据库缓存的常见方案,redis的访问速度比mysql快很多,或者说处理同一个访问请求,redis消耗的系统资源比mysql少很多,因此redis能支持的并发量更大.

redis就像是一个护盾一样,保护着mysql.

客户端访问业务服务器,发起查询请求,业务服务器会先查询redis,查看想要的数据是否在redis中存在,如果在redis中存在了,就直接返回,此时就不必访问mysql了;如果在redis中不存在,在去查询mysql.

根据二八定律,只需要在redis中存放20%的热点数据,就可以使80%的请求不在真正的查询mysql,从而大大提高整体的访问效率,降低数据库的压力.

需要注意的是:缓存是用来加快读操作的速度的,如果写操作,还是要写进数据库,此时缓存并不能提高性能.


缓存的更新策略

如何知道redis中应该存储哪些数据,如何知道哪些数据是热点数据呢?

1.定期生成

每隔一定的周期(比如一天/一周/一个月),对于访问的数据频次进行统计,挑选出访问频次最高的前N%的数据.

优点:实现起来比较简单,过程更加可控,方便排查问题.

缺点:实时性不够,如果出现一些突发性事件,有一些本来不是热点的数据变成了热点数据,那么新的热点数据可能会给数据库带来较大的压力.

2.实时生成

先给缓存设定容量上限(可以通过redis配置文件的maxmemory参数设定).

接下来用户的每次查询,如果在redis中查到了,就直接返回,如果redis中不存在,就从数据库查,同时把查到的结果也写入redis.

如果缓存满了,就会触发内存淘汰策略,把一些相对不那么热门的数据淘汰掉.

按照上述过程,持续一段事件之后,redis内部的数据自然就是热门数据了.

通用的淘汰策略

FIFO(first in first out)

先进先出,把缓存中存在时间最久的,也就是先来的数据,淘汰掉.

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 作为 MySQL 的缓存的时候, 当 Redis 刚刚启动, 或者 Redis ⼤批 key 失效之后, 此时由于 Redis ⾃⾝相当于是空着的, 没啥缓存数据, 那么 MySQL 就可能直接被访问到, 从⽽造成较⼤的压⼒.因此就需要提前把热点数据准备好, 直接写⼊到 Redis 中. 使 Redis 可以尽快为 MySQL 撑起保护伞. 热点数据可以基于之前介绍的统计的⽅式⽣成即可. 这份热点数据不⼀定⾮得那么 "准确", 只要能帮助MySQL 抵挡⼤部分请求即可. 随着程序运⾏的推移, 缓存的热点数据会逐渐⾃动调整, 来更适应当前情况.


缓存穿透

访问的 key 在 Redis 和 数据库中都不存在. 此时这样的 key 不会被放到缓存上, 后续如果仍然在访问该key, 依然会访问到数据库.
这就会导致数据库承担的请求太多, 压⼒很⼤. 这种情况称为 缓存穿透.


缓存穿透产生的原因:
1.业务设计不合理,比如缺少必要的参数校验缓解,导致非法的key也被进行查询了.
2.开发/运维的误操作,导致部分数据从数据库上删除了.
3.黑客的恶意攻击.
如何解决:
1.针对要查询的参数进行严格的合法性校验.
2.针对数据库上不存在的key,也存储到redis中,比如value设置成"",避免后续频繁的访问数据库.
3.使用布隆过滤器先判定key是否存在,再去真正的查询.


缓存雪崩

短时间内大量的key在缓存上失效,导致数据库压力骤增,设置直接宕机.

产生原因

大规模的key失效,可能性主要有两种.

1.redis直接挂了.redis宕机或者redis集群模式下大量节点宕机.

2.redis上大量的key同时过期.很可能之前短时间内设置了很多key给redis,并且设置的过期时间是相同的.

解决方法

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

2.不给key设置过期时间,或者在设置过期时间的时候添加随机因子,避免同一时间过期.


缓存击穿

cache breakdown,也可以叫做缓存瘫痪/崩溃.

相当于缓存雪崩的特殊情况,针对热点key,突然过期了,导致大量的请求直接访问到数据库上,甚至引起数据库宕机.

如何解决

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

2.进行必要的服务降级,例如访问数据库的时候使用分布式锁,限制同时请求数据库的并发数.

服务降级:在特定的情况下,适当的关闭一些不重要的功能,只保留核心的功能.


相关推荐
Elastic 中国社区官方博客1 小时前
在 Elasticsearch 中使用 Mistral Chat completions 进行上下文工程
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
编程爱好者熊浪3 小时前
两次连接池泄露的BUG
java·数据库
cr7xin4 小时前
缓存三大问题及解决方案
redis·后端·缓存
爱怪笑的小杰杰4 小时前
浏览器端缓存地图请求:使用 IndexedDB + ajax-hook 提升地图加载速度
ajax·okhttp·缓存
TDengine (老段)5 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349845 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE5 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102166 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎6 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP6 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql