redis学习笔记(16)---过期键的设置与删除

expires

  在之前数据库的结构中可以看到,每一个数据库除了用变量dict来保存所有的key-value对之外,还通过一个expires成员变量来保存所有设置了过期时间的key

typedef struct redisDb {
    dict *dict;        /* 数据库 */
    dict *expires;    /* 过期键集合 */
    ......
} redisDb;

  expires也是通过字典dict来实现的,其中每一个key-value对中的key为设置了过期时间的key,value为UNIX时间戳,为超时时间。

设置过期时间

  设置过期时间的命令主要有以下几个,其中expire都是以秒为单位,pexpire都是以毫秒为单位的。

SETEX key seconds value
EXPIRE key seconds 
EXPIREAT key timestamp
PEXPIRE key milliseconds
PEXPIREAT key milliseconds-timestamp

  这些命令最终都是调用setExpire()来将key-when对加入到集合db->expires中的。

void setExpire(redisDb *db, robj *key, long long when) {
    kde = dictFind(db->dict,key->ptr);  //首先在dict中找到key
    redisAssertWithInfo(NULL,key,kde != NULL);
    de = dictReplaceRaw(db->expires,dictGetKey(kde)); //将key加入到expires集合中
    dictSetSignedIntegerVal(de,when); //设置过期时间
}

#define dictSetSignedIntegerVal(entry, _val_) \
    do { entry->v.s64 = _val_; } while(0) 
//过期时间直接以整数的形式存放在每一个entry的val中
//而不是以robject对象的形式存在

  为了节省内存,在将过期键加入到expires字典的过程中,expires会重用dict中key对应的sds对象。
  expires中每个key-value对的value直接存放过期时间when
  如下图所示:
  redis学习笔记(16)---过期键的设置与删除_第1张图片

删除过期键

  一般的删除操作可以有三种策略:
  1)定时删除:超时时间到达时,删除
  2)惰性删除:再次访问时,删除
  3)定期删除:每隔一定周期,删除
  对于定时删除:由于数据库可能同时接受成千上万个用户的访问,那么可能有大量的key需要删除,如果我们为每一个key的超时时间都设置一个定时器,每次超时就进行删除操作,那么会导致系统性能非常低。
  对于惰性删除:如果一个过期key长期没有被访问,那么该key-value对将会一直存储在数据库中,会一直占有内存。而redis又是一个基于内存的数据库,这样很容易导致内存被耗尽。
  对于定期删除 :redis难以确定执行删除操作的时长和频率
  因此redis采用惰性删除和定期删除相结合的方式,来删除系统中的过期键。

惰性删除

  惰性删除由db.c/expireIfNeeded()函数实现,所有读写数据库的命令在执行之前都会调用expireIfNeeded()函数对要操作的key进行检查。如果key已经过期,那么将会将key从数据库中删除
  redis学习笔记(16)---过期键的设置与删除_第2张图片

定期删除

  定期删除由函数redis.c/activeExpireCycle()函数实现,每当server在调用beforeSleep()和serverCron()时,都会被调用
  这里写图片描述



本文所引用的源码全部来自Redis3.0.7版本

redis学习参考资料:
Redis 设计与实现(第二版)

你可能感兴趣的:(redis学习笔记(16)---过期键的设置与删除)