问题引入

  Redis是一款基于内存的key-value数据库,内存使用率是咱们十分关注的一个指标。

  通常咱们都能够通过『EXPIRE key seconds』等形式,为指定键设置生存工夫;待过期后,Redis会主动删除该键值对,以此避免内存应用持续增长。

  然而,生产环境中,往往存在很多键值对都没有设置正当的生存工夫;随着业务的继续倒退,内存使用量也持续增长。

  DBA或者研发人员,在监控到Redis占用内存过高时,能够手动清理某些长期不拜访的键值对。如何判断一个键值对多久没有被拜访了呢?能够通过命令object idletime实现,该命令返回的是以后键从上一次拜访到当初通过的工夫(单位,秒):

127.0.0.1:6379> object idletime key(integer) 2

  在一次统计过程中,发现有一批key曾经很长时间没有拜访了(数月),然而object idletime命令却表明最近刚被拜访过(甚至数秒内)。

  为什么会不准呢?为此钻研了下object idletime的实现原理。

object idletime实现

  Redis外部对象应用构造体redisObject示意,其定义为:

typedef struct redisObject {    //数据类型,string,list,hash等    unsigned type:4;    //编码,即底层采纳哪种数据结构    unsigned encoding:4;        //缓存淘汰应用;会存储上一次该对象的拜访工夫    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or                            * LFU data (least significant 8 bits frequency                            * and most significant 16 bits access time). */    //援用计数    int refcount;    //指向对应的数据结构    void *ptr;} robj;

  能够看到,正因为redisObject.lru字段的存在,咱们才能够获取到任何一个对象的闲暇工夫,以后工夫 - 上次访问工夫lru,即可。

  object命令的实现函数为objectCommand。

objectCommand(client *c)     objectCommandLookupOrReply(client *c, robj *key, robj *reply)        objectCommandLookup(client *c, robj *key)        robj *objectCommandLookup(client *c, robj *key) {    dictEntry *de;    if ((de = dictFind(c->db->dict,key->ptr)) == NULL) return NULL;    return (robj*) dictGetVal(de);}

  objectCommandLookup函数返回的是该键值对的值,即最终是根据key-value值对象的lru计算的。

  值对象有什么非凡吗?Redis外部的对象在某些状况下是能够共享的,比方整数。

#define OBJ_SHARED_INTEGERS 10000struct sharedObjectsStruct {    //共享的整数对象    *integers[OBJ_SHARED_INTEGERS],};set keya 1set keyb 1set keyc 1

  因而,上述命令执行后,keya、keyb以及keyc对应的值是同一个对象。而当咱们拜访keyc键时,其对应值对象的lru会更新,导致object idletime查问到的keya与keyb的闲暇工夫随之扭转。

127.0.0.1:6379> object idletime keya(integer) 1302127.0.0.1:6379> set keyb 1OK127.0.0.1:6379> get keyb"1"127.0.0.1:6379> object idletime keya(integer) 4

  业务中很多时候设置key-value只是设置一个标识,value都为数字1等(比方通过setnx实现锁),这就导致大量的键对应的值对象关联起来,object idletime随之也相互影响。

论断

  当多个键的值是一些简略整数时,他们共享同一个值对象,而object idletime命令返回的是值对象的闲暇工夫,就导致这些键的object idletime相互影响。在应用object idletime统计键的闲暇工夫,须要特地留神这一点。