Redis——第9章:数据库 + 过期/淘汰策略

  • 服务器
    • RedisServer
    • RedisClient
  • 数据库
    • RedisDb(KV键值对 + 过期字典)
    • 读写时的其他维护操作
  • 过期时间
    • 命令
    • 两种过期策略
    • 淘汰策略
  • 持久化对过期键的处理
    • 写入RDB,载入RDB,写入AOF,重写AOF,复制

1.服务器

和服务器有关的数据结构存在redisServer中,客户端存在redisClient中

struct redisServer{  
    //一个数组保存服务起中所有数据库
    redisDb *Db;
    //记录数据库大小,默认16
    int dbnum;
}

struct redisClient{  
    //客户端指向当前在使用的数据库
    redisDb *Db;
}

2.数据库

数据库格式,即db,如下图所示:分为键空间和过期字典

typedef struct redisDb{
    //其他
    ...
    //数据库键空间
    dict *dict;
    //过期字典,保存着过期时间
    dict *expires;
}redisDb;

数据库键空间中存储着所有key(字符串对象)和value(这里的value可以理解为redisObject)

过期字典中,保存key要过期的时间戳。

注:实际上dict和expires指向的key是同一块地址,该图是为了直观展示

除了对key进行常规的增删改之外,服务器还会进行额外的维护操作:

1.更新键空间命中(hit)和键空间不命中(miss)次数。

2.更新RedisObject中的lru,用于计算key的闲置时间

3.读取时候如果发现这个key已经过期,先删除再操作

4.如果使用WATCH命令监视了这个key,那么服务器在对被watch的key修改之后,会把这个key标记为dirty,从而让事务程序注意到这个key已经被修改过

5.服务器每修改一个键后,会对脏键计数器+1,主要用于触发持久化BGSAVE和复制操作

6.如果服务器开启了数据库通知功能,在对key进行修改之后,服务器将按配置发送相应的数据库通知

3.过期时间

(1)与过期时间有关的命令

expire / pExpire:设置时间段后过期,秒/毫秒expire key ttl   eg. expire apple 1000
expireAt / pExpireAt:设置时间点后过期,秒/毫秒expire key timestamp   eg. expire apple 1377333070
TTL/ PTTL:返回这个键生存时间 ,单位分别为 秒/毫秒ttl key ——>返回剩余时间
persist:取消key的过期时间persist key
setEx:原理一样,只适用字符串类型 
TIME:获取当前时间戳 

本质上expire, pExpire, expireAt的底层都是调用pExpireAt完成的

(2)过期删除策略

  • 传统过期策略:
    • 定时策略:为每个有过期时间的key创建定时器,到期就立即删除。缺点:立即删除影响CPU,定时器太多不好管理。
    • 惰性策略:放着不管,下次用到发现了再删除。缺点:如果没访问则一直占用内存,容易内存泄漏。
    • 定期策略:每隔一段时间,检查所有的过期key并删除,前两者的折中。缺点:不好控制删除频率。
  • Redis的过期策略实现:Redis服务器实际采用惰性+定期策略
    • 惰性:对Redis所有命令在执行前都会判断是否过期

  • 定期:
    • Redis会每100ms执行函数serverCron中的activeExpireCycle函数,会在规定时间分多次遍历服务器的每个数据库,从数据库的expires字段中随机检查一部分键的过期时间。
    • 全局变量current_db会记录进度,下次开启时恢复上次的进度。eg. 如果有16个数据库,从0记录到15,再恢复到0重头再来。
    • 具体实现:
      • 从过期字典中随机 20 个 key
      • 删除这 20 个 key 中已经过期的 key
      • 如果过期的 key 比率超过 1/4,那就重复步骤 1

(3)淘汰策略

  • 解决的问题:尽管有过期策略,但这都不是精准的删除,就还是会存在key没有被删除掉的场景,所以就需要内存淘汰策略进行补充。
  • 概述:当内存不足时,redis会根据配置的策略淘汰部分keys,保证写入成功。当无淘汰策略时或没有找到适合淘汰的key时,Redis直接返回out of memory错误。
  • 策略(6+2种)
策略(触发条件:内存不足以容纳新写入数据时)范围移除策略评价
noeviction(默认策略)/不移除,直接报错,DEL请求和部分特殊请求除外一般不用
allkeys-lru所有键空间最久没有使用的最常用
volatile-lruexpires字典中最久没有使用的 
allkeys-random所有键空间随机移除所有数据访问概率大致相等时,可以选择
volatile-randomexpires字典中随即移除 
volatile-ttlexpires字典中更早过期时间的key / 将要过期的key 
allkeys-lfu所有键空间使用频率(次数)最少redis4.0之后出现
volatile-lfuexpires字典中使用频率(次数)最少 
  • redis的lru策略:常规LRU会准确的淘汰掉队头的元素,但是Redis的LRU并不维护队列,只是根据配置的策略要么从所有的key中随机选择N个(N可以配置)要么从所有的设置了过期时间的key中选出N个键,然后再从这N个键中选出最久没有使用的一个key进行淘汰。

4. RDF,AOF和复制对过期键的处理

1. 写入RDB:不会写入过期数据

2. 载入RDB:如果以主服务器运行,过期键不会被载入;

                     如果以从服务器运行,过期键会被载入;

3. 写入AOF:如果键已经过期但未被删除,AOF不会记录;

                      如果键已经过期并被删除,则程序会向AOF添加DEL命令。

                      eg. 加入msg已经过期,但还未删除。系统执行 GET msg指令

                           (1)数据库发现msg过期,于是惰性删除;(2)数据库向AOF添加DEL msg指令;(3)返回空

4. 重写AOF:不会写入过期数据

5. 复制:主服务器为保证数据一致,每次删除过期key时,会向从服务器发送DEL指令。

               如果主服务器上的key没有被发现删除,则从服务器即使碰到该key也不会主动删除。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值