Redis深度历险-过期删除 Redis深度历险-过期删除

Redis深度历险-过期删除

保存过期时间

Redis支持通过TTLPTTL命令来查询剩下的存活时间

typedef struct redisDb {
    ......
    dict *expires;              /* Timeout of keys with a timeout set */
        ......
} redisDb;

在Redis中每一个数据库中有一个专门存储过期时间的字典,不管是通过什么命令设置的过期时间,内部存储的都是过期的毫秒数时间戳

Redis的过期删除策略

常用的删除策略是惰性删除和定时删除,Redis是两者结合

惰性删除

db.c/expireIfNeeded函数就是用来处理过期键,在命令真正执行之前会过滤删除掉过期的键

int expireIfNeeded(redisDb *db, robj *key) {
    //如果键没有过期,返回0
    if (!keyIsExpired(db,key)) return 0;

    //非主机或者pause状态则不会进行删除,但是返回1表示该键已过期
    if (server.masterhost != NULL) return 1;

    if (checkClientPauseTimeoutAndReturnIfPaused()) return 1;

    //lazyfree_lazy_expire配置决定同步删除还是异步删除
    if (server.lazyfree_lazy_expire) {
        dbAsyncDelete(db,key);
    } else {
        dbSyncDelete(db,key);
    }
    server.stat_expiredkeys++;
    propagateExpire(db,key,server.lazyfree_lazy_expire);
    notifyKeyspaceEvent(NOTIFY_EXPIRED,
        "expired",key,db->id);
    signalModifiedKey(NULL,db,key);
    return 1;
}
long long getExpire(redisDb *db, robj *key) {
    dictEntry *de;

    //如果key没有过期时间返回-1
    if (dictSize(db->expires) == 0 ||
       (de = dictFind(db->expires,key->ptr)) == NULL) return -1;

    //字符串转换为整数
    serverAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL);
    return dictGetSignedIntegerVal(de);
}

在各种命令中最终都会调用到此函数中,逻辑上只是从expire中查询并比较

定时删除策略

定时删除的逻辑实现在server.c/activeExpireCycle中,在Redis的定时函数server.c/serverCron中被调用

void activeExpireCycle(int type) {
    ......
      //记录此次操作的是哪个数据库
      static unsigned int current_db = 0; /* Next DB to test. */
      //遍历16个数据库,对每一个都删除一定的过期key
            for (j = 0; j < dbs_per_call && timelimit_exit == 0; j++) {
        .......

定时删除的代码比较复杂,这里简述一下定时删除的规则:

  1. 每一次定时删除都会对尝试所有的数据库进行删除操作
  2. Redis的定时删除操作是有时间限制的,超过时间会退出此函数
  3. Redis会记录当前过期的操作进度,包括操作的数据库、操作的过期键游标
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章