news 2026/5/12 13:22:58

Redis 数据结构之 List 详细解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis 数据结构之 List 详细解析

Redis 数据结构详解:List 列表篇

在 Redis 的五大基础数据结构中,List(列表)是一种非常灵活的有序字符串集合,它既可以充当栈和队列,也能实现消息队列、时间线等业务场景。本文将带你从底层特性、核心命令、内部编码到实战场景,全面吃透 Redis List。


一、List 列表是什么?

List 是 Redis 中存储多个有序字符串的序列,每个元素称为element,一个列表最多可以存储2 32 − 1 2^{32}-12321个元素。它的核心特性可以概括为三点:

  1. 有序性:列表中的元素是按插入顺序排列的,我们可以通过下标(正索引 / 负索引)获取指定元素,例如获取第 5 个元素用index 4,或直接用负索引lindex \-1获取最后一个元素。

  2. 元素可重复:列表中允许存在相同的值,比如[“a”, “b”, “a”] 这样的结构是完全合法的。

  3. 操作灵活性:支持从两端(左 / 右)插入、弹出元素,也支持按范围截取、按索引修改,能同时适配栈、队列等多种数据结构的使用需求。

List 的基础操作示意图如下:


二、List 核心命令详解

List 的命令可以分为基础操作阻塞操作两大类,我们按功能逐一拆解说明。

1. 基础操作命令

(1)添加元素:LPUSH / LPUSHX / RPUSH / RPUSHX

这组命令用于向列表中插入元素,区别在于插入方向和是否仅在列表存在时操作。

命令作用语法时间复杂度
LPUSH从列表左侧(表头)插入一个或多个元素LPUSH key element [element \.\.\.\]单个元素O ( 1 ) O(1)O(1),多个元素O ( N ) O(N)O(N)
LPUSHX仅当列表存在时,从左侧插入元素LPUSHX key element [element \.\.\.\]单个元素O ( 1 ) O(1)O(1),多个元素O ( N ) O(N)O(N)
RPUSH从列表右侧(表尾)插入一个或多个元素RPUSH key element [element \.\.\.\]单个元素O ( 1 ) O(1)O(1),多个元素O ( N ) O(N)O(N)
RPUSHX仅当列表存在时,从右侧插入元素RPUSHX key element [element \.\.\.\]单个元素O ( 1 ) O(1)O(1),多个元素O ( N ) O(N)O(N)

示例:

# 从左侧插入元素 127.0.0.1:6379> LPUSH mylist "world" (integer) 1 127.0.0.1:6379> LPUSH mylist "hello" (integer) 2 # 查看列表所有元素 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello" 2) "world"
(2)获取元素:LRANGE / LINDEX / LLEN

这组命令用于读取列表中的元素信息,不修改列表本身。

  • LRANGE key start stop:获取列表中从startstop索引区间的所有元素(左闭右闭),支持负索引(\-1表示最后一个元素)。

  • LINDEX key index:获取列表中指定索引位置的元素,索引超出范围返回nil

  • LLEN key:获取列表的长度,时间复杂度为O ( 1 ) O(1)O(1)

示例:

# 继续上面的示例 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello" 2) "world" 127.0.0.1:6379> LINDEX mylist 0 "hello" 127.0.0.1:6379> LINDEX mylist -1 "world" 127.0.0.1:6379> LLEN mylist (integer) 2
(3)插入 / 修改 / 删除元素:LINSERT / LREM / LTRIM / LSET

这组命令用于修改列表的结构或元素值。

  • LINSERT key BEFORE|AFTER pivot element:在列表中指定元素pivot的前 / 后插入新元素。

  • LREM key count value:删除列表中前count个值为value的元素(count\>0从左删,count\<0从右删,count=0删除所有匹配元素)。

  • LTRIM key start stop:截取列表中startstop区间的元素,其余元素全部删除,常用于实现固定长度列表。

  • LSET key index value:修改列表中指定索引位置的元素值,索引超出范围会报错。

示例:

# 在 "world" 前插入 "there" 127.0.0.1:6379> LINSERT mylist BEFORE "world" "there" (integer) 3 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello" 2) "there" 3) "world" # 修改索引1的元素为 "hi" 127.0.0.1:6379> LSET mylist 1 "hi" OK 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello" 2) "hi" 3) "world"

2. 阻塞操作命令:BLPOP / BRPOP

BLPOPBRPOPLPOPRPOP的阻塞版本,它们的核心区别在于:

  • 非阻塞版(LPOP/RPOP):如果列表为空,直接返回nil

  • 阻塞版(BLPOP/BRPOP):如果列表为空,会阻塞等待指定时间,直到有新元素加入或超时才返回结果。

命令语法
BLPOP key [key ...] timeout BRPOP key [key ...] timeout
  • key:要监听的列表键,可以同时监听多个;

  • timeout:阻塞等待的超时时间(单位:秒),0表示永久阻塞。

核心特性
  1. 多键监听:可以同时监听多个列表,按顺序检查列表,哪个列表有元素就从哪个列表弹出。

  2. 客户端公平性:多个客户端同时阻塞等待同一个列表时,遵循 “先到先得” 原则,先执行命令的客户端会优先获取元素。

  3. 超时机制:超时时间到了仍无元素加入,返回nil

阻塞 vs 非阻塞对比
场景非阻塞版(LPOP)阻塞版(BLPOP)
列表不为空直接弹出元素,返回结果直接弹出元素,返回结果
列表为空立即返回nil阻塞等待,直到有元素加入或超时

示意图如下:


三、List 内部编码实现

Redis 为了兼顾性能和内存占用,为 List 设计了两种内部编码,会根据列表的元素数量和元素长度自动切换:

1. ziplist(压缩列表)

