redis過(guò)期數(shù)據(jù)刪除策略

系列

redis數(shù)據(jù)淘汰原理
redis過(guò)期數(shù)據(jù)刪除策略
redis server事件模型
redis cluster mget 引發(fā)的討論
redis 3.x windows 集群搭建
redis 命令執(zhí)行過(guò)程
redis string底層數(shù)據(jù)結(jié)構(gòu)
redis list底層數(shù)據(jù)結(jié)構(gòu)
redis hash底層數(shù)據(jù)結(jié)構(gòu)
redis set底層數(shù)據(jù)結(jié)構(gòu)
redis zset底層數(shù)據(jù)結(jié)構(gòu)
redis 客戶端管理
redis 主從同步-slave端
redis 主從同步-master端
redis 主從超時(shí)檢測(cè)
redis aof持久化
redis rdb持久化
redis 數(shù)據(jù)恢復(fù)過(guò)程
redis TTL實(shí)現(xiàn)原理
redis cluster集群建立
redis cluster集群選主

過(guò)期數(shù)據(jù)刪除策略

?redis的過(guò)期數(shù)據(jù)刪除策略使用了惰性刪除和定期刪除兩種策略:

  • 惰性刪除發(fā)生在redis處理讀寫(xiě)請(qǐng)求的過(guò)程,如get/set等命令驾凶。
  • 定期刪除發(fā)生在redis內(nèi)部定時(shí)任務(wù)執(zhí)行過(guò)程中宏榕,限制占用cpu的時(shí)間玖瘸。


定期刪除

?redis的定期刪除是通過(guò)定時(shí)任務(wù)實(shí)現(xiàn)的两波,也就是定時(shí)任務(wù)會(huì)循環(huán)調(diào)用serverCron方法埃唯。然后定時(shí)檢查過(guò)期數(shù)據(jù)的方法是databasesCron免糕。
?定期刪除的一大特點(diǎn)就是考慮了定時(shí)刪除過(guò)期數(shù)據(jù)會(huì)占用cpu時(shí)間善镰,所以每次執(zhí)行databasesCron的時(shí)候會(huì)限制cpu的占用不超過(guò)25%是目。

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
    // 省略了很多無(wú)關(guān)代碼

    /* We need to do a few operations on clients asynchronously. */
    // 檢查客戶端谤饭,關(guān)閉超時(shí)客戶端,并釋放客戶端多余的緩沖區(qū)
    clientsCron();

    /* Handle background operations on Redis databases. */
    // 對(duì)數(shù)據(jù)庫(kù)執(zhí)行各種操作
    databasesCron();



?activeExpireCycle執(zhí)行過(guò)期數(shù)據(jù)的刪除懊纳,其他的動(dòng)作不在該部分討論當(dāng)中揉抵。

// 對(duì)數(shù)據(jù)庫(kù)執(zhí)行刪除過(guò)期鍵,調(diào)整大小嗤疯,以及主動(dòng)和漸進(jìn)式 rehash
void databasesCron(void) {

    // 如果服務(wù)器不是從服務(wù)器冤今,那么執(zhí)行主動(dòng)過(guò)期鍵清除
    if (server.active_expire_enabled && server.masterhost == NULL)
        // 清除模式為 CYCLE_SLOW ,這個(gè)模式會(huì)盡量多清除過(guò)期鍵
        activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);

    // 在沒(méi)有 BGSAVE 或者 BGREWRITEAOF 執(zhí)行時(shí)茂缚,對(duì)哈希表進(jìn)行 rehash
    if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
        static unsigned int resize_db = 0;
        static unsigned int rehash_db = 0;
        unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
        unsigned int j;

        /* Don't test more DBs than we have. */
        // 設(shè)定要測(cè)試的數(shù)據(jù)庫(kù)數(shù)量
        if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;

        /* Resize */
        // 調(diào)整字典的大小
        for (j = 0; j < dbs_per_call; j++) {
            tryResizeHashTables(resize_db % server.dbnum);
            resize_db++;
        }

        /* Rehash */
        // 對(duì)字典進(jìn)行漸進(jìn)式 rehash
        if (server.activerehashing) {
            for (j = 0; j < dbs_per_call; j++) {
                int work_done = incrementallyRehash(rehash_db % server.dbnum);
                rehash_db++;
                if (work_done) {
                    /* If the function did some work, stop here, we'll do
                     * more at the next cron loop. */
                    break;
                }
            }
        }
    }
}



