日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Redis中主鍵失效的原理及實現(xiàn)機制剖析

深入剖析Redis主鍵失效原理及實現(xiàn)機制

創(chuàng)新互聯(lián)是專業(yè)的懷柔網(wǎng)站建設(shè)公司,懷柔接單;提供成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進行懷柔網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

Redis作為一款高性能的鍵值對存儲系統(tǒng),被廣泛應(yīng)用于緩存、消息隊列、分布式鎖等場景,在使用Redis的過程中,我們經(jīng)常會遇到鍵值對失效的情況,那么Redis中主鍵失效的原理是什么?又是如何實現(xiàn)的呢?本文將深入剖析Redis主鍵失效的原理及實現(xiàn)機制。

Redis主鍵失效原理

在Redis中,主鍵失效主要分為兩種情況:自然失效和手動失效。

1、自然失效

自然失效是指鍵值對在Redis中存儲的時間超過了設(shè)定的過期時間,Redis會自動刪除這些鍵值對,自然失效的實現(xiàn)依賴于Redis的過期鍵清理策略。

Redis的過期鍵清理策略主要有以下幾種:

(1)惰性刪除:在客戶端訪問鍵時,檢查鍵是否已經(jīng)過期,如果已經(jīng)過期,則刪除該鍵,并返回空,這種策略的優(yōu)點是操作簡單,缺點是內(nèi)存使用效率不高,可能會出現(xiàn)大量過期鍵占用內(nèi)存的情況。

(2)定時刪除:Redis內(nèi)部維護一個定時任務(wù),按照一定的頻率掃描數(shù)據(jù)庫中的鍵,刪除過期的鍵,這種策略可以有效地清理過期鍵,但會增加CPU的負擔(dān)。

(3)定期刪除:定期刪除是定時刪除的優(yōu)化版本,它將定時掃描調(diào)整為周期性掃描,每次掃描只處理部分鍵,從而降低CPU的負擔(dān)。

2、手動失效

手動失效是指通過DEL命令或其他相關(guān)命令手動刪除鍵值對,這種情況下,鍵值對會立即失效。

Redis主鍵失效實現(xiàn)機制

下面我們將從源碼角度分析Redis主鍵失效的實現(xiàn)機制。

1、自然失效實現(xiàn)機制

(1)惰性刪除實現(xiàn)

在Redis中,惰性刪除主要在db.c文件中的lookupKey函數(shù)中實現(xiàn):

robj *lookupKey(redisDb *db, robj *key, int flags) {
    dictEntry *de = dictFind(db->dict, key->ptr);
    if (de) {
        robj *val = dictGetVal(de);
        if (expireIfNeeded(db, key) == 0) {
            /* If we are in the context of a Lua script, we return the
             * value without checking if we need to propagate the expired
             * key to AOF / slaves. */
            if (server.lua_caller) return val;
            if (flags & LOOKUP_NOTOUCH) {
                /* This is a read-only lookup, don't touch the key */
            } else {
                /* Update the access time for the ageing algorithm.
                 * Don't do it if we have a saving child, as this will trigger
                 * a copy on write madness. */
                if (!hasActiveChildProcess())
                    updateKeyAccessTime(key);
            }
            return val;
        } else {
            /* Key expired. If we are in the context of a script, it is up to
             * the script to handle the key expiration. Otherwise, we return
             * NULL to the caller, who should handle the key expiration
             * properly. */
            if (server.lua_caller) return NULL;
        }
    } else {
        /* No key */
    }
    return NULL;
}

在這個函數(shù)中,如果找到了鍵,會調(diào)用expireIfNeeded函數(shù)檢查鍵是否過期,如果過期,刪除鍵并返回0。

(2)定時刪除和定期刪除實現(xiàn)

定時刪除和定期刪除的實現(xiàn)主要在redis.c文件中的activeExpireCycle函數(shù)中:

