当前位置: 首页 > news >正文

Redis List 类型全解析

文章目录

  • 1.引言
  • 2.List 类型核心命令
    • 2.1 插入命令:lpush /rpush/lpushx /rpushx
      • 2.1.1 lpush
      • 2.1.2 rpush
      • 2.1.3 lpushx
      • 2.1.4 rpushx
    • 2.2 删除命令
      • 2.2.1 lpop
      • 2.2.2 rpop
      • 2.2.3 blpop /brpop
    • 2.3 查询命令
      • 2.3.1 lrange
      • 2.3.2 lindex
      • 2.3.3 llen
    • 2.4 修改与删除指定元素命令
      • 2.4.1 linsert
      • 2.4.2 lset
      • 2.4.3 lrem
      • 2.4.4 ltrim
  • 3.List 类型的底层编码
  • 4.应用场景
    • 4.1 有序数据存储
    • 4.2 分布式消息队列
      • 分频道的消息队列
    • 4.3 分页
      • 4.3.1 基础实现:基于lrange的分页
      • 4.3.2 核心优化:解决 “中间页查询低效” 问题
      • 4.3.3 额外优化:减少网络请求次数
    • 4.4 业务视角
  • 5.小结

1.引言

在 Redis 的常用数据类型中,List(列表)是兼顾 “有序性” 与 “灵活性” 的代表 —— 它既可以像数组一样按下标访问元素,也能像双端队列一样高效地从两端插入 / 删除数据,甚至能模拟栈、消息队列等经典数据结构。本文将从 List 的核心特性出发,系统拆解其命令体系、底层编码优化逻辑,以及在实际业务中的典型应用场景,帮助你掌握 “如何用 List 解决分布式系统中的有序数据存储与交互问题”。

在这里插入图片描述

2.List 类型核心命令

2.1 插入命令:lpush /rpush/lpushx /rpushx

2.1.1 lpush

lpush key element [element ...]

  • 功能:从列表头部(左侧) 插入 1 个或多个元素;若 Key 不存在,会先创建空列表再插入。
  • 时间复杂度:O (1)
  • 返回值:插入元素后,列表的总长度。

在这里插入图片描述
在这里插入图片描述

2.1.2 rpush

rpush key element [element ...]

  • 功能:从列表尾部(右侧) 插入 1 个或多个元素;若 Key 不存在,会先创建空列表再插入。
  • 时间复杂度:O(1)。
  • 返回值:插入元素后,列表的总长度。

在这里插入图片描述

2.1.3 lpushx

lpushx key element [element ...]

  • 功能:仅当 Key已存在时,从列表头部插入 1 个或多个元素;若 Key 不存在,不执行任何操作。
  • 时间复杂度:O(1)。
  • 返回值:插入元素后列表的总长度(Key 不存在时返回 0)。

在这里插入图片描述
在这里插入图片描述

2.1.4 rpushx

rpushx key element [element ...]

  • 功能:仅当 Key已存在时,从列表尾部插入 1 个或多个元素;若 Key 不存在,不执行任何操作。
  • 时间复杂度:O(1)。
  • 返回值:插入元素后列表的总长度(Key 不存在时返回 0)。

2.2 删除命令

2.2.1 lpop

lpop key [count]

  • 功能:从列表头部移除 1 个或count个元素;若 Key 不存在或列表为空,返回nil。
  • 时间复杂度:O (1)
  • 返回值:移除的元素(移除 1 个时返回单个值,移除多个时返回元素列表)。

在这里插入图片描述

2.2.2 rpop

rpop key [count]

  • 功能:从列表尾部移除 1 个或count个元素;若 Key 不存在或列表为空,返回nil。
  • 时间复杂度:O(1)。
  • 返回值:移除的元素(移除 1 个时返回单个值,移除多个时返回元素列表)。

在这里插入图片描述
redis中的list是一个双端队列,从两头插入删除都是非常高效的O(1)

搭配使用lpush(rpush) rpop(lpop)就是一个队列
搭配使用lpush(rpush) lpop(rpop)就是一个栈

2.2.3 blpop /brpop

