Redis过期键


一、Redis过期键存储:
命令:expire key seconds
存储时未过期:往expire库中添加/或者替换一条expires[key]:timeout数据
此时数据库中存在两条关于这条key的信息:
dict库------dict[key]:value
expires库--expires[key]:timeout


二、Redis过期键的删除策略:

1惰性删除策略:

所有的redis命令在执行之前都会调用expireIfNeeded函数。

主库,expireIfNeeded会删除过期键。

从库,expireIfNeeded会返回一个逻辑删除的结果,但是物理删除由主库的synthesized DEL operations控制。

2.定时删除策略:

我们线上的机器为1milliseconds执行调用一次activeExpireCycle

 if (server->masterhost == NULL) activeExpireCycle();

主库,会定时删除过期键。采用策略:从一定数量的数据库的过期库中取出一定数量的随机键进行检查,不为空则删除。不保证实时删除。(具体策略见后面的代码)

从库,不执行定期删除。

综上

主库的过期键删除策略有两种:1.在执行所有操作之前调用expireIfNeeded—惰性删除。2. 1milliseconds执行调用一次activeExpireCycle,每次随机删除部分键—定时删除。

从库:过期键删除由主库的synthesized DEL operations控制。


也就是说只有主库执行删除操作,但无论是惰性删除还是定期删除都做如下操作
server->stat_expiredkeys++;  //info信息中的expired_keys的数目都会加1
dictDelete(db->expires,key->ptr);  //删除expire库中的过期键数据,同时expires库总量减一
dictDelete(db->dict,key->ptr);       //删除dict库中过期键数据,同时dict库中的总量减一


三、Redis过期键删除策略不一致造成的问题:
question:从库ttl(或者其他命令get、set等)exists显示结果不一致,貌似存在时延问题。

answer

Ttl命令执行的是

if (expireIfNeeded(db,key))return NULL;

exists命令执行的是:

expireIfNeeded(db,key);

也就是说

主库中调用expireIfNeeded,过期键都会被删除,返回结果一致。

从库中调用expireIfNeeded,返回一个逻辑值表示被删除,但实际上并未删除。expireIfNeededttl的返回结果有影响,把逻辑删除的结果作为返回。但exists只是调用expireIfNeeded,它并不参与对返回结果的判断,显示的是实际存储情况,未被删除。
如果要测试从库的某个key是否存在,可以用ttl取代exists进行判断。
ttl不会对Redis其他策略造成影响。


四、Info中关于expires键的信息:
expired_keys:历史上每一次删除过期键就做一次加操作,记录删除过期键的总数。
keys:该数据库中key的总量。
expires:该数据库中设置为过期键并且未被删除的总量(如果曾设置为过期键且删除则不计入)。

 

附函数代码:

int expireIfNeeded(redisDb *db, robj *key) {

    long long when = getExpire(db,key); //获取过期时间
    if (when < 0) return 0; //
未设置过期键 
    ......
    /*
 从库直接返回过期逻辑值,不做dbDelete*/

    if (server->masterhost != NULL) {
        return mstime() > when;
    }   
    if (mstime() <= when) return 0;  //
设置过期健但未过期
    /* Delete the key */
    server->stat_expiredkeys++;
    propagateExpire(db,key);
    return dbDelete(db,key);
}

 

 

/* Try to expire a few timed out keys. The algorithm used is adaptive and
* will use few CPU cycles if there are few expiring keys, otherwise
* it will get more aggressive to avoid that too much memory is used by
* keys that can be removed from the keyspace. */
//
自适应算法 并不保证删除所有的key
void activeExpireCycle(void) {
    int j;
    long long start = mstime();
//
轮询所有的数据库  
    for (j = 0; j < server->dbnum; j++) {
        int expired, iteration = 0;
        redisDb *db = server->db+j;

        /* Continue to expire if at the end of the cycle more than 25%
         * of the keys were expired. */
        do {
//
每个数据库轮询的次数为min(dictSize10)
            long num = dictSize(db->expires);
            long long now = mstime();

            expired = 0;
            if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
                num = REDIS_EXPIRELOOKUPS_PER_CRON;
            while (num--) {
                dictEntry *de;
                long long t;

                if ((de = dictGetRandomKey(db->expires)) == NULL) break;
                t = (long long) dictGetEntryVal(de);
                if (now > t) {
                    sds key = dictGetEntryKey(de);
                    robj *keyobj = createStringObject(key,sdslen(key));

  propagateExpire(db,keyobj);
                    dbDelete(db,keyobj);
                    decrRefCount(keyobj);
                    expired++;
                    server->stat_expiredkeys++;
                }
            }
            /* We can't block forever here even if there are many keys to
             * expire. So after a given amount of milliseconds return to the
             * caller waiting for the other active expire cycle. */
            iteration++;
            if ((iteration & 0xff) == 0 && /* Check once every 255 iterations */
                (mstime()-start) > REDIS_EXPIRELOOKUPS_TIME_LIMIT) return;//
超时退出
        } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);//
过期键数量大于2才会继续删除
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值