redis的LRU策略理解
阿新 • • 發佈:2018-03-02
判斷 lag frequency actually nds 次循環 mac 例如 cron
首先看下serverCron中,服務器每次循環執行的時候,都會刷新server.lrulock。
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { ... server.lruclock = getLRUClock(); ...
使用的方法是getLRUClock,LRU_CLOCK_RESOLUTION代表LRU算法的精度,即一個LRU的單位是多長時間。LRU_CLOCK_MAX代表邏輯時鐘的最大位數,類似現實中的表盤,劃分了最大的刻度,一個刻度是一個LRU大小。所以整個方法表示的含義為:當前時間是LRU的單位的多少倍,即已經過了多少個LRU,然後對最大刻度LRU_CLOCK_MAX取模。
unsigned int getLRUClock(void) { return (mstime()/LRU_CLOCK_RESOLUTION) & LRU_CLOCK_MAX; }
了解以上概念後,再看到創建object對象的時候,會給其lru屬性賦值,下次被訪問時也會更新。
robj *createObject(int type, void *ptr) { robj *o = zmalloc(sizeof(*o)); o->type = type; o->encoding = OBJ_ENCODING_RAW; o->ptr = ptr; o->refcount = 1; /* Set the LRU to the current lruclock (minutes resolution). */ o->lru = LRU_CLOCK(); return o; }
/* Low level key lookup API, not actually called directly from commands * implementations that should instead rely on lookupKeyRead(), * lookupKeyWrite() and lookupKeyReadWithFlags().*/ robj *lookupKey(redisDb *db, robj *key, int flags) { dictEntry *de = dictFind(db->dict,key->ptr); if (de) { robj *val = dictGetVal(de); /* 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 (server.rdb_child_pid == -1 && server.aof_child_pid == -1 && !(flags & LOOKUP_NOTOUCH)) { val->lru = LRU_CLOCK(); } return val; } else { return NULL; } }
使用的方法是LRU_CLOCK,server.hz代表服務器刷新的頻率,意思是如果服務器的時間更新精度值比LRU的精度值要小(精度值表示一次刷新的間隔時間,越小精度越高),說明服務器的精度更高,直接用服務器的時間。舉例如果服務器精度是10ms, LRU精度是100ms,則在100ms內服務器進行10次刷新,得到的server.lrulock都是一樣,既然如此,不必調用getLRUCLOCK()函數增加額外的開銷。
/* Macro used to obtain the current LRU clock. * If the current resolution is lower than the frequency we refresh the * LRU clock (as it should be in production servers) we return the * precomputed value, otherwise we need to resort to a system call. */ #define LRU_CLOCK() ((1000/server.hz <= LRU_CLOCK_RESOLUTION) ? server.lruclock : getLRUClock())
那麽obj的lru值是如何使用的呢,判斷一個key是否需要過期淘汰時,先計算其最近沒有使用的時間,方法如下:獲取當前時鐘,如果obj的lru小於當前時鐘,則獲取obj到當前時鐘間隔了多少個LRU單位時間,再乘以LRU_CLOCK_RESOLUTION即得到真實毫秒數。
/* Given an object returns the min number of milliseconds the object was never * requested, using an approximated LRU algorithm. */ unsigned long long estimateObjectIdleTime(robj *o) { unsigned long long lruclock = LRU_CLOCK(); if (lruclock >= o->lru) { return (lruclock - o->lru) * LRU_CLOCK_RESOLUTION; } else { return (lruclock + (LRU_CLOCK_MAX - o->lru)) * LRU_CLOCK_RESOLUTION; } }
redis的LRU策略理解