Redis中的字典(dict)是一种核心的数据结构,用于实现键值对的存储,如数据库的内部表示、缓存数据等。Redis字典的实现基于哈希表(hashtable),采用了典型的“开放地址法”( Separate Chaining)来解决哈希冲突,即在哈希表的每个槽位(bucket)中使用链表来链接所有哈希冲突的键值对。以下是Redis字典实现的一些关键点:
数据结构定义
- dictEntry:表示字典中的一个键值对节点,包含键(key)、值(value)以及指向下一个冲突节点的指针(next)。
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
struct dictEntry *next;
} dictEntry;
-
dictht:表示哈希表结构,包含一个桶数组(table)、大小(size)、掩码(sizemask,用于计算索引)、以及已使用节点的数量(used)。
-
dict:是Redis字典的结构体,包含两个dictht实例(ht[2]),一个用于当前操作,另一个备用(在rehash时使用),还包括其它如类型定义(type)、私有数据(privdata)等。
核心操作
-
初始化与销毁:
dictInit
用于初始化一个空字典,包括分配内存和初始化两个哈希表。dictFree
用于释放字典及其所有键值对占用的内存。 -
哈希函数:Redis使用特定的哈希函数来计算键的哈希值,决定其在哈希表中的位置。哈希函数的选择对性能至关重要,需要在速度和碰撞概率之间取得平衡。
-
查找、插入与删除:通过哈希函数确定键值对的位置,如果遇到哈希冲突,则遍历链表。插入和删除操作可能涉及调整哈希表大小(rehash),以维持负载因子在一个合理的范围内,通常在0.7左右。
-
渐进式rehash:当哈希表达到一定负载时,Redis会启动渐进式rehash,即分批次地将ht[0]中的键值对重新散列到ht[1],此过程在处理命令时逐步进行,以减少对服务器性能的影响。
-
迭代器:Redis提供了迭代器来遍历字典中的所有键值对,这对于备份、持久化、以及客户端遍历操作非常重要。
实现细节
-
dictType:这是一个结构体,定义了操作字典的各种函数指针,比如比较函数、哈希函数、复制函数、析构函数等,使得字典可以灵活应用于不同类型的键值对。
-
内存管理:Redis利用简单动态字符串(SDS)和其他高效内存管理策略来存储键和值,确保内存使用高效。
-
并发安全:虽然Redis单线程模型本身避免了多线程竞争,但在某些特定情况下(如Redis Cluster中的共享数据),仍然需要考虑并发控制,通常通过锁机制实现。
通过深入研究dict.c
文件中的源码,可以详细了解Redis字典的实现细节,包括哈希算法、冲突解决策略、rehash机制等。