Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis数据结构Dict

浅析Redis底层数据结构Dict

作者:WARRIOR

Redis是一个键值型的数据库,我们可以根据键实现快速的增删改查,而键与值的映射关系正是通过Dict来实现的,当然 Dict 也是 Set Hash 的实现方式,本文就详细带大家介绍一下Redis底层数据结构 Dict,,需要的朋友可以参考下

Dict 优点在于,它能以 O(1) 的复杂度快速查询数据。怎么做到的呢?将 key 通过 Hash 函数的计算,就能定位数据在表中的位置,因为哈希表实际上是数组,所以可以通过索引值快速查询到数据。

但是存在的风险也是有,在哈希表大小固定的情况下,随着数据不断增多,那么哈希冲突的可能性也会越高。

解决哈希冲突的方式,有很多种。

Redis 采用了「链式哈希」来解决哈希冲突,在不扩容哈希表的前提下,将具有相同哈希值的数据串起来,形成链接起,以便这些数据在表中仍然可以被查询到。

接下来,详细说说 Dict 的结构设计

Dict 的结构

Dict 由三部分组成,分别是:dictdicthtdicEntry

dictht

dictht 的结构如下:

typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

dicEntry

dicEntry 结构如下

void *key;/*键*/
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v; /*值*/
    struct dictEntry *next;/*下一个 entry 的指针*/
} dictEntry;

💡 为什么是 h & sizemask ? 在根据 hash 值(h)来计算应该把 entry 放在哪个数组下标位置时,你可能会好奇,为什么不是使用 h%size ,而是使用 h&sizemask,而他们为什么可以得出一样的结果。
实际上,当散列表的大小为 2n2^n2n 时,h%sizemask 的结果与 h%size 是相同的(这里不做证明)。让我们以 size 为 8 的散列表为例:

  • size = 8,对应的 sizemask = 7 (111的二进制表示)
  • h = 18 (10010的二进制表示)
  • h%size = 18%8 = 2
  • h&sizemask = 18&7 = 2

dict

在实际使用哈希表时,Redis 没有使用 dictht ,而是定义一个 dict 结构体,如下

typedef struct dict {
    dictType *type; /* dict类型,内置不同的hash函数 */
    void *privdata; /* 私有数据,在做特殊hash运算时用 */
    dictht ht[2] ;/* 个Dict包含两个哈希表,其中一个是当前数据,另一个一般是空,rehash时使用 */
    long rehashidx; /* rehash的进度,-1表示未进行 */
    int16_t pauserehash; /* rehash是否暂停,1则暂停,0则继续 */
} dict;

Dict 的 rehash

前面我们提到,redis 使用链式哈希来解决 hash 冲突问题。但是,链式哈希也存在局限性,那就是随着链表长度的增加,Hash 表在一个位置上查询哈希项的耗时就会增加,从而增加了 Hash 表的整体查询时间,这样也会导致 Hash 表的性能下降。这时,redis 使用 rehash 来解决这个问题。

Redis 如何实现 rehash

Redis 实现 rehash 的基本思路是这样的:

什么时候进行 rehash

rehash 的新 size 是多大?

如果是扩容,则新 size 为第一个大于等于 dict.ht[0].used+1 的2n2^n2n 如果是收缩,则新 size 为第一个大于等于 dict.ht[0].used 的 2n2^n2n(不得小于4)

渐进式 rehash

rehash 的步骤

这样就巧妙地把一次性大量数据迁移工作的开销,分摊到了多次处理请求的过程中,避免了一次性 rehash 的耗时操作。

以上就是浅析Redis底层数据结构Dict的详细内容,更多关于Redis数据结构Dict的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文