面试题答案
一键面试数据结构
- Redis对象结构:在Redis中,所有的数据都是以对象的形式存在。对于Hash类型,其底层数据结构主要有两种:压缩列表(ziplist)和哈希表(hashtable)。
- 压缩列表(ziplist):当Hash对象中的元素个数较少,且每个元素的键和值的长度都较短时,Redis会使用压缩列表来存储。压缩列表是一种紧凑的、连续内存的数据结构,它将多个元素按照顺序依次存储在一块连续的内存区域中,每个元素由前一个元素的长度、自身长度等信息组成,这种结构节省内存,但查找效率相对较低,时间复杂度为O(n)。
- 哈希表(hashtable):当Hash对象中的元素个数较多,或者某个元素的键或值长度较长时,Redis会将其转换为哈希表存储。哈希表是一种基于哈希函数的数据结构,它通过对键进行哈希计算,将键值对分布到不同的桶(bucket)中,从而实现快速的查找、插入和删除操作,平均时间复杂度为O(1)。Redis的哈希表使用链地址法(separate chaining)来解决哈希冲突,即当不同的键计算出相同的哈希值时,会将这些键值对以链表的形式存储在同一个桶中。
- 哈希表结构细节:Redis的哈希表由
dict
结构表示,它包含两个哈希表ht[0]
和ht[1]
,在正常情况下只使用ht[0]
,ht[1]
用于在哈希表进行扩展或收缩时临时使用。每个哈希表由dictEntry
数组组成,每个dictEntry
存储一个键值对,同时包含指向下一个dictEntry
的指针(用于解决哈希冲突)。
主要检查逻辑
- 类型检查:在Redis执行命令时,首先会检查操作的键是否存在以及其类型是否为Hash。通过
redisObject
的type
字段可以快速判断对象类型,当类型为REDIS_HASH
时,表明该对象是Hash类型。 - 底层数据结构检查:
- 压缩列表判断:在对Hash对象进行操作时,Redis会检查当前Hash对象是否使用压缩列表存储。这可以通过检查对象的编码(
encoding
字段)来确定,当编码为REDIS_ENCODING_ZIPLIST
时,表明使用压缩列表。在使用压缩列表时,由于其查找效率低,所以遍历操作相对简单,按顺序查找每个元素。 - 哈希表判断:当编码为
REDIS_ENCODING_HT
时,表明使用哈希表存储。在进行查找、插入、删除等操作时,首先根据键计算哈希值,然后根据哈希值确定对应的桶位置。如果桶中存在多个键值对(即发生哈希冲突),则通过链表逐个比较键,直到找到目标键或遍历完链表。
- 压缩列表判断:在对Hash对象进行操作时,Redis会检查当前Hash对象是否使用压缩列表存储。这可以通过检查对象的编码(
- 内存使用检查:Redis会根据Hash对象的元素个数以及每个元素的大小来决定是否需要在压缩列表和哈希表之间进行转换。当使用压缩列表存储的Hash对象元素个数超过
hash-max-ziplist-entries
配置项(默认512),或者单个元素的键或值长度超过hash-max-ziplist-value
配置项(默认64字节)时,Redis会将压缩列表转换为哈希表,以提高操作效率。反之,在某些情况下(如哈希表元素个数减少到一定程度),哈希表也可能转换回压缩列表以节省内存。