?刪除過(guò)期數(shù)據(jù)的整個(gè)過(guò)程主要按照下面的邏輯進(jìn)行:

  • 遍歷指定個(gè)數(shù)的db(如16)進(jìn)行刪除操作
  • 針對(duì)每個(gè)db隨機(jī)獲取過(guò)期數(shù)據(jù)每次遍歷不超過(guò)指定數(shù)量(如20)戏罢,發(fā)現(xiàn)過(guò)期數(shù)據(jù)并進(jìn)行刪除。
  • 每個(gè)db的次數(shù)累積到16次的時(shí)候會(huì)進(jìn)行判斷時(shí)間是否超過(guò)25%脚囊,超過(guò)就停止刪除數(shù)據(jù)過(guò)程龟糕。
  • 最后如果刪除的過(guò)期數(shù)據(jù)耗時(shí)(通過(guò)開(kāi)始結(jié)束時(shí)間統(tǒng)計(jì))超過(guò)待過(guò)期時(shí)間數(shù)量的25%的時(shí)候就停止刪除過(guò)期數(shù)據(jù)過(guò)程。
  • timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100的解釋是:server.hz代表每秒調(diào)用的次數(shù),所以上面這個(gè)公司就是每次執(zhí)行占用的時(shí)候的25%用于過(guò)期數(shù)據(jù)刪除悔耘。
