zoukankan      html  css  js  c++  java
  • redis 缓存策略

    redis 缓存策略
    配置项:
    maxmemory <bytes>
    maxmemory-policy noeviction

    触发时机:每次执行命令(processCommand)的时候会检测

    while 循环条件是 (mem_freed < mem_tofree),每次选择一个 bestkey 进行删除。

    1. 确定 dict
    如果是 MAXMEMORY_ALLKEYS_LRU, MAXMEMORY_ALLKEYS_RANDOM
    使用 dict 键空间
    否则使用 expires 空间

    2. 确定 bestkey
    如果是 MAXMEMORY_ALLKEYS_RANDOM 或 MAXMEMORY_VOLATILE_RANDOM
    随机选取一个 key 作为 bestkey

    如果是 MAXMEMORY_ALLKEYS_LRU 或 MAXMEMORY_VOLATILE_LRU
    随机取 maxmemory_samples 个键,选一个 idletime 最长的键作为 bestkey

    如果是 MAXMEMORY_VOLATILE_TTL
    随机取 maxmemory_samples 个键,选一个过期时间最小的键作为 bestkey

    int freeMemoryIfNeeded(void) {
        size_t mem_used, mem_tofree, mem_freed;
        int slaves = listLength(server.slaves);
        mstime_t latency, eviction_latency;
    
        /* Remove the size of slaves output buffers and AOF buffer from the
         * count of used memory. */
        mem_used = zmalloc_used_memory();
        if (slaves) {
            listIter li;
            listNode *ln;
    
            listRewind(server.slaves,&li);
            while((ln = listNext(&li))) {
                client *slave = listNodeValue(ln);
                unsigned long obuf_bytes = getClientOutputBufferMemoryUsage(slave);
                if (obuf_bytes > mem_used)
                    mem_used = 0;
                else
                    mem_used -= obuf_bytes;
            }
        }
        if (server.aof_state != AOF_OFF) {
            mem_used -= sdslen(server.aof_buf);
            mem_used -= aofRewriteBufferSize();
        }
    
        /* Check if we are over the memory limit. */
        if (mem_used <= server.maxmemory) return C_OK;
    
        if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION)
            return C_ERR; /* We need to free memory, but policy forbids. */
    
        /* Compute how much memory we need to free. */
        mem_tofree = mem_used - server.maxmemory;
        mem_freed = 0;
        latencyStartMonitor(latency);
        while (mem_freed < mem_tofree) {
            int j, k, keys_freed = 0;
    
            for (j = 0; j < server.dbnum; j++) {
                long bestval = 0; /* just to prevent warning */
                sds bestkey = NULL;
                dictEntry *de;
                redisDb *db = server.db+j;
                dict *dict;
    
                if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
                    server.maxmemory_policy == MAXMEMORY_ALLKEYS_RANDOM)
                {
                    dict = server.db[j].dict;
                } else {
                    dict = server.db[j].expires;
                }
                if (dictSize(dict) == 0) continue;
    
                /* volatile-random and allkeys-random policy */
                if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_RANDOM ||
                    server.maxmemory_policy == MAXMEMORY_VOLATILE_RANDOM)
                {
                    de = dictGetRandomKey(dict);
                    bestkey = dictGetKey(de);
                }
    
                /* volatile-lru and allkeys-lru policy */
                else if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
                    server.maxmemory_policy == MAXMEMORY_VOLATILE_LRU)
                {
                    struct evictionPoolEntry *pool = db->eviction_pool;
    
                    while(bestkey == NULL) {
                        evictionPoolPopulate(dict, db->dict, db->eviction_pool);
                        /* Go backward from best to worst element to evict. */
                        for (k = MAXMEMORY_EVICTION_POOL_SIZE-1; k >= 0; k--) {
                            if (pool[k].key == NULL) continue;
                            de = dictFind(dict,pool[k].key);
    
                            /* Remove the entry from the pool. */
                            sdsfree(pool[k].key);
                            /* Shift all elements on its right to left. */
                            memmove(pool+k,pool+k+1,
                                sizeof(pool[0])*(MAXMEMORY_EVICTION_POOL_SIZE-k-1));
                            /* Clear the element on the right which is empty
                             * since we shifted one position to the left.  */
                            pool[MAXMEMORY_EVICTION_POOL_SIZE-1].key = NULL;
                            pool[MAXMEMORY_EVICTION_POOL_SIZE-1].idle = 0;
    
                            /* If the key exists, is our pick. Otherwise it is
                             * a ghost and we need to try the next element. */
                            if (de) {
                                bestkey = dictGetKey(de);
                                break;
                            } else {
                                /* Ghost... */
                                continue;
                            }
                        }
                    }
                }
    
                /* volatile-ttl */
                else if (server.maxmemory_policy == MAXMEMORY_VOLATILE_TTL) {
                    for (k = 0; k < server.maxmemory_samples; k++) {
                        sds thiskey;
                        long thisval;
    
                        de = dictGetRandomKey(dict);
                        thiskey = dictGetKey(de);
                        thisval = (long) dictGetVal(de);
    
                        /* Expire sooner (minor expire unix timestamp) is better
                         * candidate for deletion */
                        if (bestkey == NULL || thisval < bestval) {
                            bestkey = thiskey;
                            bestval = thisval;
                        }
                    }
                }
    
                /* Finally remove the selected key. */
                if (bestkey) {
                    long long delta;
    
                    robj *keyobj = createStringObject(bestkey,sdslen(bestkey));
                    propagateExpire(db,keyobj);
                    /* We compute the amount of memory freed by dbDelete() alone.
                     * It is possible that actually the memory needed to propagate
                     * the DEL in AOF and replication link is greater than the one
                     * we are freeing removing the key, but we can't account for
                     * that otherwise we would never exit the loop.
                     *
                     * AOF and Output buffer memory will be freed eventually so
                     * we only care about memory used by the key space. */
                    delta = (long long) zmalloc_used_memory();
                    latencyStartMonitor(eviction_latency);
                    dbDelete(db,keyobj);
                    latencyEndMonitor(eviction_latency);
                    latencyAddSampleIfNeeded("eviction-del",eviction_latency);
                    latencyRemoveNestedEvent(latency,eviction_latency);
                    delta -= (long long) zmalloc_used_memory();
                    mem_freed += delta;
                    server.stat_evictedkeys++;
                    notifyKeyspaceEvent(NOTIFY_EVICTED, "evicted",
                        keyobj, db->id);
                    decrRefCount(keyobj);
                    keys_freed++;
    
                    /* When the memory to free starts to be big enough, we may
                     * start spending so much time here that is impossible to
                     * deliver data to the slaves fast enough, so we force the
                     * transmission here inside the loop. */
                    if (slaves) flushSlavesOutputBuffers();
                }
            }
            if (!keys_freed) {
                latencyEndMonitor(latency);
                latencyAddSampleIfNeeded("eviction-cycle",latency);
                return C_ERR; /* nothing to free... */
            }
        }
        latencyEndMonitor(latency);
        latencyAddSampleIfNeeded("eviction-cycle",latency);
        return C_OK;
    }
  • 相关阅读:
    子类继承和调用父类的构造方法 (转)
    数组复制 System.arraycopy 与 Arrays.copyof()
    ArrayList的使用方法 (转)
    Eclipse 的debug 用法 (转)
    for each
    二维数组 排序 随机数 练习
    react 之 reflux 填坑
    react & vue 项目创建的方式
    数组实例的 copyWithin()
    es6的正则扩展笔记之修饰符
  • 原文地址:https://www.cnblogs.com/allenwas3/p/9329599.html
Copyright © 2011-2022 走看看