Redis列表(List):实现队列/栈的利器,底层原理与实战

Redis列表(List):实现队列/栈的利器,底层原理与实战

1. Redis列表概述

1.1 什么是Redis列表

Redis列表(List)是一个有序的字符串元素集合,支持在头部和尾部进行高效的插入和删除操作。它可以实现栈(Stack)、**队列(Queue)**等多种数据结构的功能。

1.2 列表的特点

特性描述优势
有序性元素按插入顺序排列保持数据的时间序列
双端操作支持头尾两端插入删除实现多种数据结构
索引访问支持按索引访问元素灵活的数据读取
阻塞操作支持阻塞式弹出实现生产者消费者模式

2. 底层实现原理

2.1 编码方式演进

Redis版本编码方式特点
3.2之前ziplist + linkedlist双编码切换
3.2-6.2quicklist统一实现
7.0+listpack内存优化

2.2 quicklist实现详解

quicklist结构特点

  • 由多个ziplist节点组成的双向链表
  • 每个节点包含一个ziplist
  • 兼顾内存效率和操作性能

2.3 配置参数

# redis.conf 列表相关配置
list-max-ziplist-size -2        # 单个ziplist大小限制(8KB)
list-compress-depth 0           # 压缩深度(0=不压缩)

3. 基本列表操作

3.1 插入操作

# 头部插入
127.0.0.1:6379> LPUSH mylist "a" "b" "c"
(integer) 3# 尾部插入
127.0.0.1:6379> RPUSH mylist "d" "e"
(integer) 5# 指定位置插入
127.0.0.1:6379> LINSERT mylist BEFORE "b" "new"
(integer) 6

3.2 删除操作

# 头部弹出
127.0.0.1:6379> LPOP mylist
"c"# 尾部弹出
127.0.0.1:6379> RPOP mylist
"e"# 按值删除
127.0.0.1:6379> LREM mylist 2 "a"
(integer) 1

3.3 查询操作

# 范围查询
127.0.0.1:6379> LRANGE mylist 0 -1
1) "new"
2) "b"
3) "a"
4) "d"# 索引查询
127.0.0.1:6379> LINDEX mylist 0
"new"# 长度查询
127.0.0.1:6379> LLEN mylist
(integer) 4

4. 阻塞式操作

4.1 阻塞弹出

# 阻塞式左弹出
127.0.0.1:6379> BLPOP list1 list2 10
1) "list1"
2) "element"# 阻塞式右弹出
127.0.0.1:6379> BRPOP myqueue 0# 阻塞式移动
127.0.0.1:6379> BRPOPLPUSH source dest 30

4.2 应用模式

# 栈模式(LIFO)
LPUSH stack "item1"
LPOP stack# 队列模式(FIFO)  
LPUSH queue "task1"
RPOP queue# 双端队列
LPUSH deque "left"
RPUSH deque "right"

5. 实战应用场景

5.1 消息队列系统

@Service
public class RedisMessageQueue {@Autowiredprivate RedisTemplate<String, String> redisTemplate;/*** 发送消息*/public void sendMessage(String queueName, String message) {redisTemplate.opsForList().leftPush(queueName, message);}/*** 接收消息(阻塞)*/public String receiveMessageBlocking(String queueName, long timeout, TimeUnit unit) {return redisTemplate.opsForList().rightPop(queueName, timeout, unit);}/*** 获取队列长度*/public Long getQueueSize(String queueName) {return redisTemplate.opsForList().size(queueName);}
}

5.2 任务队列处理器

