Redis的过期键删除策略

639 阅读2分钟

这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

Redis的过期键删除策略

我们知道过期键的删除策略有定时删除、惰性删除和定期删除,redis服务器实际使用的是惰性删除和定期删除

惰性删除

惰性删除策略在db.c的expireIfNeeded

/*
 * 如果 key 已经过期,那么将它删除,否则,不做动作。
 *
 * key 没有过期时间、服务器正在载入或 key 未过期时,返回 0 
 * key 已过期,那么返回正数值
 */
int expireIfNeeded(redisDb *db, robj *key) {
    // 取出 key 的过期时间
    long long when = getExpire(db,key);

    // key 没有过期时间,直接返回
    if (when < 0) return 0; /* No expire for this key */

    /* Don't expire anything while loading. It will be done later. */
    // 不要在服务器载入数据时执行过期
    if (server.loading) return 0;

    /* If we are running in the context of a slave, return ASAP:
     * the slave key expiration is controlled by the master that will
     * send us synthesized DEL operations for expired keys.
     *
     * Still we try to return the right information to the caller, 
     * that is, 0 if we think the key should be still valid, 1 if
     * we think the key is expired at this time. */
    // 如果服务器作为附属节点运行,那么直接返回
    // 因为附属节点的过期是由主节点通过发送 DEL 命令来删除的
    // 不必自主删除
    if (server.masterhost != NULL) {
        // 返回一个理论上正确的值,但不执行实际的删除操作
        return mstime() > when;
    }

    /* Return when this key has not expired */
    // 未过期
    if (mstime() <= when) return 0;

    /* Delete the key */
    server.stat_expiredkeys++;

    // 传播过期命令
    propagateExpire(db,key);

    // 从数据库中删除 key
    return dbDelete(db,key);
}

所有读写数据库的redis命令在执行之前都会调用expireIfNeeded函数对输入键进行检查,如果输入键已经过期,那么expireIfNeeded函数将输入键从数据库中删除,如果输入键未过期,不删除键

定期删除

定期删除策略在redis,c的activeExpireCycle中,当redis的服务器周期性操作redis.c的serverCron函数的时候调用activeExpireCycle,在规定时间内分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键

每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键

全局变量current_db会记录当前activeExpireCycle函数检查的进度,并在下一次activeExpireCycle函数调用时,接着上一次进度进行处理

随着activeExpireCycle的不断执行,服务器的所有数据都会被检查一遍,这时函数将current_db变量重置为0,然后再次进行新一轮的检查