blpop key [key ...] timeout

  • 功能:阻塞式从 “第一个非空列表” 的头部移除元素:
    • 若传入多个 Key,按顺序检查每个 Key 对应的列表,找到第一个非空列表并移除头部元素;
    • 若所有列表均为空,阻塞等待timeout秒(timeout=0表示永久阻塞),超时后返回nil。
  • 时间复杂度:O(1)。
  • 返回值:数组形式,第一个元素是 “移除元素所在的 Key”,第二个元素是 “移除的元素”(超时返回nil)。

阻塞队列:
1)如果队列为空,尝试出队列–》阻塞 。 队列不空–》不阻塞
2)如果队列为满,尝试入队列–》阻塞。 队列不满–》不阻塞

1)blpop/brpop可以设置阻塞时间,超时也会停止阻塞。

2)命令也可以同时监听多个key,从左向右遍历,一旦有一个key对应的列表中可以弹出元素,命令立刻返回。

3)多个客户端同时执行pop,则最先执行的客户端得到弹出的元素
在这里插入图片描述

对一个空队列操作:
在这里插入图片描述
先阻塞在那,开另一个客户端对指定队列插入元素,结束阻塞并弹出。

对多个key进行操作:

在这里插入图片描述
brpop与blpop同理

2.3 查询命令

2.3.1 lrange

lrange key start end

  • 功能:获取列表中[start, end]区间的所有元素(闭区间,支持负数下标:-1表示最后一个元素,-2表示倒数第二个,以此类推)。
  • 时间复杂度:O (N)(N 为区间内元素的个数,而非列表总长度)。
  • 返回值:区间内的元素列表(空列表或 Key 不存在时返回空列表)。
  • 关键特性:容错性强,若start或end超出列表范围,会自动调整为有效区间(如列表长度为 5,end=10会自动改为end=4)。

在这里插入图片描述

2.3.2 lindex

lindex key index

  • 功能:获取列表中指定下标的单个元素(下标从 0 开始,负数表示倒数)。
  • 时间复杂度:O (N)(N 为 “从列表头部 / 尾部到目标下标的距离”,列表越长,中间元素查询越慢)。
  • 返回值:指定下标的元素(下标非法或 Key 不存在时返回nil)

在这里插入图片描述

2.3.3 llen

llen key

  • 功能:获取列表的元素总长度。
  • 时间复杂度:O (1)
  • 返回值:列表的元素个数(Key 不存在时返回 0)。

在这里插入图片描述

2.4 修改与删除指定元素命令

2.4.1 linsert

linsert key BEFORE|AFTER pivot element

  • 功能:在列表中 “第一个匹配pivot的元素” 的前面(BEFORE) 或后面(AFTER) 插入element;若列表中无pivot元素,不执行任何操作。
  • 时间复杂度:O (N)
  • 返回值:插入元素后列表的总长度(无pivot时返回-1,Key 不存在时返回0)。

在这里插入图片描述
在这里插入图片描述

2.4.2 lset

lset key index element

  • 功能:将列表中指定下标的元素修改为element;若 Key 不存在或下标非法(超出列表长度),直接报错。
  • 时间复杂度:O (N)
  • 返回值:修改成功返回OK,失败返回错误信息。
  • 注意:与lindex的区别 ——lindex下标非法返回nil,lset下标非法会报错。

在这里插入图片描述

2.4.3 lrem

lrem key count element

  • 功能:删除列表中 “值等于element” 的元素,删除数量由count决定:
    • count > 0:从列表头部到尾部删除count个匹配元素;
    • count < 0:从列表尾部到头部删除count的绝对值个匹配元素;
    • count = 0:删除列表中所有值等于element的元素。
  • 时间复杂度:O (N+M)(N 为列表总长度,M 为删除的元素个数,需遍历列表匹配元素)。
  • 返回值:实际删除的元素总个数(Key 不存在或无匹配元素时返回 0)。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4.4 ltrim

ltrim key start end

  • 功能:保留列表中[start, end]区间的元素,删除区间外的所有元素(闭区间,支持负数下标);若 Key 不存在,不执行任何操作。
  • 时间复杂度:O (N)(N 为删除的元素个数,需遍历并移除区间外元素)。
  • 返回值:操作成功返回OK。