@Service
public class TaskQueueProcessor {@Autowiredprivate RedisTemplate<String, String> redisTemplate;private static final String TASK_QUEUE = "task:queue";private static final String PROCESSING_QUEUE = "task:processing";/*** 添加任务*/public void addTask(String task) {redisTemplate.opsForList().leftPush(TASK_QUEUE, task);}/*** 处理任务*/public void processTask() {// 从任务队列移动到处理队列(原子操作)String task = redisTemplate.opsForList().rightPopAndLeftPush(TASK_QUEUE, PROCESSING_QUEUE);if (task != null) {try {// 执行任务executeTask(task);// 任务完成,从处理队列移除redisTemplate.opsForList().lrem(PROCESSING_QUEUE, 1, task);} catch (Exception e) {// 任务失败处理handleTaskFailure(task, e);}}}private void executeTask(String task) {// 具体任务执行逻辑System.out.println("执行任务: " + task);}private void handleTaskFailure(String task, Exception e) {// 将失败任务移动到失败队列redisTemplate.opsForList().lrem(PROCESSING_QUEUE, 1, task);redisTemplate.opsForList().leftPush("task:failed", task);}
}

5.3 最近访问记录

@Service
public class RecentAccessService {@Autowiredprivate RedisTemplate<String, String> redisTemplate;private static final int MAX_RECENT_COUNT = 100;/*** 记录用户访问*/public void recordAccess(String userId, String resource) {String key = "recent:access:" + userId;String accessRecord = resource + ":" + System.currentTimeMillis();// 添加新访问记录redisTemplate.opsForList().leftPush(key, accessRecord);// 保持最多100条记录redisTemplate.opsForList().ltrim(key, 0, MAX_RECENT_COUNT - 1);// 设置过期时间redisTemplate.expire(key, 30, TimeUnit.DAYS);}/*** 获取最近访问记录*/public List<String> getRecentAccess(String userId, int count) {String key = "recent:access:" + userId;return redisTemplate.opsForList().range(key, 0, count - 1);}
}

5.4 实时日志收集

@Service
public class LogCollectorService {@Autowiredprivate RedisTemplate<String, String> redisTemplate;private static final String LOG_QUEUE = "logs:queue";/*** 收集日志*/public void collectLog(String level, String message) {String logEntry = String.format("[%s] %s - %s", level, new Date(), message);redisTemplate.opsForList().leftPush(LOG_QUEUE, logEntry);}/*** 批量获取日志*/public List<String> batchGetLogs(int batchSize) {List<String> logs = new ArrayList<>();for (int i = 0; i < batchSize; i++) {String log = redisTemplate.opsForList().rightPop(LOG_QUEUE);if (log == null) break;logs.add(log);}return logs;}/*** 阻塞式获取日志*/public String getLogBlocking(long timeout, TimeUnit unit) {return redisTemplate.opsForList().rightPop(LOG_QUEUE, timeout, unit);}
}

6. Java编程实践

6.1 完整的List工具类

@Component
public class RedisListUtil {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// ==================== 插入操作 ====================public Long leftPush(String key, Object value) {return redisTemplate.opsForList().leftPush(key, value);}public Long leftPushAll(String key, Object... values) {return redisTemplate.opsForList().leftPushAll(key, values);}public Long rightPush(String key, Object value) {return redisTemplate.opsForList().rightPush(key, value);}// ==================== 弹出操作 ====================public Object leftPop(String key) {return redisTemplate.opsForList().leftPop(key);}public Object rightPop(String key) {return redisTemplate.opsForList().rightPop(key);}public Object leftPopBlocking(String key, long timeout, TimeUnit unit) {return redisTemplate.opsForList().leftPop(key, timeout, unit);}public Object rightPopAndLeftPush(String sourceKey, String destinationKey) {return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey);}// ==================== 查询操作 ====================public List<Object> range(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}public Object index(String key, long index) {return redisTemplate.opsForList().index(key, index);}public Long size(String key) {return redisTemplate.opsForList().size(key);}// ==================== 修改操作 ====================public void set(String key, long index, Object value) {redisTemplate.opsForList().set(key, index, value);}public Long remove(String key, long count, Object value) {return redisTemplate.opsForList().remove(key, count, value);}public void trim(String key, long start, long end) {redisTemplate.opsForList().trim(key, start, end);}
}

7. 性能优化与最佳实践

7.1 性能特点

操作类型时间复杂度性能说明
LPUSH/RPUSHO(1)头尾插入高效
LPOP/RPOPO(1)头尾弹出高效
LINDEXO(N)随机访问慢
LRANGEO(S+N)S为起始偏移量
LREMO(N+M)M为删除的元素数

7.2 最佳实践

7.2.1 优先使用头尾操作
// ✅ 推荐:优先使用头尾操作
redisTemplate.opsForList().leftPush(key, value);    // O(1)
redisTemplate.opsForList().rightPop(key);           // O(1)// ❌ 避免:频繁使用中间位置操作
redisTemplate.opsForList().index(key, 1000);        // O(N)
redisTemplate.opsForList().set(key, 1000, value);   // O(N)
7.2.2 控制列表长度
@Service
public class OptimizedListService {private static final int MAX_LIST_SIZE = 10000;/*** 安全的列表插入*/public void safeListPush(String key, Object value) {Long size = redisTemplate.opsForList().size(key);if (size >= MAX_LIST_SIZE) {redisTemplate.opsForList().rightPop(key);}redisTemplate.opsForList().leftPush(key, value);}/*** 批量插入时的长度控制*/public void batchPushWithLimit(String key, List<Object> values) {redisTemplate.opsForList().leftPushAll(key, values);redisTemplate.opsForList().trim(key, 0, MAX_LIST_SIZE - 1);}
}
7.2.3 使用Pipeline优化
/*** Pipeline批量操作*/
public void batchOperations(String key, List<String> values) {redisTemplate.executePipelined(new RedisCallback<Object>() {@Overridepublic Object doInRedis(RedisConnection connection) {for (String value : values) {connection.lPush(key.getBytes(), value.getBytes());}return null;}});
}

7.3 监控和维护

@Service
public class ListMonitorService {/*** 监控列表状态*/public Map<String, Object> getListStats(String key) {Map<String, Object> stats = new HashMap<>();stats.put("size", redisTemplate.opsForList().size(key));stats.put("exists", redisTemplate.hasKey(key));// 获取内存使用和编码信息String script = "local memory = redis.call('memory', 'usage', KEYS[1]) " +"local encoding = redis.call('object', 'encoding', KEYS[1]) " +"return {memory, encoding}";List<Object> result = (List<Object>) redisTemplate.execute(new DefaultRedisScript<>(script, List.class),Collections.singletonList(key));if (result != null && result.size() >= 2) {stats.put("memory_usage", result.get(0));stats.put("encoding", result.get(1));}return stats;}
}

总结

Redis列表是一个功能强大的有序集合数据结构:

核心知识点