当列表同时满足以下两个条件时,使用ziplist作为内部编码:

  • 列表中元素数量小于list\-max\-ziplist\-entries(默认 512);

  • 每个元素的长度都小于list\-max\-ziplist\-value(默认 64 字节)。

ziplist是一种紧凑的连续内存结构,通过减少额外指针和元数据来节省内存,适合存储少量、短字符串元素。

2. linkedlist(双向链表)

当列表不满足ziplist的条件时,Redis 会自动切换为linkedlist编码:

  • 元素数量超过 512 个;

  • 任意一个元素长度超过 64 字节。

linkedlist是标准的双向链表结构,每个节点包含前驱 / 后继指针和元素值,虽然内存占用比ziplist高,但插入、删除元素的时间复杂度为O ( 1 ) O(1)O(1),适合处理大量元素或长字符串元素。

示例:

# 查看小列表的编码 127.0.0.1:6379> LPUSH smalllist "a" "b" "c" (integer) 3 127.0.0.1:6379> OBJECT ENCODING smalllist "ziplist" # 查看长字符串列表的编码 127.0.0.1:6379> LPUSH biglist "a very long string that exceeds 64 bytes..." (integer) 1 127.0.0.1:6379> OBJECT ENCODING biglist "linkedlist"

四、List 典型使用场景

List 的特性决定了它非常适合处理 “有序、需频繁两端操作” 的业务场景,以下是最常见的两个场景:

1. 阻塞式消息队列(生产者 - 消费者模型)

利用LPUSH(生产者写入)和BRPOP(消费者读取)可以实现经典的阻塞式消息队列:

  • 生产者:使用LPUSH将消息写入列表;

  • 消费者:使用BRPOP阻塞等待消息,有消息时立即处理,无消息时阻塞等待,避免轮询空列表消耗资源。

示意图如下:

如果需要实现多消费者的负载均衡,可以同时监听多个列表键,实现 “发布 - 订阅” 模式的扩展。

2. 社交平台时间线(Timeline)

微博、朋友圈这类社交平台的时间线功能,本质上就是基于 List 实现的:

  1. 存储单条动态:每条微博 / 朋友圈作为一条数据,存入 Hash 结构中;

  2. 构建时间线列表:用户发布动态时,用LPUSH将动态 ID 写入用户的时间线列表(user:1:blogs),保证最新的动态在列表最前面;

  3. 分页查询:使用LRANGE user:1:blogs 0 9分页获取动态 ID,再批量查询 Hash 中的动态详情。

这种实现方式既保证了时间线的有序性,又支持高效的分页查询,是 List 最经典的实战场景之一。


五、List 命令时间复杂度总结

为了方便大家快速回顾,这里整理了 List 所有核心命令的时间复杂度:

操作类型命令时间复杂度
添加LPUSH/RPUSH/LPUSHX/RPUSHX单个元素O ( 1 ) O(1)O(1),多个元素O ( N ) O(N)O(N)
查找LRANGEO ( N ) O(N)O(N)(N 为返回元素个数)
LINDEX/LLENO ( 1 ) O(1)O(1)
修改LINSERT/LSETO ( N ) O(N)O(N)(N 为列表长度)
删除LREM/LTRIMO ( N ) O(N)O(N)(N 为列表长度)
阻塞操作BLPOP/BRPOPO ( 1 ) O(1)O(1)

List 作为 Redis 中唯一的有序序列结构,凭借灵活的操作和高效的性能,在消息队列、时间线等场景中有着不可替代的作用。理解它的底层编码和命令特性,才能在业务中选择最合适的实现方式。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 13:18:54

迁移至 Taotoken 平台后 API 密钥管理与审计日志带来的安全感

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 迁移至 Taotoken 平台后 API 密钥管理与审计日志带来的安全感 在集成多个大模型服务到业务系统的过程中,API密钥的管理…

作者头像 李华
网站建设 2026/5/12 13:18:07

OmenSuperHub终极指南:免费开源工具彻底释放惠普OMEN游戏本性能

OmenSuperHub终极指南:免费开源工具彻底释放惠普OMEN游戏本性能 【免费下载链接】OmenSuperHub 使用 WMI BIOS控制性能和风扇速度,自动解除DB功耗限制。 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否为官方Omen Gaming Hub的…

作者头像 李华
网站建设 2026/5/12 13:17:02

ArcGIS Pro新手避坑:从零到一创建并编辑线状Shapefile的保姆级流程

ArcGIS Pro新手避坑指南:从零到一创建并编辑线状Shapefile的完整流程 当你第一次打开ArcGIS Pro,面对琳琅满目的工具和复杂的界面,创建和编辑线状Shapefile可能会让你感到不知所措。这篇文章将带你避开那些新手常踩的坑,从文件创…

作者头像 李华
网站建设 2026/5/12 13:13:31

ARMv8/v9架构中SCTLR2MASK_EL2寄存器详解与应用

1. ARM架构中的系统控制寄存器概述 在ARMv8/v9架构中,系统控制寄存器(System Control Registers)是处理器核心功能配置的关键组件。这些寄存器控制着处理器的内存管理、异常处理、安全状态等基础行为。其中,SCTLR(系统控制寄存器)系列是最核心的配置寄存…

作者头像 李华
网站建设 2026/5/12 13:12:40

基于YOLOv7的森林火灾烟雾检测系统:从算法原理到工程部署

1. 项目概述与核心价值 森林火灾是全球性的生态灾难,其破坏力不仅在于瞬间吞噬大片林木,更在于火势蔓延的不可预测性和扑救的极端困难性。传统的火灾监测手段,如瞭望塔人工值守、卫星遥感等,存在响应延迟长、受天气影响大、夜间或…

作者头像 李华