首先看下 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.
- * Dont 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;
- }
- }
来源: http://www.bubuko.com/infodetail-2513132.html