在这里插入图片描述

3.List 类型的底层编码

Redis 3.2 版本前,List 的底层编码是 “ziplist(压缩列表)” 和 “linkedlist(双向链表)” 的切换;3.2 版本后,统一为quicklist(快速列表) —— 这是 “双向链表 + 压缩列表” 的混合结构,兼顾了内存效率与操作性能。

在这里插入图片描述
每个压缩列表控制大小,不要太大

在这里插入图片描述
在这里插入图片描述

4.应用场景

4.1 有序数据存储

适用于需要 “按插入顺序存储多个元素” 且 “频繁访问两端数据” 的场景,如用户浏览历史、商品评价列表、系统操作日志等 —— 这类场景的核心诉求是 “保留顺序 + 快速增删 + 按需截取”。

在这里插入图片描述
redis如何组织要通过实际情况决定

4.2 分布式消息队列

List 的lpush(生产者写入)+brpop(消费者阻塞读取)组合,是实现 “轻量级分布式消息队列” 的经典方案,适用于低延迟、低并发的消息传递场景(如订单状态通知、用户注册成功后发送欢迎短信)。

在这里插入图片描述
谁先执行brpop命令,先拿到元素

这样的设定,就能构成一个 “轮询” 式的效果。
按执行命令的顺序依次获取元素,如果一个消费者想多次消费,再次执行的命令排在前面已有的命令之后,达到轮流获取(轮询)的效果。

分频道的消息队列

在这里插入图片描述
当业务场景中存在多种消息类型(如电商平台的 “订单消息”“库存消息”“物流消息”),若所有消息都放入一个 List,会导致 “消息混杂、处理效率低、某类消息异常影响全局”。此时可通过 “分频道” 优化 —— 为每种消息类型创建独立的 List,实现 “消息隔离、解耦业务”。

比如在抖音上刷视频:
通过一个频道,来传输视频数据
另一个频道,传输弹幕
另一个频道,传输 评论 数据

搞成多个频道,就可以在某种数据发送问题的时候,不会对其他数据造成影响(解耦合)

4.3 分页

当 List 中存储的元素数量过大(如微博用户发表的 1 万条文章),无法一次性在前端展示,需实现 “分页加载”—— 用户点击 “下一页” 时,加载对应页的内容。List 的lrange命令可直接支持分页,但需注意优化 “中间页查询效率”。

4.3.1 基础实现:基于lrange的分页

假设每页展示 10 条文章,分页逻辑如下:

  • 第 1 页(首页):调用lrange user:articles:10086 0 9—— 获取列表第 0 到 9 个元素(最新的 10
    条文章);
  • 第 2 页:调用lrange user:articles:10086 10 19—— 获取第 10 到 19 个元素;
  • 第 N 页:调用lrange user:articles:10086 (N-1)10 N10-1—— 按公式计算区间。

同时,调用llen user:articles:10086获取总元素个数,计算总页数。

4.3.2 核心优化:解决 “中间页查询低效” 问题

List 的底层是链表结构,lrange查询中间页(如第 500 页)时,需从列表头部遍历到第 4990 个元素,时间复杂度为 O (N),随着页数增加,查询速度会明显变慢。针对这一问题,可采用 “列表拆分” 优化 —— 将大列表拆分为多个小列表,降低单列表长度。

以 “存储 1 万条文章” 为例,优化方案如下:

  1. 拆分小列表:按 “每页 10 条” 的粒度,将 1 万条文章拆分为 1000 个小列表,命名规则为user:articles:10086:page:1(第 1 页,存储前 10条)、user:articles:10086:page:2(第 2 页,存储 11-20条)、 user:articles:10086:page:1000(第 1000 页,存储 9991-10000 条);
  2. 分页查询:用户访问第 500 页时,直接调用lrange user:articles:10086:page:500 0 9—— 无需遍历大列表,直接查询对应小列表,时间复杂度降至 O (1);
  3. 新增文章处理:用户发表新文章时,调用lpush user:articles:10086:page:1 新文章ID—— 插入第 1
    页小列表;若第 1 页元素超过 10 条(如第 1 页已有 10 条,插入后变为 11 条),则将第 1 页的最后 1 条元素移到第 2页的头部(rpop user:articles:10086:page:1 + lpush user:articles:10086:page:2 元素ID),确保每个小列表不超过 10 条。