void activeExpireCycle(int type) {
    /* This function has some global state in order to continue the work
     * incrementally across calls. */
    static unsigned int current_db = 0; /* Last DB tested. */
    static int timelimit_exit = 0;      /* Time limit hit in previous call? */
    static long long last_fast_cycle = 0; /* When last fast cycle ran. */
    int j, iteration = 0;
    int dbs_per_call = CRON_DBS_PER_CALL;
    long long start = ustime(), timelimit;
    if (type == ACTIVE_EXPIRE_CYCLE_FAST) {
        if (start < last_fast_cycle + ACTIVE_EXPIRE_CYCLE_FAST_DURATION)
            return;
        last_fast_cycle = start;
    }
    /* We usually should test CRON_DBS_PER_CALL per iteration, with
     * two exceptions:
     *
     * 1) Don't test more DBs than we have.
     * 2) If last time we hit the time limit, we want to scan all DBs
     * in this iteration, as there is work to do in some DB and we don't want
     * expired keys to use memory for too much time. */
    if (dbs_per_call > server.dbnum || timelimit_exit)
        dbs_per_call = server.dbnum;
    /* We can use at max ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC percentage of CPU time
     * per iteration. Since this function gets called with a frequency of
     * server.hz times per second, the following is the max amount of time
     * we can spend in this function. */
    timelimit = 1000000 * ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC / server.hz / 100;
    /* Iterate over a few databases at a time. */
    for (j = 0; j < dbs_per_call; j++) {
        int expired;
        redisDb *db = server.db+(current_db % server.dbnum);
        /* Increment the DB now so we are sure if we run out of time
         * in the current iteration we'll restart from the next DB. */
        current_db++;
        /* Continue to expire if at the end of the cycle more than 25%
         * of the keys were expired. */
        do {
            unsigned long num, slots;
            long long now, ttl_sum;
            int ttl_samples;
            /* If there is nothing to expire try next DB. */
            if ((num = dictSize(db->dict)) == 0) {
                db->avg_ttl = 0;
                break;
            }
            /* When we have a lot of keys to expire, we get a time sample
             * to check later if the CPU time is too high. */
            if (num > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)
                start = ustime();
            /* Here we count the number of keys that are going to be
             * expired in this loop, and the number of keys we actually
             * look at to see if they should be expired. */
            expired = 0;
            ttl_sum = 0;
            ttl_samples = 0;
            if (type == ACTIVE_EXPIRE_CYCLE_FAST) {
                slots = dictSlots(db->dict);
                /* Fast mode: Sample keys from the dictionary. */
                while (slots--) {
                    dictEntry *de = dictGetRandomKey(db->dict);
                    long long ttl;
                    if (dictGetVal(de) == NULL) {
                        /*_expired++; /* Key is already logically expired. */
                        continue;
                    }
                    ttl = dictGetSignedIntegerVal(de) - now;
                    if (activeExpireCycleTryExpire(db, de, now)) {
                        expired++;
                    } else {
                        /* If the key is non expired, add its TTL to the sum. */
                        if (ttl > 0) {
                            ttl_sum += ttl;
                            ttl_samples++;
                        }
                    }
                }
            } else {
                /* Slow mode: Check every key. */
                dictEntry *de = dictGetSafeIterator(db->dict);
                while ((de = dictNext(de)) != NULL) {
                    long long ttl;
                    if (dictGetVal(de) == NULL) {
                        expired++;
                        continue;
                    }
                    ttl = dictGetSignedIntegerVal(de) - now;
                    if (activeExpireCycleTryExpire(db, de, now)) {
                        expired++;
                    } else {
                        /* If the key is non expired, add its TTL to the sum. */
                        if (ttl > 0) {
                            ttl_sum += ttl;
                            ttl_samples++;
                        }
                    }
                }
                dictReleaseIterator(de);
            }
            /* Update the average TTL stats for this DB. */
            if (ttl_samples) {
                long long avg_ttl = ttl_sum / ttl_samples;
                /* Do a simple running average with a few samples.
                 * We just use the current estimate if the previous one
                 * was zero, otherwise we combine the two. */
                if (db->avg_ttl == 0) {
                    db->avg_ttl = avg_ttl;
                } else {
                    db->avg_ttl = (db->avg_ttl/2) + (avg_ttl/2);
                }
            }
            /* 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. */
            if (ustime() - start > timelimit) {
                timelimit_exit = 1;
                break;
            }
        } while (expired > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4);
    }
    /* Update our estimate of keys existing but yet to be expired. */
    updateKeyspaceEvents();
    /* We don't repeat the cycle if there are less than 25% of keys to
     * expire in the DB we just handled, however if we exited because of the
     * time limit, we'll try again later

網(wǎng)站題目:Redis中主鍵失效的原理及實現(xiàn)機制剖析
當(dāng)前路徑:http://m.5511xx.com/article/coegpgd.html