Redis知识小结

过期键删除策略

  当我们在Redis数据库中添加数据的时候可以执行一个数据的过期时间,那么当数据过期之后Redis是怎么来对这些过期的键进行处理的呢?
  这个问题有三种可能的答案,他们分别代表了三种不同的删除策略:

  • 定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
  • 惰性删除:放任过期键不管,但是每次从键空间获取键时,都检查取得的键是否过期,如果过期的话,就删除该键,如果没有过期,就返回该键。
  • 定期删除:每隔一段时间,程序就会对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
    定时删除
      定时删除是对内存最友好的,通过使用定时器,定时删除策略可以保证过期键会尽可能快地被删除,并释放过期键所占用的内存。但是反过来说它对CPU时间是最不友好的,在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分CPU时间,无疑会对服务器的响应时间和吞吐量造成影响。
    惰性删除
      惰性删除对CPU时间来说是最友好的,程序只有在取出键的时候才会判断一个键是否过期,这可以保证删除过期键的操作只会在非做不可的情况下进行,并且删除的目标仅限于当前处理的键,不会再删除其他无关的过期键上花费任何CPU时间;但是这个策略对于内存来说是最不友好的,一个过期的键如果没有被访问到的话可能会长时间的停留在内存中占据空间(除非用户手动执行FLUSHDB)。
    定期删除
      通过对定时删除和惰性删除的学习来看,这两种删除方式在某些方面都存在着自己的缺陷。定期删除则是前两种策略的一种整合和折中:
  • 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对于CPU时间的影响。
  • 除此之外,通过定期删除过期键,定期删除策略有效地减少了因为过期键操作而带来的内存浪费。
      定期删除策略的难点在于确定删除操作执行的时长和频率:
  • 如果删除操作执行的太频繁,或者执行的时间太长

Redis内存淘汰策略

  当Redis的内存超过允许的最大内存之后,Redis会触发内存淘汰策略,删除一些不常用的数据,以保证Redis服务器的正常运行。
Redis4.0以前

  • volatile-lru :从设置过期时间的数据集中(expries)中挑选出最近最少使用的数据淘汰;
  • volatile-ttl :从设置过期时间的数据集中(expires)中挑选中将要过期的数据淘汰,ttl的值越大越优先被淘汰;
  • volatile-random :从设置过期时间的数据集(expries)中随机的选取数据淘汰;
  • allkeys-lru :从数据集(dict)中挑选最近最少使用的数据淘汰,该策略要淘汰的数据是全体key的集合,而非过期的key;
  • allkeys-random :从数据集(dict)中选择任意数据淘汰;
  • noeviction :禁止删除数据,当内存不足时,新写入操作就会报错,请求可以继续进行,保证已插入的数据不会丢失;
    Redis4.0以后
  • volatile-lfu :从已设置过期时间的数据集中挑选最不经常使用的数据淘汰;
  • allkeys-lfu :当内存不足以容纳新写入数据时,从数据集中移除最不经常使用的key;

Redis事物

事物开始

  MULTI命令的执行标志着事物的开始,MULTI命令可以将执行该命令的客户端从非事物状态切换至事物状态

命令入队

  当一个客户端处于非事物状态时,这个客户端发送的命令会立即被服务器执行,但是当一个客户端切换至事物状态之后,服务器会根据这个客户端发送来的不同命令执行不同的操作:

  • 如果客户端发送的命令为:EXEC、DIACARD、WATCH、MULTI四个命令中的其中一个,那么服务器会立即执行这个命令。
  • 当客户端发送的命令是这四个命令之外的命令时,那么服务器不会立即执行这个命令,而是将这个命令放入一个事物队列里面,然后向客户端返回QUEUED回复。
    在这里插入图片描述

执行事物

  当一个处于事物状态的客户端向服务器发送EXEC命令时,这个EXEC命令将立即被服务器执行。服务器会遍历这个客户端的事物队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。

WATCH命令的实现

  WATCH命令是一个乐观锁,它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事物,并向客户端返回代表事物执行失败的空回复。
在这里插入图片描述
  
如图所示,如果在客户端A使用WATCH命令监视name键后,在客户端B中使用命令对name键进行操作,当A对name键进行操作时就会显示nil;
在这里插入图片描述

WACH实现原理

  WATCH命令的实现原理是在每个Redis数据库中都存在着一个watched-keys字典,这个字典的键是被WATCH命令监视的数据库键,而字典的值是一个链表,链表中记录了所有监视相应数据库键的客户端。
在这里插入图片描述
  在每次执行对数据库进行修改的命令之后,数据库都会对watched_keys字典进行检查,查看是否有客户单正在监视刚刚被命令修改过的数据库键,如果有的话,会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端的事物安全性已经被破坏。
  当服务器接收到一个客户端发来的EXEC请求,服务器会根据这个客户端是否打开了REDIS_DIRTY_CAS表示来决定是否执行事物:
在这里插入图片描述

事物的ACID性质

  在传统的关系型数据库中,常常用ACID性质来检验事物功能的可靠性和安全性。在Redis中,Redis事物就是一次性,顺序性,排他性的执行一个队列中的一系列命令。