void activeExpireCycle(int type) {
    // 靜態(tài)變量讲岁,用來(lái)累積函數(shù)連續(xù)執(zhí)行時(shí)的數(shù)據(jù)
    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. */

    unsigned int j, iteration = 0;
    // 默認(rèn)每次處理的數(shù)據(jù)庫(kù)數(shù)量
    unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
    // 函數(shù)開(kāi)始的時(shí)間
    long long start = ustime(), timelimit;

    // 快速模式
    if (type == ACTIVE_EXPIRE_CYCLE_FAST) {
        // 如果上次函數(shù)沒(méi)有觸發(fā) timelimit_exit ,那么不執(zhí)行處理
        if (!timelimit_exit) return;
        // 如果距離上次執(zhí)行未夠一定時(shí)間衬以,那么不執(zhí)行處理
        if (start < last_fast_cycle + ACTIVE_EXPIRE_CYCLE_FAST_DURATION*2) return;
        // 運(yùn)行到這里缓艳,說(shuō)明執(zhí)行快速處理,記錄當(dāng)前時(shí)間
        last_fast_cycle = start;
    }

    /* 
     * 一般情況下看峻,函數(shù)只處理 REDIS_DBCRON_DBS_PER_CALL 個(gè)數(shù)據(jù)庫(kù)郎任,
     * 除非:
     *
     * 1) 當(dāng)前數(shù)據(jù)庫(kù)的數(shù)量小于 REDIS_DBCRON_DBS_PER_CALL
     * 2) 如果上次處理遇到了時(shí)間上限,那么這次需要對(duì)所有數(shù)據(jù)庫(kù)進(jìn)行掃描备籽,
     *     這可以避免過(guò)多的過(guò)期鍵占用空間
     */
    if (dbs_per_call > server.dbnum || timelimit_exit)
        dbs_per_call = server.dbnum;

    // 函數(shù)處理的微秒時(shí)間上限
    // ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 默認(rèn)為 25 舶治,也即是 25 % 的 CPU 時(shí)間
    timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;
    timelimit_exit = 0;
    if (timelimit <= 0) timelimit = 1;

    // 如果是運(yùn)行在快速模式之下
    // 那么最多只能運(yùn)行 FAST_DURATION 微秒 
    // 默認(rèn)值為 1000 (微秒)
    if (type == ACTIVE_EXPIRE_CYCLE_FAST)
        timelimit = ACTIVE_EXPIRE_CYCLE_FAST_DURATION; /* in microseconds. */

    // 遍歷數(shù)據(jù)庫(kù)
    for (j = 0; j < dbs_per_call; j++) {
        int expired;
        // 指向要處理的數(shù)據(jù)庫(kù)
        redisDb *db = server.db+(current_db % server.dbnum);

        // 為 DB 計(jì)數(shù)器加一分井,如果進(jìn)入 do 循環(huán)之后因?yàn)槌瑫r(shí)而跳出
        // 那么下次會(huì)直接從下個(gè) DB 開(kāi)始處理
        current_db++;

        do {
            unsigned long num, slots;
            long long now, ttl_sum;
            int ttl_samples;

            /* If there is nothing to expire try next DB ASAP. */
            // 獲取數(shù)據(jù)庫(kù)中帶過(guò)期時(shí)間的鍵的數(shù)量
            // 如果該數(shù)量為 0 ,直接跳過(guò)這個(gè)數(shù)據(jù)庫(kù)
            if ((num = dictSize(db->expires)) == 0) {
                db->avg_ttl = 0;
                break;
            }
            // 獲取數(shù)據(jù)庫(kù)中鍵值對(duì)的數(shù)量
            slots = dictSlots(db->expires);
            // 當(dāng)前時(shí)間
            now = mstime();

            // 這個(gè)數(shù)據(jù)庫(kù)的使用率低于 1% 霉猛,掃描起來(lái)太費(fèi)力了(大部分都會(huì) MISS)
            // 跳過(guò)尺锚,等待字典收縮程序運(yùn)行
            if (num && slots > DICT_HT_INITIAL_SIZE &&
                (num*100/slots < 1)) break;

            /* 
             * 樣本計(jì)數(shù)器
             */
            // 已處理過(guò)期鍵計(jì)數(shù)器
            expired = 0;
            // 鍵的總 TTL 計(jì)數(shù)器
            ttl_sum = 0;
            // 總共處理的鍵計(jì)數(shù)器
            ttl_samples = 0;

            // 每次最多只能檢查 LOOKUPS_PER_LOOP 個(gè)鍵
            if (num > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)
                num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP;

            // 開(kāi)始遍歷數(shù)據(jù)庫(kù)
            while (num--) {
                dictEntry *de;
                long long ttl;

                // 從 expires 中隨機(jī)取出一個(gè)帶過(guò)期時(shí)間的鍵
                if ((de = dictGetRandomKey(db->expires)) == NULL) break;
                // 計(jì)算 TTL
                ttl = dictGetSignedIntegerVal(de)-now;
                // 如果鍵已經(jīng)過(guò)期,那么刪除它惜浅,并將 expired 計(jì)數(shù)器增一
                if (activeExpireCycleTryExpire(db,de,now)) expired++;
                if (ttl < 0) ttl = 0;
                // 累積鍵的 TTL
                ttl_sum += ttl;
                // 累積處理鍵的個(gè)數(shù)
                ttl_samples++;
            }

            /* Update the average TTL stats for this database. */
            // 為這個(gè)數(shù)據(jù)庫(kù)更新平均 TTL 統(tǒng)計(jì)數(shù)據(jù)
            if (ttl_samples) {
                // 計(jì)算當(dāng)前平均值
                long long avg_ttl = ttl_sum/ttl_samples;
                
                // 如果這是第一次設(shè)置數(shù)據(jù)庫(kù)平均 TTL 瘫辩,那么進(jìn)行初始化
                if (db->avg_ttl == 0) db->avg_ttl = avg_ttl;
                /* Smooth the value averaging with the previous one. */
                // 取數(shù)據(jù)庫(kù)的上次平均 TTL 和今次平均 TTL 的平均值
                db->avg_ttl = (db->avg_ttl+avg_ttl)/2;
            }

            // 我們不能用太長(zhǎng)時(shí)間處理過(guò)期鍵,
            // 所以這個(gè)函數(shù)執(zhí)行一定時(shí)間之后就要返回

            // 更新遍歷次數(shù)
            iteration++;

            // 每遍歷 16 次執(zhí)行一次
            if ((iteration & 0xf) == 0 && /* check once every 16 iterations. */
                (ustime()-start) > timelimit)
            {
                // 如果遍歷次數(shù)正好是 16 的倍數(shù)
                // 并且遍歷的時(shí)間超過(guò)了 timelimit
                // 那么斷開(kāi) timelimit_exit
                timelimit_exit = 1;
            }

            // 已經(jīng)超時(shí)了坛悉,返回
            if (timelimit_exit) return;

            // 如果已刪除的過(guò)期鍵占當(dāng)前總數(shù)據(jù)庫(kù)帶過(guò)期時(shí)間的鍵數(shù)量的 25 %
            // 那么不再遍歷
        } while (expired > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4);
    }
}


