链表    

首先Redis中存在的抽象结构为List,而链表是其一种实现方式,当list元素较多或者元素都为比较长的字符串时,采用链表作为底层实现。此外,链表还用在Redis服务器保存客户端状态、发布与订阅功能等等。

       在Redis中,链表是双向链表,其Node结构定义如左图,List的定义如右图:

redis 建库 redis创建数据表_redis 建库

redis 建库 redis创建数据表_多态_02

观察得知,Redis中链表的特点如下

  1. 无环(头节点的pre指向null,尾节点的next也指向null)
  2. 具有头指针和尾指针,找表头和表尾的时间复杂度都是O(1)
  3. 双端
  4. 多态(由于多态的存在,使得链表可以保存不同类型的值并正常处理)
  5. 带有链表长度len

字典

       Key-value键值对,key独一无二,Redis的数据库就是用这种数据结构实现的,使用哈希表来实现,其中哈希表节点定义如左图所示,哈希表整个的定义如右图所示:

redis 建库 redis创建数据表_redis 建库_03

redis 建库 redis创建数据表_Redis_04

 

Hash节点的next指针用来链接同一个hash值的元素(链地址法解决冲突,添加到表头O(1))

下图是整个字典的实现,其中type用于指示键值对的类型,是为了创建多态字典,Redis为用途不同的字典配置不同的类型函数,具体如右图所示:

redis 建库 redis创建数据表_redis 建库_05

redis 建库 redis创建数据表_Redis_06

 

Redis采用MurmurHash2算法来计算hash值

Rehash操作

  1. 为hash[1]表分配空间:
  1. 如果执行扩展操作,则分配为超过hash[0].used*2的最小2^n;
  2. 如果执行收缩操作,则分配为超过hash[0].used的最小2^n;
  1. 将hash[0]上所有元素rehash到hash[1]上
  2. 释放hash[0],将hash[1]置为hash[0],在hash[1]上新建一个空白表

那么到底啥时候进行Rehash扩容呢?

  1. 服务器目前没在BGSAVE 或则BVGEWRITEAOF,且hash表的负载因子>=1;
  2. 服务器目前在BGSAVE 或则BVGEWRITEAOF,且hash表的负载因子>=5;
  3. 缩容是负载因子<0.1时

渐进式Hash

       在字典中维护一个rehashIdx属性,在rehash期间,每次进行更新、删除、查找、添加时,除了进行原有操作外,额外还将hash[0]中的rehashIdx对应的项rehash到hash[1]中去,然后将rehashIdx+1;直到所有都移动完毕,rehashIdx恢复-1。

注意,在rehash期间,所有的添加操作都在hash[1]上进行,查找、更新、删除则要从两个表都进行。