Redis——缓存

什么是缓存?

缓存是计算机中一个经典的概念,其实本质就是将常用的数据放到访问速度快的地方,方便读取。

对于硬件的访问速度来说,通常情况如下:

CPU寄存器 > 内存 > 硬盘 > 网路

但是对于计算机硬件来说,往往访问速度快的设备,成本就会越高,存储空间就会越小。缓存是快,但是空间是不足的,所以,缓存大部分就是放一些热点数据

在一个网站中,通常使用像MySQL这样的关系型数据库来存储数据。关系型数据库虽然功能强大,但是有一个缺陷就是性能不高(这里是相对于redis来说)

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

  • 数据库将数据存储到硬盘上,硬盘上的IO速度并不快,尤其是随机访问
  • 如果查询不能命中索引,就需要进行表的遍历,这会大大增加硬盘IO次数
  • 如果涉及到了一些复杂的查询,需要用到笛卡尔积,效率就会下降很多

而且,在面对并发量大的情况下,数据库可能会宕机

为什么并发量大的情况下会宕机?

  • 服务器每次处理一个请求,都是需要消耗一定的硬件资源的(CPU、内存、硬盘、网络带宽)
  • 一个服务器的资源是有限的,一个请求消耗一份资源,请求多了,后续的请求就没有资源可用了,无法得到处理,就有可能会宕机

如何让数据库承担更大的并发量呢?

  • 开源:引入更多的机器,部署更多的数据库实例,构成集群。比如:分库分表、主从复制等
  • 节流:引入缓存,使用其他的方式保存经常访问的数据,从而降低数据库的压力

其中Redis就是缓存的一个经典案列,Redis的访问速度比MySQL快,或者说处理同一个访问请求,Redis消耗的系统资源比MySQL少很多,因此Redis能支持的并发量大

  • Redis数据在内存中,访问速度比硬盘快
  • Redis只支持key-value的形式,不涉及复杂查询的限制规则
  • 客户端访问服务器的时候,发起查询请求
  • 业务服务器先查询Redis,看数据是否在Redis存在,如果存在直接返回,如果不存在就访问MySQL

那么问题来了如何知道Redis应该存储哪些数据呢?

定期生成

每隔一定的周期,对于访问的数据频次做统计,挑选出访问最高的前N%的数据,这些数据就是热点数据。

比如:用户来搜索引擎中输入一个关键字,有些关键字就是高频出现的,搜索引擎的服务器中可以通过日志的方式记录下来,然后每隔一定的时间将结果统计出来,就可以得到热点数据了。

但是想过没有,如果面对像一个节假日的突发情况,某个词会出现的很频繁,但是过了这段时间,就不会有人搜索这个词。 这种情况下,如果采取了定期生成的方式,是不是就不合适了呢??

所以基于上面的场景,有了实时生成的策略

实时生成

先给缓存设定容量上限(可以通过Redis中的maxmemory参数来设定)

接下来用户的每次查询:

  • 如果Redis存在,就直接返回
  • 如果Redis不存在,就从数据库中查询,将查询到的结果写入到Redis中

但是,如果缓存达到了上限,就会发出淘汰机制,将一些"相对不热门的"的数据淘汰掉。

通常的淘汰策略有如下几种

  • FIFO(First In First Out)先入先出:将缓存时间最久的数据淘汰掉
  • LRU(Least Recently Used)淘汰最久没使用的:记录每个key的最近访问时间,将最近的访问时间最老的key淘汰掉
  • LFU(Least Frequently Used)淘汰访问次数最少的:记录每个key最近一段时间的访问次数,将访问次数最少的key淘汰掉
  • Random随机淘汰:从所有的key中随机淘汰一个key

淘汰策略,用户可以自己实现,当然Redis也提供了内置的淘汰策略,以便直接使用。

Redis的内置淘汰策略如下:

  • volatile-lru: 当内存不足以容纳新写入的数据时,从设置了过期时间的key中使用LRU算法进行淘汰
  • allkeys-lru:当内存不足以容纳新写入的数据时,从所有的key中使用LRU算法进行淘汰
  • volatile-lfu:当内存不足以容纳新写入的数据时,在过期的key中,使用lfu算法进行淘汰
  • allkeys-lru:当内存不足以容纳新写入的数据时,从所有的key中使用lfu算法进行淘汰
  • volatile-random:当内存不足以容纳新写入的数据时,从所有的key中随机淘汰一个key
  • volatile-ttl:在设置了过期时间的key中,根据过期时间来淘汰。 (越早的过期key,越早被淘汰)
  • noeviction:这是Redis采用的默认策略,当内存不足的时候,写入操作会报错

缓存预热

什么是缓存预热

  • 使用Redis作为MySQL的缓存,当MySQL刚刚启动的时候,或者Redis大批量的key失效以后,由于Redis自身没啥数据,会直接访问到MySQL中,就会对MySQL造成巨大的压力。

所以要将热点数据准备好,直接写入到Redis中。

缓存穿透(Cache penetration)

什么是缓存穿透

  • 当一个key在Redis中不存在,并且也不在MySQL中,那么如果这时候并发量很大,就会造成巨大的压力。 这就叫做缓存穿透

为何产生:

  • 业务设计的不合理,比如缺少必要的参数校验,导致非法的key进行查询
  • 开发/运维误操作:将部分的key删除掉了
  • ...

如何解决

  • 针对要查询的参数进行严格的校验,比如查询的key是用户的手机号,那么就需要校验当前的key是否满足一个合法的手机号的格式
  • 针对数据库也不存在的key,也存储到Redis中,比如value就随便设置为一个"",避免后续频繁的访问数据库
  • 在应用程序中使用布隆过滤器,先进行一次判断,降低Redis的压力

缓存雪崩

什么是缓存雪崩

  • 短时间内大量的key在缓存上失效,导致数据库压力剧增,甚至是宕机了

为何产生:

大规模的key失效有两种情况

  • Redis挂了
  • Redis设置了大量的key同时过期了

如何解决?

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

缓存击穿(Cache breakdown)

什么是缓存击穿

  • 相当于缓存雪崩的特殊场景,针对热点的key,突然过期了,导致大量的请求打到了数据库上,引发了宕机

如何解决?

  • 基于统计的方式发现热点key,并设置永不过期
  • 进行服务降级,例如采用分布式锁,限制同时请求数据库的并发量。 或者进行分流操作,将流量分到其他的服务器中
相关推荐
张声录128 分钟前
【ETCD】【实操篇(十五)】etcd集群成员管理:如何高效地添加、删除与更新节点
数据库·etcd
天乐敲代码29 分钟前
Etcd静态分布式集群搭建
数据库·分布式·etcd
chengma_09090930 分钟前
MySQL 数据库连接数查询、配置
数据库·mysql
奋斗的老史36 分钟前
Spring Retry + Redis Watch实现高并发乐观锁
java·redis·spring
TDengine (老段)1 小时前
两分钟掌握 TDengine 全部写入方式
大数据·数据库·时序数据库·tdengine·涛思数据
码农君莫笑1 小时前
《信管通低代码信息管理系统开发平台》Windows环境安装说明
服务器·数据库·windows·低代码·c#·bootstrap·.netcore
计算机学长felix1 小时前
基于SpringBoot的“大学生社团活动平台”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·后端
木与子不厌2 小时前
微服务自定义过滤器
运维·数据库·微服务
loop lee2 小时前
Redis - Token & JWT 概念解析及双token实现分布式session存储实战
java·redis