惰性過(guò)期

?執(zhí)行數(shù)據(jù)寫(xiě)入過(guò)程中伐厌,首先通過(guò)expireIfNeeded函數(shù)對(duì)寫(xiě)入的key進(jìn)行過(guò)期判斷。

/*
 * 為執(zhí)行寫(xiě)入操作而取出鍵 key 在數(shù)據(jù)庫(kù) db 中的值裸影。
 *
 * 和 lookupKeyRead 不同挣轨,這個(gè)函數(shù)不會(huì)更新服務(wù)器的命中/不命中信息。
 *
 * 找到時(shí)返回值對(duì)象轩猩,沒(méi)找到返回 NULL 卷扮。
 */
robj *lookupKeyWrite(redisDb *db, robj *key) {

    // 刪除過(guò)期鍵
    expireIfNeeded(db,key);

    // 查找并返回 key 的值對(duì)象
    return lookupKey(db,key);
}



?執(zhí)行數(shù)據(jù)讀取過(guò)程中,首先通過(guò)expireIfNeeded函數(shù)對(duì)寫(xiě)入的key進(jìn)行過(guò)期判斷均践。

/*
 * 為執(zhí)行讀取操作而取出鍵 key 在數(shù)據(jù)庫(kù) db 中的值晤锹。
 *
 * 并根據(jù)是否成功找到值,更新服務(wù)器的命中/不命中信息彤委。
 *
 * 找到時(shí)返回值對(duì)象鞭铆,沒(méi)找到返回 NULL 。
 */
robj *lookupKeyRead(redisDb *db, robj *key) {
    robj *val;

    // 檢查 key 釋放已經(jīng)過(guò)期
    expireIfNeeded(db,key);

    // 從數(shù)據(jù)庫(kù)中取出鍵的值
    val = lookupKey(db,key);

    // 更新命中/不命中信息
    if (val == NULL)
        server.stat_keyspace_misses++;
    else
        server.stat_keyspace_hits++;

    // 返回值
    return val;
}



?執(zhí)行過(guò)期動(dòng)作expireIfNeeded其實(shí)內(nèi)部做了三件事情焦影,分別是:

  • 查看key判斷是否過(guò)期
  • 向slave節(jié)點(diǎn)傳播執(zhí)行過(guò)期key的動(dòng)作并發(fā)送事件通知
  • 刪除過(guò)期key
/*
 * 檢查 key 是否已經(jīng)過(guò)期衔彻,如果是的話,將它從數(shù)據(jù)庫(kù)中刪除偷办。
 *
 * 返回 0 表示鍵沒(méi)有過(guò)期時(shí)間,或者鍵未過(guò)期澄港。
 *
 * 返回 1 表示鍵已經(jīng)因?yàn)檫^(guò)期而被刪除了椒涯。
 */
