乐趣区

关于redis:Redis之object-idletime为什么是不可靠的

问题引入

  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 10000

struct sharedObjectsStruct {
    // 共享的整数对象
    *integers[OBJ_SHARED_INTEGERS],
};


set keya 1
set keyb 1
set keyc 1

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

127.0.0.1:6379> object idletime keya
(integer) 1302
127.0.0.1:6379> set keyb 1
OK
127.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 统计键的闲暇工夫,须要特地留神这一点。

退出移动版