Redis不保证原子性
  Redis中,单条命令是原子执行的,但是事物并不保证原子性,并且没有回滚的概念。事物中任意命令执行失败,其余的命令仍会执行。
Redis事物没有隔离级别概念
  批量操作在发送EXEC命令前被放入队列,并不会执行,也就不存在事物内的查询要看到事物里的更新,事物外查询不能看到。
特殊点
  编译时异常 :当命令中存在编译时异常(命令错误),事物中所有的命令都不会执行。
在这里插入图片描述
  执行时异常 :如果事务队列中存在错误的语法,在事务执行的时候,其他命令都可以正确执行,错误的命令抛出异常。
在这里插入图片描述

Redis缓存数据一致性及问题

如何保证缓存和数据库数据一致性

  首先我们要明白缓存数据的插入时机,对于服务器而言,查询数据的步骤为:

  • 首先到缓存查询数据,如果数据存在则直接获取数据返回
  • 如果缓存不存在,需要查询数据库,从数据库中获取数据并插入缓存,将数据返回
  • 当二次查询时,后续查询操作就可以查询缓存数据

更新数据的三种策略

1、先删除缓存再更新数据库
  进行更新数据库数据时,先删除缓存,然后更新数据库,后续的请求再次读取数据时,会从数据库中读取数据更新到缓存。
存在问题:
  删除缓存之后,更新数据库之前,这个时间段内如果有新的请求过来,就会从数据库中读取到旧的数据写入缓存,再次造成数据不一致,并且后续读操作都是旧数据。
2、先更新数据库再删除缓存
  首先进行数据库的更新操作,成功之后再删除缓存,后续请求将数据写回缓存。
存在问题:
  在更新数据库和删除缓存这段时间内,请求读取的还是缓存内的旧数据,不过等数据库更新完成之后,数据就会回复一致。
3、异步更新缓存
  数据库的更新操作完成后不直接操作缓存,而是将命令封装成消息放到消息队列里,然后Redis自己去更新数据,消息队列保证数据操作数据的一致性,保证缓存数据的数据正常。
4、延时双删
  延时双删的思路是首先删除缓存,然后去更新数据库中的数据,在更新完成后sleep一段时间,然后再次删除缓存。(sleep的时间需要大于读写缓存的时间)流程如下:

  • 线程1删除缓存,然后去更新数据库;
  • 线程2来读缓存,发现缓存已被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读取到的是旧值,然后把旧值写入缓存;
  • 线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除
  • 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值。
    在这里插入图片描述

缓存问题

缓存穿透

在这里插入图片描述
  缓存穿透是指用户想查询一个数据,发现缓存中没有这个数据,于是向数据库发起查询,发现数据库中也没有这个数据,于是查询失败了。当用户请求很多的情况下,缓存和数据库中都没有数据,就会给数据库造成很大压力,这就是缓存穿透。
在这里插入图片描述
解决方案
  布隆过滤器
  使用布隆过滤器之后,将存储的数据放入布隆过滤器,每次数据查询首先查询布隆过滤器,当在布隆过滤器中判断存在时再到缓存中查询,如果在布隆过滤器中没有该数据时,则直接返回告诉用户该数据查不到,这样能够大大减轻数据库查询压力。
在这里插入图片描述
  缓存空对象
  当数据库中数据不存在时,及时返回的空对象也缓存起来,同时设置一个过期时间,之后在访问相同数据时将从缓存中获取,保护了数据库。
存在问题:
  1、对空值设置过期时间,会存在更新数据库数据到缓存数据失效的一段时间,缓存数据有问题,会对要保证数据一致性的业务造成影响。
  2、会需要更多的空间来存储更多的控制,造成内存中有大量的空值的键。

缓存击穿

  缓存击穿是指一个热点key在不停的扛着大量的并发,当key在失效的瞬间,持续的大并发就会穿破缓存,直接请求到数据库。对数据库造成瞬间压力过大。
解决方案
  第一种方案:热点数据永不过期
  缓存角度看,没有设置过期时间,就不会存在缓存过期之后产生的问题。
  加互斥锁
  使用分布式锁,保证对每个key的访问同一时刻只能有一个线程去查询后端服务,其他没有获取锁权限的线程则等待即可。

缓存雪崩

  缓存雪崩是指在某一个时间段,缓存集中过期失效或者Redis宕机。对于数据库而言,所有请求压力会全部到达数据库,导致数据库调用量暴增,可能也造成数据库宕机的情况。
在这里插入图片描述
解决方案
  Redis采用高可用
  这种方案的思路是将数据在Redis中存放在服务器上,即使一个服务器挂掉,其他服务器还可以继续工作。
  限流降级
  这种思路就是在缓存失效后,通过加锁或者队列来控制读取数据库的线程数量让线程在队列排队,控制整齐请求速率。
  数据预热
  数据预热是在正式部署服务之前,先访问一遍数据,可以将大部分的数据加载到缓存中,在即将发生大并发之前已经加载到不同的key,设置不同的过期时间,让缓存失效的时间更加均匀。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值