int expireIfNeeded(redisDb *db, robj *key) {

    // 取出鍵的過(guò)期時(shí)間
    mstime_t when = getExpire(db,key);
    mstime_t now;

    // 沒(méi)有過(guò)期時(shí)間
    if (when < 0) return 0; /* No expire for this key */

    /* Don't expire anything while loading. It will be done later. */
    // 如果服務(wù)器正在進(jìn)行載入,那么不進(jìn)行任何過(guò)期檢查
    if (server.loading) return 0;

    // 當(dāng)服務(wù)器運(yùn)行在 replication 模式時(shí)
    // 附屬節(jié)點(diǎn)并不主動(dòng)刪除 key
    // 它只返回一個(gè)邏輯上正確的返回值
    // 真正的刪除操作要等待主節(jié)點(diǎn)發(fā)來(lái)刪除命令時(shí)才執(zhí)行
    // 從而保證數(shù)據(jù)的同步
    if (server.masterhost != NULL) return now > when;

    // 運(yùn)行到這里回梧,表示鍵帶有過(guò)期時(shí)間废岂,并且服務(wù)器為主節(jié)點(diǎn)

    /* Return when this key has not expired */
    // 如果未過(guò)期,返回 0
    if (now <= when) return 0;

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

    // 向 AOF 文件和附屬節(jié)點(diǎn)傳播過(guò)期信息
    propagateExpire(db,key);

    // 發(fā)送事件通知
    notifyKeyspaceEvent(REDIS_NOTIFY_EXPIRED,
        "expired",key,db->id);

    // 將過(guò)期鍵從數(shù)據(jù)庫(kù)中刪除
    return dbDelete(db,key);
}



?判斷key是否過(guò)期的數(shù)據(jù)結(jié)構(gòu)是db->expires狱意,也就是通過(guò)expires的數(shù)據(jù)結(jié)構(gòu)判斷數(shù)據(jù)是否過(guò)期湖苞。
內(nèi)部獲取過(guò)期時(shí)間并返回。

/* Return the expire time of the specified key, or -1 if no expire
 * is associated with this key (i.e. the key is non volatile) 
 *
 * 返回給定 key 的過(guò)期時(shí)間详囤。
 *
 * 如果鍵沒(méi)有設(shè)置過(guò)期時(shí)間财骨,那么返回 -1 镐作。
 */
long long getExpire(redisDb *db, robj *key) {
    dictEntry *de;

    /* No expire? return ASAP */
    // 獲取鍵的過(guò)期時(shí)間
    // 如果過(guò)期時(shí)間不存在,那么直接返回
    if (dictSize(db->expires) == 0 ||
       (de = dictFind(db->expires,key->ptr)) == NULL) return -1;

    /* The entry was found in the expire dict, this means it should also
     * be present in the main dict (safety check). */
    redisAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL);

    // 返回過(guò)期時(shí)間,#define dictGetSignedIntegerVal(he) ((he)->v.s64)
    return dictGetSignedIntegerVal(de);
}



?整個(gè)數(shù)據(jù)查找過(guò)程類比hashtab的查找過(guò)程隆箩,首先定位hash桶该贾,然后遍歷hash桶下掛的鏈查找對(duì)應(yīng)的節(jié)點(diǎn)。

/*
 * 返回字典中包含鍵 key 的節(jié)點(diǎn)
 *
 * 找到返回節(jié)點(diǎn)捌臊,找不到返回 NULL
 *
 * T = O(1)
 */
dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    unsigned int h, idx, table;

    // 字典(的哈希表)為空
    if (d->ht[0].size == 0) return NULL; /* We don't have a table at all */

    // 如果條件允許的話杨蛋,進(jìn)行單步 rehash
    if (dictIsRehashing(d)) _dictRehashStep(d);

    // 計(jì)算鍵的哈希值
    h = dictHashKey(d, key);
    // 在字典的哈希表中查找這個(gè)鍵
    // T = O(1)
    for (table = 0; table <= 1; table++) {

        // 計(jì)算索引值
        idx = h & d->ht[table].sizemask;

        // 遍歷給定索引上的鏈表的所有節(jié)點(diǎn),查找 key
        he = d->ht[table].table[idx];
        // T = O(1)
        while(he) {

            if (dictCompareKeys(d, key, he->key))
                return he;

            he = he->next;
        }

        // 如果程序遍歷完 0 號(hào)哈希表理澎,仍然沒(méi)找到指定的鍵的節(jié)點(diǎn)
        // 那么程序會(huì)檢查字典是否在進(jìn)行 rehash 逞力,
        // 然后才決定是直接返回 NULL ,還是繼續(xù)查找 1 號(hào)哈希表
        if (!dictIsRehashing(d)) return NULL;
    }

    // 進(jìn)行到這里時(shí)糠爬,說(shuō)明兩個(gè)哈希表都沒(méi)找到
    return NULL;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寇荧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秩铆,更是在濱河造成了極大的恐慌砚亭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件殴玛,死亡現(xiàn)場(chǎng)離奇詭異捅膘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)滚粟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)寻仗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人凡壤,你說(shuō)我怎么就攤上這事署尤。” “怎么了亚侠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵曹体,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我硝烂,道長(zhǎng)箕别,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任滞谢,我火速辦了婚禮串稀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狮杨。我一直安慰自己母截,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布橄教。 她就那樣靜靜地躺著清寇,像睡著了一般喘漏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颗管,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天陷遮,我揣著相機(jī)與錄音,去河邊找鬼垦江。 笑死帽馋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的比吭。 我是一名探鬼主播绽族,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼衩藤!你這毒婦竟也來(lái)了吧慢?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赏表,失蹤者是張志新(化名)和其女友劉穎检诗,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瓢剿,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逢慌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了间狂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攻泼。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鉴象,靈堂內(nèi)的尸體忽然破棺而出忙菠,到底是詐尸還是另有隱情,我是刑警寧澤纺弊,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布牛欢,位于F島的核電站,受9級(jí)特大地震影響淆游,放射性物質(zhì)發(fā)生泄漏傍睹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一稽犁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骚亿,春花似錦已亥、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)震鹉。三九已至,卻和暖如春捆姜,著一層夾襖步出監(jiān)牢的瞬間传趾,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工泥技, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浆兰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓珊豹,卻偏偏與公主長(zhǎng)得像簸呈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子店茶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本文對(duì)Redis的過(guò)期機(jī)制簡(jiǎn)單的講解一下講解之前我們先拋出一個(gè)問(wèn)題蜕便,我們知道很多時(shí)候服務(wù)器經(jīng)常會(huì)用到redis作為...
    小陳阿飛閱讀 1,284評(píng)論 0 0
  • 制定Redis過(guò)期策略,是整個(gè)Redis緩存策略的關(guān)鍵之一贩幻,因?yàn)閮?nèi)存來(lái)說(shuō)轿腺,公司不可能無(wú)限大,所以就要對(duì)key進(jìn)行一...
    JackFrost_fuzhu閱讀 4,839評(píng)論 1 10
  • #少些吼叫多些愛(ài)#我在行動(dòng)#第4天# 4月3日丛楚,哥哥從早上10點(diǎn)到下午4點(diǎn)在新東方學(xué)習(xí)族壳,我?guī)е妹盟透绺缟险n、接哥...
    格格貓_真閱讀 175評(píng)論 0 0
  • 探·產(chǎn)業(yè)深耕之道鸯檬,創(chuàng)·運(yùn)營(yíng)價(jià)值高地 —3月16日决侈,產(chǎn)業(yè)地產(chǎn)運(yùn)營(yíng)高峰論壇與你不期而遇 引言:“2018,我們要做的...
    陳丹瑤閱讀 145評(píng)論 0 0
  • 山色晴嵐雨后清喧务, 綠風(fēng)拂岸草亭亭赖歌。 魚(yú)蝦弄影天門(mén)過(guò), 樓宇平波澧水橫功茴。 古寺深幽鐘鼓短庐冯, 民歌高亢調(diào)音明。 庸...
    東林梁閱讀 348評(píng)論 1 27