Appearance
List(列表)
1. 概述
List是简单的字符串列表,按插入顺序排序。
常用命令:LPUSH、RPUSH、LPOP、RPOP、LRANGE、LINDEX、LSET
2. 底层数据结构
2.1 三种编码
| 编码 | 说明 | 适用场景 |
|---|---|---|
| ziplist | 压缩列表,小列表 | 少量元素 |
| quicklist | 快速列表(Redis 3.2+) | 大列表 |
| linkedlist | 双端链表,旧版本 | 历史兼容 |
2.2 quicklist
Redis 3.2+使用quicklist作为List的底层实现:
quicklist = [quicklistNode1] → [quicklistNode2] → [quicklistNode3]
↓ ↓ ↓
[ziplist] [ziplist] [ziplist]设计思想:结合ziplist和linkedlist的优点
- ziplist:内存紧凑,缓存局部性好
- linkedlist:O(1)头尾操作
2.3 quicklistNode结构
c
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl; // 指向ziplist
unsigned int sz; // ziplist字节大小
unsigned int count: 16; // ziplist中元素数量
unsigned int encoding: 2; // 1=原生,2=lzf压缩
unsigned int container: 2; // 1=ziplist,2=quicklistNode
unsigned int recompress: 1; // 是否需要解压
unsigned int attempted_compress: 1;
unsigned int extra: 10;
} quicklistNode;2.4 配置参数
bash
# 压缩深度(两端各多少个节点不压缩)
list-compress-depth 0
# 单节点ziplist最大大小(字节)
list-max-ziplist-size -2
# 元素数量限制
list-max-ziplist-entries 5123. 编码转换
ziplist → quicklist → quicklist(压缩)转换条件:
- list-max-ziplist-size > 0:ziplist字节大小限制
- list-max-ziplist-entries > 0:元素数量限制
4. 面试考点
Q1: Redis List的底层实现?
答案: Redis 3.2+使用quicklist作为List的底层实现,由多个ziplist节点组成双向链表。每个quicklistNode包含一个ziplist,平衡了内存紧凑性和头尾操作的O(1)复杂度。
Q2: 为什么用quicklist而不是linkedlist?
答案: linkedlist每个节点独立分配内存,内存碎片化且缓存局部性差。quicklist将多个元素存储在一个ziplist中,减少内存分配,提高缓存命中率。综合了ziplist紧凑和linkedlist灵活的优点。
Q3: LPUSH和RPUSH的时间复杂度?
答案: 都是O(1)。quicklist在头尾操作时直接操作对应的ziplist,无需遍历。
5. 应用场景
5.1 消息队列
bash
LPUSH queue:msg "msg1"
LPUSH queue:msg "msg2"
RPOP queue:msg # "msg1"
RPOP queue:msg # "msg2"注意:Redis的list做消息队列有风险,缺少消息确认机制,建议使用Stream。
5.2 排行榜
bash
LPUSH rank:user:1001 100 # 用户得分
LRANGE rank:user:1001 0 -1 # 获取排名列表5.3 最新消息列表
bash
LPUSH latest:news "news1"
LPUSH latest:news "news2"
LPUSH latest:news "news3"
LTRIM latest:news 0 99 # 只保留前100条
LRANGE latest:news 0 -1 # 获取最新100条6. 实践问题
Q: List如何实现异步队列?
答案: 使用RPOPLPUSH或BLPOP/BRPOP实现可靠队列:
bash
# 生产者
RPUSH queue:task "task1"
# 消费者
BRPOP queue:task 0 # 阻塞获取
RPUSH queue:processed "task1" # 处理完移到已处理队列Q: 如何控制List内存占用?
答案: 通过配置参数控制:
list-max-ziplist-size:单个ziplist最大字节list-max-ziplist-entries:单个ziplist最大元素数list-compress-depth:两端不压缩的节点数
