Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

一、哈希对象的编码

  • 哈希对象的编码可以是ziplist或者hashtable

ziplist型编码

  • ziplist编码的哈希对象使用压缩列表作为底层实现
  • 每当有新的键值对要加入到哈希对象 时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾,因此:
    • 保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在 后
    • 先添加到哈希对象中的键值对会被放在压缩列表的表头方向,而后来添加到哈希对象中 的键值对会被放在压缩列表的表尾方向
  • 举个例子,如果我们执行以下HSET命令,那么服务器将创建一个列表对象作为profile键的值,如果profile键的值对象使用的是ziplist编码,那么这个值对象将会是图2所示的样子,其 中对象所使用的压缩列表如图3所示:

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

hashtable型编码

  • hashtable编码的哈希对象使用字典作为底层实现
  • 哈希对象中的每个键值对都使用一个字典键值对来保存:
    • 字典的每个键都是一个字符串对象,对象中保存了键值对的键
    • 字典的每个值都是一个字符串对象,对象中保存了键值对的值
  • 举个例子,如果前面profile键创建的不是ziplist编码的哈希对象,而是hashtable编码的哈希对象,那么这个哈希对象应该会是下图所示的样子

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

二、编码转换

编码的规则

  • ziplist编码的规则如下:
    • 列表对象保存的所有字符串元素的长度都小于64字节
    • 列表对象保存的元素数量小于512个
  • hashtable编码的规则:
    • 不能满足上面那两个条件的列表对象需要使用hashtable编码

配置选项

  • 以上两个条件的上限值是可以修改的,具体请看配置文件中关于hash-max-ziplist-value选项 和hash-max-ziplist-entries选项的说明

演示案例

  • 以下代码展示了哈希对象因为键值对的键长度太大而引起从ziplist编码转换为hashtable编码的过程:

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

  • 除了键的长度太大会引起编码转换之外,值的长度太大也会引起编码转换,以下代码展示了这样的一个示例:

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

  • 以下代码展示了哈希对象因为包含的键值对数量过多而引起从ziplist编码转换为hashtable编码的过程:

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)

三、哈希命令的实现

  • 因为哈希键的值为哈希对象,所以用于哈希键的所有命令都是针对哈希对象来构建的, 下表列出了其中一部分哈希键命令,以及这些命令在不同编码的哈希对象下的实现方法

Redis(源码剖析):10---对象之哈希对象(HSET、HGET)