Redis对象(二) List

定义

Redis List 是一组连接起来的字符串集合。个数限制是 2^64-1。

使用场景

存储一批数据。例如,存储一批任务数据。

常用操作

常用操作还是聚焦于创建、查询、更新和删除。

  • 写操作相关

语法:LPUSH key value [value …] 从头部增加元素,返回值为 List 中元素的总数。

语法:RPUSH key value [value …] 从尾部增加元素,返回值为 List 中元素的总数。

语法:LPOP key 移出并获取列表的第一个元素。

语法:RPOP key 移出并获取列表的最后一个元素。

语法:LREM key count value 移出值等于 value 的元素。当 count=0,则移除所有等于 value 的元素。当 count>0,则从左侧开始移除 count 个。当 count<0,则从右到左移除 count 个。返回值为被移除元素的数量。

语法:DEL key [key…] 删除对象,返回值为成功删除了几个键。

语法:UNLINK key [key…] 删除对象。DEL 命令同步删除命令,会阻塞客户端,直到删除完成。UNLINK 命令是异步命令,只是取消 key 在键空间的关联,让其无法查到,删除是异步进行,不会阻塞客户端。

  • 读操作相关

语法:LLEN key 查看 List 的长度,即 List 中元素的总数。

语法:LRANGE key start stop 查看 start 到 stop 为角标的元素,如果 start、stop 为负数,表示倒数第几个元素。

底层实现

3.2 版本之前,List 对象有两种编码方式,一种是 ZIPLIST,另一种是 LINKEDLIST。 当满足以下条件时,用 ZIPLIST 编码:

  1. 列表对象元素个数少于 512 个;
  2. 列表对象保存的所有字符串对象长度都小于 64 字节。

ZIPLIST 底层用压缩列表实现,ZIPLIST 内存排列得很紧凑,因此减少产生内存碎片的可能性,可以有效节约内存空间。

如果不满足 ZIPLIST 编码的条件,则使用 LINKEDLIST 编码,如果用 LINKEDLIST 编码,String 对象之间依靠指针进行链接,也就是以链表的形式。LINKEDLIST 编码,删除更灵活,但内存不如 ZIPLIST 紧凑,所以只有在列表个数或节点数据长度比较大的时候,才会使用 LINKEDLIST 编码,以加快处理速度,一定程度上牺牲了内存。

3.2 版本,引入了 QUICKLIST。QUICKLIST 其实就是 ZIPLIST 和 LINKEDLIST 的结合体。一个 LINKEDLIST,但其节点是 ZIPLIST。 当数据较少的时候,QUICKLIST 的节点就只有一个,其实相当于就是一个 ZIPLIST;当数据较多的时候,则同时利用 ZIPLIST 和 LINKEDLIST 的优势。

ZIPLIST 本身存在一个连锁更新的问题,所以 Redis 7.0 之后,使用了 LISTPACK 的编码模式取代了 ZIPLIST,而它们其实本质都是一种压缩的列表,即用处都是一样的,实现细节不一样而已。

ZIPLIST 的细节,以及 LISTPACK 是怎么优化的,将在下一节介绍。

常见问题

面试的考察点集中在 List 常规操作和底层实现。常规操作熟练掌握,底层实现要了解其编码方式,以及一些基本的实现细节。

  • List 是完全先入先出吗? 提示:双端操作对象。
  • List 对象底层编码方式是什么? 提示:Redis 3.2 版本之前和之后,List 对象底层编码方式是不同的。但是切记不要背这些版本的实现,这样会让面试官觉得你完全是背,没有理解,没有实践,这会减分。最好先说下自己用的哪个版本。
Redis对象(三) 底层数据结构压缩列表
Redis对象(一) String