面试题答案
一键面试ziplist(压缩列表)
- 结构特点:
- 是一种紧凑的、为节约内存而设计的顺序存储结构。
- 它由一系列特殊编码的连续内存块组成,每个节点可以保存一个字节数组或者一个整数值。
- 其表头包括zlbytes(记录整个ziplist的字节数)、zltail(记录尾节点距离起始地址的偏移量)和zllen(记录ziplist中节点的数量)等信息。
- 适用场景:
- 当列表对象包含的元素数量较少,并且每个元素都是小整数值或者长度较短的字符串时,Redis会选择使用ziplist。这是因为ziplist可以有效节省内存空间,相比于其他结构,在这种场景下存储效率更高。
linkedlist(链表)
- 结构特点:
- 由一系列节点组成,每个节点通过指针连接,形成一个双向链表。
- 每个节点包含prev、next指针以及存储数据的空间,这种结构允许在链表的任意位置进行高效的插入和删除操作。
- 转换场景:
- 当列表对象中的元素数量超过
list-max-ziplist-entries
配置的数量(默认为512 ),或者有元素的长度超过list-max-ziplist-value
配置的大小(默认为64字节)时,Redis会将列表对象的底层存储结构由ziplist转换为linkedlist。这是因为在元素较多或元素较大时,ziplist的操作性能会下降,而linkedlist更适合这种情况,虽然它会占用更多的内存空间,但在操作效率上更有优势。
- 当列表对象中的元素数量超过
优化访问性能
- 键设计:
- 避免过长键:键的长度过长会增加内存占用,同时在查找和比较键时也会消耗更多时间。尽量保持键名简洁且有意义,例如对于存储用户订单列表的键,可以使用
user:123:orders
这种格式,而不是冗长复杂的描述。 - 合理使用前缀:通过使用公共前缀,可以方便地对相关键进行批量操作。比如对于不同用户的列表数据,可以统一使用
user:
作为前缀,然后通过SCAN
命令结合前缀进行遍历,这样可以提高键的管理和操作效率。
- 避免过长键:键的长度过长会增加内存占用,同时在查找和比较键时也会消耗更多时间。尽量保持键名简洁且有意义,例如对于存储用户订单列表的键,可以使用
- 命令选择:
- 范围操作:如果需要获取列表的部分元素,例如获取列表的前N个元素,使用
LRANGE
命令。它的时间复杂度为O(S+N),其中S为偏移量,N为获取的元素数量。相比逐个获取元素,这种方式效率更高。例如,获取列表mylist
的前10个元素,可以使用LRANGE mylist 0 9
。 - 两端操作:如果经常需要在列表两端进行插入或删除操作,如
LPUSH
(在列表头部插入)、RPUSH
(在列表尾部插入)、LPOP
(从列表头部删除)、RPOP
(从列表尾部删除)等命令,这些操作的时间复杂度为O(1),非常高效。例如,在实时消息队列场景中,使用RPUSH
将消息添加到队列尾部,使用LPOP
从队列头部取出消息进行处理。
- 范围操作:如果需要获取列表的部分元素,例如获取列表的前N个元素,使用