4.3.3 额外优化:减少网络请求次数

基础分页中,查询 “某页文章详情” 时,需先调用lrange获取该页的文章 ID 列表,再循环调用hgetall 文章ID获取每个文章的标题、内容等详情 —— 若每页 10 条文章,需 1 次lrange+10 次hgetall,共 11 次网络请求,效率较低。
可通过Redis Pipeline(流水线/管道) 优化:将 “1 次lrange+10 次hgetall” 的 11 次请求合并为 1 次请求发送给 Redis,Redis 批量处理后一次性返回结果,大幅减少网络通信次数(从 11 次降至 1 次),提升查询效率。

4.4 业务视角

List 核心特性对应的业务诉求典型场景
两端插入 / 删除高效(O (1))高频增删、需保留顺序(先进先出 / 先进后出)消息队列、浏览历史、栈
支持阻塞读取(brpop/blpop)避免轮询空列表、降低资源浪费消费者监听消息队列
支持区间截取(ltrim/lrange)需保留最新 N 条数据、分页展示操作日志、分页文章
元素可重复允许存储相同内容的多条数据重复消息通知、多次浏览记录

5.小结

Redis List 类型的核心价值在于 “有序性 + 灵活性”—— 它既满足了 “按插入顺序存储” 的基础需求,又通过双端操作、阻塞读取等特性,适配了消息队列、分页等复杂场景,是分布式系统中 “有序数据交互” 的重要工具。

使用 List 类型时,需牢记三个关键建议:

  1. 优先操作两端:尽量用lpush/rpush(插入)、lpop/rpop(删除)等两端操作(O (1)),避免lindex/linsert等中间操作(O (N)),减少性能损耗;
  2. 合理拆分大列表:当列表元素超过 1 万条时,采用 “小列表拆分” 优化,避免lrange查询中间页效率低的问题;
  3. 消息队列需兜底:用 List 实现消息队列时,必须添加 “备份队列” 或 “消息重试” 逻辑,避免消息丢失,同时监控队列长度,防止内存溢出。
http://www.dtcms.com/a/428101.html

相关文章:

  • 服务器做jsp网站教程视频城市介绍网站模板
  • 做网站一定需要虚拟主机吗自建网站定位
  • CompletableFuture原理与实践----商品信息查询接口优化---信息组装
  • 深圳求职网站哪个好网站对接微信接口
  • Cause: java.sql.SQLException: 无效的列类型: 1111
  • IMU传感器价格与高精度组合惯导市场现状分析
  • (28)ASP.NET Core8.0 SOLID原则
  • API 接口开发与实时实时采集构建京东商品数据通道方案
  • 做网销的网站移动网站 模板
  • 某短视频 sig3 逆向纯算分析
  • CMSIS设计的理解
  • 串扰06-近端串扰的大小
  • 哪些网站是做食品网站前台设计方案
  • 达州市网站建设wordpress文章与页面
  • Powershell维护系统管理任务(五)
  • 美团滑块-[behavior] 加密分析
  • 泉州专业建站单位网站建设实施方案
  • 动作捕捉技术与服务 | 推动人形机器人实现规模化高质量数据采集与训练
  • 网站开发软件有哪设计师网络叫法
  • 服务类网站开发中山家居企业网站建设
  • 【Android】Kotlin.flow在主线程collect为什么不阻塞主线程?
  • 数据整合展示中心
  • 阜宁网站制作哪家好我公司想做网站
  • Spring IOC源码篇七 核心方法obtainFreshBeanFactory自定义标签
  • 在哪里找做网站的客户郴州网络营销
  • 产生式规则对人工智能中自然语言处理深层语义分析的影响与启示研究
  • 南宁专业网站开发潍坊市网站制作
  • 网站后台登录密码修改自己网站做问卷调查
  • 在命令提示符页面中用pip命令行安装Python第三方库的详细步骤
  • 杭州开发网站的公司网站默认中文字体