  1. 底层原理:quicklist实现,兼顾内存效率和性能
  2. 基本操作:头尾插入删除、索引访问、范围查询
  3. 阻塞操作:实现生产者消费者模式的关键
  4. 应用场景:消息队列、任务队列、访问记录、日志收集
  5. 性能优化:优先头尾操作,控制列表长度

关键要点

  • 双端高效:头尾操作时间复杂度O(1)
  • 阻塞机制:支持阻塞式操作,实现队列功能
  • 原子性保证:单个操作和移动操作都是原子的
  • 内存优化:quicklist结构平衡内存和性能

实战建议

  1. 合理选择操作:根据场景选择合适的插入删除方式
  2. 控制数据规模:避免单个列表过大影响性能
  3. 监控列表状态:定期检查内存使用和编码类型
  4. 结合业务特点:根据访问模式选择最优的数据结构

通过本文学习,你应该能够熟练使用Redis列表实现各种队列功能。


下一篇预告:《Redis集合(Set):去重与交集/并集操作,这些场景必用》


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96731.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV 图像双三次插值

文章目录 一、简介 二、实现代码 三、实现效果 参考资料 一、简介 在数学中,双三次插值是三次样条插值(一种将三次插值应用于数据集的方法)的扩展,用于在二维规则网格上插值数据点。插值曲面(指核形状,而非图像)比通过双线性插值或最近邻插值获得的相应曲面更平滑。双三…

【Java实战㊲】Spring Security:为Spring Boot应用筑牢安全防线

目录 一、Spring Security 概述 1.1 Spring Security 核心功能 1.2 Spring Security 与 Shiro 对比 二、Spring Boot 整合 Spring Security 基础 2.1 整合依赖导入 2.2 默认安全配置 2.3 自定义用户认证 2.4 自定义登录与注销 三、Spring Security 授权控制 3.1 基于角色的授权…

linux命令—stat

命令简介 stat是Linux中用于查看文件或文件系统的详细状态信息的强大命令。它比ls -l更全面&#xff0c;其输出信息包括但不限于&#xff1a;文件大小、权限、所有者、最后访问/修改/状态变更时间、inode号、所在设备信息等。 用法 stat命令的语法格式如下 stat [选项] 文件…

解决串口数据乱序问题

环境&#xff1a;jetson nano ubuntu 20.04python 3.12终于是找到解决串口乱序的最佳解决办法了&#xff0c;先来看看什么是串口乱序&#xff1a;这就是一个典型的串口乱序&#xff0c;我的发送端发送 的协议为0x55 0x51 ...0x55 0x52 ...0x55 0x53 ...0x55 0x54 ...在这四条协…

Spring的注解

声明Bean的注解 Component Controller Service Repository 后三种为Component的别名&#xff0c;之所以不同是因为可读性的考虑 Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented Component public interface Controller {AliasFor(//别名an…

UVM寄存器模型与通道机制

接续UVM基础入门文章。前言重点讲述UVM常用的接口连接方式。寄存器模型&#xff1a;UVM寄存器模型&#xff08;Register Model&#xff09;是一组高级抽象的类&#xff0c;用于对DUT&#xff08;Design Under Test&#xff09;中具有地址映射的寄存器和存储器进行建模&#xff…

12.NModbus4在C#上的部署与使用 C#例子 WPF例子

一、Modbus TCP/IP是什么Modbus TCP/IP是一种基于TCP/IP协议的工业自动化通信协议。它在Modbus协议的基础上&#xff0c;利用TCP/IP网络进行数据传输&#xff0c;使得工业设备之间的通信更加便捷和高效。常用的Modbus功能码包括0x03&#xff08;读保持寄存器&#xff09;、0x06…

硬件开发2-汇编1(ARMv7-A)- 基本概要

一、汇编基本概要1、ARM数据和指令类型2、ARM字节顺序即可大端存储也可小端存储&#xff0c;默认小端存储&#xff08;不建议修改&#xff09;、kernel&#xff08;内核&#xff09;中的&#xff0c;CPSR&#xff08;当前程序状态寄存器&#xff09;可修改大小端存储3、ARM处理…

Linux中进程和线程常用的API详解

进程与线程基础及 Linux 进程间通信&#xff08;IPC&#xff09;详解 一、程序与进程 1. 程序&#xff08;静态文件&#xff09; 程序是存储在磁盘上的可执行文件&#xff0c;是静态实体&#xff0c;不占用 CPU、内存等运行时资源&#xff0c;仅占用磁盘空间。不同操作系统的可…

VS Code 插件开发教程

VS Code 插件开发教程 概述 Visual Studio Code&#xff08;简称 VS Code&#xff09;是一款由 Microsoft 开发的开源轻量级编辑器&#xff0c;支持跨平台&#xff08;Windows、macOS、Linux&#xff09;。 其最大的优势之一是强大的插件系统&#xff0c;开发者可以通过编写扩…

Docker技术解析

1.Docker安装 1.如果Ubuntu自带的Docker版本太低&#xff0c;我们需要卸载旧版本并安装新的 sudo apt-get remove docker docker-engine docker.io containerd runc2. 备份原有软件源 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak3.选择合适的镜像源 # 或者使用…

TCP套接字的使用

Java中使⽤TCP协议通信,使用ServerSocket来建立链接,使用Socket进行通信.ServerSocketServerSocket是创建TCP服务端Socket的api,主要方法:方法签名说明ServerSocket(int port)创建一个服务端流套接字Socket,并绑定指定端口Socket accpet()开始监听指定端口,有客户端链接后,返回…

linux执行systemctl enable xxxxx 报 Failed to execute operation: Bad message

linux执行systemctl enable redis.service 报 Failed to execute operation: Bad message 如果在执行 systemctl enable 命令时遇到 "Failed to execute operation: Bad message" 错误&#xff0c;可能是由于以下几个原因导致的。你可以按照以下步骤进行排查和解决&a…

终端之外:解锁Linux命令行的魔法与力量

Linux命令行的核心理念 在记忆具体的指令之前&#xff0c;先理解它的哲学&#xff1a; 一切皆文件 &#xff1a;硬件设施&#xff0c;进程&#xff0c;目录…在Linux中几乎所有资源都被抽象为文件&#xff0c;这意味着你可以通过同样的指令&#xff08;如 ench ,cat&#xff…

CSS 动画实战:实现电商中“加入购物车”的抛物线效果

引言 在电商网站中&#xff0c;“加入购物车”动画 是提升用户体验的经典交互之一。一个小小的商品图标从页面飘向购物车&#xff0c;不仅直观地反馈了操作结果&#xff0c;还能增加趣味性与沉浸感。 实现这一效果的方式有很多&#xff0c;比如 JavaScript 计算路径 动画&…

深度学习之损失函数

深度神经网络由多层网络连接而成&#xff0c;网络连接处防止线性直接相关&#xff0c;采用非线性函数进行逐层隔离&#xff0c;真正实现每层参数的独立性&#xff0c;也就是只对本层提取到的特征紧密相关。因为如果是线性函数直接相连就成了一层中间网络了&#xff0c;只不过参…

Oracle OCP认证考试题目详解082系列第32题

考察知识点:Oracle profiles(配置文件) 英语题目 32.Which are two of the account management capabilities that can be configured using Oracle profiles? A.the number of days for which an account may be logged in to one or more sessions before it is locked…

Docker 部署 MongoDB:单节点与副本集的最佳实践

Docker 部署 MongoDB&#xff1a;单节点与复制集的企业级最佳实践引言&#xff1a;容器化有状态服务的范式转变第一部分&#xff1a;基础概念与生产环境考量1.1 核心 Docker 概念深度解析1.2 Volume vs. Bind Mount&#xff1a;生产环境抉择1.3 获取与验证官方镜像官方镜像默认…

公司本地服务器上搭建部署的办公系统web项目网站,怎么让外网访问?有无公网IP下的2种通用方法教程

本地物理服务器计算机搭建部署应用包括网站等&#xff0c;然后在局域网内的访问外&#xff0c;还需要提供外地的连接访问&#xff0c;这是比较常见的跨网通信需求。如在家或在外访问公司内部办公系统网站&#xff0c;这就涉及内网IP和公网IP的转换&#xff0c;或域名的解析使用…

整体设计 之 绪 思维导图引擎 之 引 认知系统 之 引 认知系统 之 序 认知元架构 之6 拼句 之1 (豆包助手 之8)

摘要(AI生成)认知演进 中 交流句子所包含的 信息描述框架 < i , j > ( m , n )本体论基础&#xff08;数学约束&#xff09;&#xff1a; n n元&#xff08;维度&#xff09;n次&#xff08;层次&#xff09;n个&#xff08;方程&#xff09;n场&#xff08;场景&am…