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會記錄當前過期的操作進度,包括操作的數據庫、操作的過期鍵遊標
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章