Redis hash详解| 小册免费学

194 阅读2分钟

Redis hash详解.png

dict

hash通过dict实现,可dict不只是在hash中使用,过期时间、zset的score与value都是dict实现的

dict 结构内部包含两个 hashtable,通常情况下只有一个 hashtable 是有值的。但是在 dict 扩容缩容时,需要分配新的 hashtable,然后进行渐进式搬迁,这时候两个 hashtable 存储的分别是旧的 hashtable 和新的 hashtable。待搬迁结束后,旧的 hashtable 被删除,新的 hashtable 取而代之。

typedef struct dict{
    //类型特定函数
    dictType *type;
    //私有数据
    void *privdata;
    //哈希表
    dictht ht[2];
    //rehash索引
    //当rehash不在进行时,值为-1
    int rehashidx;
} dict;

type和privdata属性是针对不同类型的键值对,为丰富键值对的使用场景而设置的。

  • type属性是一个指向dictType的结构指针,每个dictType结构保存了一簇用于操作特定类型键值对的函数,Redis为用途不同的字典设置不同类型特定函数。
typedef struct dictType{
    //计算哈希值的函数
    unsigned int (*hashFunction)(const void *key);
    //复制键的函数
    void *(*keyDup)(void *privdata,const void *key)
    ...
}
  • privdata属性保存了需要传给那些类型特定函数的可选参数

image.png

hashtable

struct dictEntry {
    void* key;
    //值
    union{
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;
    dictEntry* next; // next是指向另一个哈希节点的指针,可将多个哈希值相同的键值对连接在一起,以此来解决冲突。
}
struct dictht {
    dictEntry** table; // 二维
    long size; // 第一维数组的长度
    long used; // hash 表中的元素个数
    //哈希表大小掩码,用于计算索引值
    //总是等于size-1
    unsigned long sizemask;
}

Redis计算哈希值方法: hash=dict->type->hashFunction(key); 计算索引值的方法:index=hash & dict->ht[x].sizemask;

扩容

  1. 为字典ht[1]哈希表分配空间,大小取决于要执行的操作与ht[0]当前键值对的数量。
  2. 将保存在ht[0]中的所有键值对存放到ht[1]指定的位置。
  3. 当ht[0]的所有键值对都迁移完毕后,释放ht[0],并指向ht[1],并在ht[1]上创建一个空的哈希表,为下次rehash准备。
  • 服务器目前没有在执行BGSAVE命令或BGREWRITEAOF命令,并且哈希表的负载因子>=1。
  • 服务器正在执行BGSAVE命令或BGREWRITEAOF命令,并且哈希表的负载因子>=5。

渐进式rehash的过程

在rehash的期间,字典同时使用ht[0],ht[1]两个哈希表。对哈希表的操作会在两个表上进行,比如查找键时,先在ht[0]里面查找,如果为空,就继续到ht[1]里查找。在此期间,新增的键值对都会被添加到ht[1]中,ht[0]不承担任何添加操作,保证ht[0]中的键值对只能是越来越少。

文章末尾请带上以下文字及链接:本文正在参与「掘金小册免费学啦!」活动, 点击查看活动详情