Redis 中哈希键(Hash)命令的实现主要包括对哈希表(dictionary)和压缩列表(ziplist)这两种数据结构的操作。哈希键在内部存储时,其编码可以是 OBJ_ENCODING_HT (哈希表)或 OBJ_ENCODING_ZIPLIST(压缩列表),选择哪种编码取决于键值对的数量和元素大小。
哈希表(OBJ_ENCODING_HT)实现:
-
Redis 使用一个全局的哈希表结构(dict)来存储键值对。这个结构包含了哈希表本身(ht[2],一般情况下只使用其中一个,另一个在 rehash 过程中作为临时存储区域)、字典大小、哈希表的负载因子(影响 rehash 触发时机)等信息。
-
哈希表中的每个键值对由一个 dictEntry 结构体表示,它包含一个指向键(通常是 sds 字符串)的指针和一个指向值(即任意类型的 redisObject)的指针。
-
哈希键的命令实现,如 HSET、HGET、HDEL、HEXISTS 等,都会先找到与给定键关联的哈希对象,然后根据其编码执行相应的操作。如果是哈希表编码,会进一步在哈希表中查找或插入键值对。
压缩列表(OBJ_ENCODING_ZIPLIST)实现:
-
当哈希键包含的元素数量少且元素值大小有限时,Redis 会选择使用压缩列表来存储。在这种编码方式下,每个哈希键的元素按照 field-value 对的形式连续存储在 ziplist 中。
-
哈希键命令在面对 ziplist 编码的哈希对象时,会通过解析 ziplist 的编码规则来定位和操作对应的 field-value 对。
-
对于哈希命令的实现,比如 HSET,在 ziplist 编码模式下,需要更新或插入元素时,Redis 会检查是否超过了配置项(如
hash-max-ziplist-entries
和hash-max-ziplist-value
)所限定的大小,如果超限则触发编码升级,将 ziplist 转换为哈希表。
哈希命令实现关键点:
-
查找操作:无论是哈希表还是压缩列表,都需要通过某种方式定位到指定的 field,前者通过哈希函数和碰撞解决机制,后者通过遍历并解析编码。
-
插入与删除操作:涉及到哈希表的扩容与缩容、键值对的插入和删除操作;对于压缩列表,还需要考虑元素的插入位置、可能的连锁更新以及是否需要升级为哈希表。
-
迭代器:Redis 为哈希类型实现了独立的迭代器,可以根据编码的不同分别提供基于哈希表或压缩列表的迭代功能。
-
内存管理:在进行任何操作时,Redis 都会关注内存的分配与回收,包括 redisObject 的引用计数变化、哈希表的 rehash 时的内存迁移、压缩列表的内存扩展或收缩等。
在源码解析过程中,我们可以深入理解 Redis 如何通过高效的哈希算法、精巧的数据结构和细致的内存管理策略来实现哈希键命令的功能,确保数据存储和访问的高效稳定。