欢迎使用CSDN-markdown编辑器

来源:互联网 发布:stm32和51编程一样吗 编辑:程序博客网 时间:2024/06/18 08:06

最近在做用户体系模块,其中涉及到验证码存储问题,我们目前采用的是redis分片进行缓存处理。其中搭建及配置redis很简单,此处就不再重复。下午遇到使用setex(key, seconds, value)方法,但是缓存数据未过期。然后查看了一下ShardedJedis的setex(key, seconds, value)源码,

 public String setex(String key, int seconds, String value) {    Jedis j = getShard(key);    return j.setex(key, seconds, value);  }

为什么会出现缓存数据过期未清楚的情况呢?
经过分析,查看到原来做redis分片的两台服务器,我本地是配置的从库(原来考虑的是做redis的一主二从).虽然redis.conf的 slave-read-only no
,但是配置文件没有进行修改
# Master服务器IP port
slaveof 127.0.0.1 6379

这样,缓存数据成功,但是过期时间没有生效。然后修改redis.conf中slave的配置,OK了。所以就去查看redis主键原理及实现机制。
redis三种不同的删除策略
1,定时删除

什么是定时删除?顾名思义,就是我定个时间,到点就删除,有什么好处呢,对内存是最友好的,可以保证过期键会被尽快的删除掉,内存被尽早的释放出来,但是硬币都有两面啊,内存友好了,CUP时间呢,到点就删除到点就删除,CUP不干别的事了,光做删除过期键操作了,不现实,并且服务器还要创建大量的定时器,来实现定时删除,如果内存现在并不缺少,有空闲的内存,而这个时候有大量的命令请求在等待服务器处理,那么服务器也应该优先把CUP时间给处理客户端请求上,而不是删除过期键上。

所以定时删除不是一个完美的策略。

2,懒惰删除

那么什么时候是逼不得已的时候呢,客户端现在取这个数据了,这个key已经过期了,明显不能返回给客户端,这个时候也就是懒到家的时候了,不删不行啊,客户端那边不愿意啊,可以看出,这个策略对内存是极不好的,没有建设节约型社会,但是CUP时间是最友好的,不会轻易动用CUP时间去删除过期键。

3,定期删除

定期?比定时时间长一点,不会时刻的去检查过期键,删除过期键,定期删除,是每隔一段时间检查一次数据库,删除里面的过期键,很明显定期删除是定时删除和懒惰删除的一个折中。
Redis时间上采用了惰性删除和定期删除两种策略配合使用,可以更好的使CUP时间和内存区的平衡
本文讨论Redis的过期键删除策略就不能不提AOF和RDB两种备份策略对过期键的处理

首先说一下RDB

我们知道服务器启动的时候如果开启了RDB功能,服务器会对RDB文件进行载入

这里分两种情况

1,主服务器模式,会被文件中的键进行检查,过期的键忽略,所以过期键对主服务器不会造成影响,

2,从服务器模式,无论过期不过期全部载入数据库中,不过主服务器在进行数据同步的时候,从服务器的数据会被清空,所以一般来说,对从服务器来说也不会造成影响

然后是AOF

记住一点,在执行AOF重写的时候,过期键不会被保存到重写后的AOF文件中,所以过期键不会对AOF造成影响。

还有就是主从复制的时候

主删除一个过期键,会显示的告诉从

从在执行客户端发送的读命令时,即使是过期键也不会删除过期键,而是像处理未过期键一样处理,从只有介绍到主的Del命令才会删除

Redis 中的主键失效是如何实现的,即失效的主键是如何删除的?实际上,Redis 删除失效主键的方法主要有两种:

  •消极方法(passive way),在主键被访问时如果发现它已经失效,那么就删除它

  •积极方法(active way),周期性地从设置了失效时间的主键中选择一部分失效的主键删除
消极方法
  在大致了解了 Redis 是如何维护设置了失效时间的主键之后,我们就先来看一看 Redis 是如何实现消极地删除失效主键的。【代码段二】给出了一个名为 expireIfNeeded 的函数,这个函数在任何访问数据的函数中都会被调用,也就是说 Redis 在实现 GET、MGET、HGET、LRANGE 等所有涉及到读取数据的命令时都会调用它,它存在的意义就是在读取数据之前先检查一下它有没有失效,如果失效了就删除它。【代码段二】中给出了 expireIfNeeded 函数的所有相关描述,这里就不再重复它的实现方法了。这里需要说明的是在 expireIfNeeded 函数中调用的另外一个函数 propagateExpire,这个函数用来在正式删除失效主键之前广播这个主键已经失效的信息,这个信息会传播到两个目的地:一个是发送到 AOF文件,将删除失效主键的这一操作以 DEL Key 的标准命令格式记录下来;另一个就是发送到当前 Redis 服务器的所有 Slave,同样将删除失效主键的这一操作以 DEL Key 的标准命令格式告知这些 Slave 删除各自的失效主键。从中我们可以知道,所有作为 Slave 来运行的 Redis 服务器并不需要通过消极方法来删除失效主键,它们只需要对 Master 唯命是从就 OK 了!
 积极方法

  以上我们通过对 expireIfNeeded 函数的介绍了解了 Redis 是如何以一种消极的方式删除失效主键的,但是仅仅通过这种方式显然是不够的,因为如果某些失效的主键迟迟等不到再次访问的话,Redis 就永远不会知道这些主键已经失效,也就永远也不会删除它们了,这无疑会导致内存空间的浪费。因此,Redis 还准备了一招积极的删除方法,该方法利用 Redis 的时间事件来实现,即每隔一段时间就中断一下完成一些指定操作,其中就包括检查并删除失效主键。这里我们说的时间事件的回调函数就是 serverCron,它在 Redis 服务器启动时创建,每秒的执行次数由宏定义 REDIS_DEFAULT_HZ 来指定,默认每秒钟执行10次。【代码段四】给出该时间事件创建时的程序代码,该代码在 redis.c文件的 initServer 函数中。实际上,serverCron 这个回调函数不仅要进行失效主键的检查与删除,还要进行统计信息的更新、客户端连接超时的控制、BGSAVE 和 AOF 的触发等等,这里我们仅关注删除失效主键的实现,也就是函数 activeExpireCycle。
给出了函数 activeExpireCycle 的实现及其详细描述,其主要实现原理就是遍历处理 Redis 服务器中每个数据库的 expires 字典表中,从中尝试着随机抽样 REDIS_EXPIRELOOKUPS_PER_CRON(默认值为10)个设置了失效时间的主键,检查它们是否已经失效并删除掉失效的主键,如果失效的主键个数占本次抽样个数的比例超过25%,Redis 会认为当前数据库中的失效主键依然很多,所以它会继续进行下一轮的随机抽样和删除,直到刚才的比例低于25%才停止对当前数据库的处理,转向下一个数据库。这里我们需要注意的是,activeExpireCycle 函数不会试图一次性处理Redis中的所有数据库,而是最多只处理 REDIS_DBCRON_DBS_PER_CALL(默认值为16),此外 activeExpireCycle 函数还有处理时间上的限制,不是想执行多久就执行多久,凡此种种都只有一个目的,那就是避免失效主键删除占用过多的CPU资源。【代码段五】有对 activeExpireCycle 所有代码的详细描述,从中可以了解该函数的具体实现方法。

0 0
原创粉丝点击