面试题答案
一键面试编码转换的触发条件
- 字符串对象:
- 当字符串对象保存的是整数值,并且这个整数值可以用
long
类型表示时,编码会转换为int
。例如,SET num 123
,如果Redis判断这个值可以用int
编码,就会转换。 - 当字符串对象保存的字符串长度小于等于
39
字节时,编码为embstr
。若超过39
字节,会转换为raw
。
- 当字符串对象保存的是整数值,并且这个整数值可以用
- 列表对象:
- 当列表对象中所有元素都是字符串对象,并且元素个数小于等于
512
个,每个字符串长度小于等于64
字节时,编码为ziplist
。否则,转换为linkedlist
。
- 当列表对象中所有元素都是字符串对象,并且元素个数小于等于
- 哈希对象:
- 当哈希对象的所有键值对的键和值都是字符串对象,并且键值对个数小于等于
512
个,所有键和值的字符串长度都小于等于64
字节时,编码为ziplist
。否则,转换为hashtable
。
- 当哈希对象的所有键值对的键和值都是字符串对象,并且键值对个数小于等于
- 集合对象:
- 当集合对象中的所有元素都是整数值,并且元素个数小于等于
512
个时,编码为intset
。否则,转换为hashtable
。
- 当集合对象中的所有元素都是整数值,并且元素个数小于等于
- 有序集合对象:
- 当有序集合对象的所有元素的成员都是字符串对象,并且元素个数小于等于
128
个,所有成员的字符串长度小于等于64
字节时,编码为ziplist
。否则,转换为skiplist
。
- 当有序集合对象的所有元素的成员都是字符串对象,并且元素个数小于等于
转换过程
- 以字符串对象从
embstr
转换为raw
为例:embstr
编码的字符串对象在内存中是连续的,包含一个redisObject
结构和一个sds
结构。- 当长度超过
39
字节需要转换为raw
时,Redis会重新分配内存,创建一个新的redisObject
结构和一个新的sds
结构,然后将原来embstr
中的数据复制到新的raw
结构中,最后释放原来embstr
占用的内存。
- 以列表对象从
ziplist
转换为linkedlist
为例:ziplist
是一种紧凑的存储结构。当元素个数或元素长度超出限制需要转换为linkedlist
时,Redis会为每个元素创建一个listNode
结构,每个listNode
包含前一个节点、后一个节点和元素值的指针,然后将ziplist
中的元素依次复制到linkedlist
的节点中,最后释放ziplist
占用的内存。
减少不必要编码转换的方法
- 合理设置参数:
- 可以通过修改Redis配置文件中的相关参数来调整编码转换的阈值。例如,对于列表对象、哈希对象等,可以通过调整
list-max-ziplist-entries
和list-max-ziplist-value
(列表对象相关)、hash-max-ziplist-entries
和hash-max-ziplist-value
(哈希对象相关)等参数,根据业务数据特点,适当增大这些阈值,减少编码转换的可能性。
- 可以通过修改Redis配置文件中的相关参数来调整编码转换的阈值。例如,对于列表对象、哈希对象等,可以通过调整
- 优化业务:
- 数据写入:在写入数据时,尽量控制数据的规模和大小。例如,对于列表,尽量避免一次性插入大量元素或者过长的字符串元素;对于哈希,避免键值对过多或键值过长。
- 数据结构选择:根据业务场景选择合适的数据结构。如果知道某个集合主要是存储整数值且数量不会太多,就使用集合对象而不是哈希对象来存储,这样可以保持
intset
编码,提升性能。同时,在设计数据结构时,尽量保持数据类型和规模的一致性,减少因数据变化导致的编码转换。