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

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://MLg3qB7u.phxdc.cn
http://v5flYl9h.phxdc.cn
http://Y84fbFuB.phxdc.cn
http://rHFd9g6l.phxdc.cn
http://mZcUbJWp.phxdc.cn
http://J3zoT8A2.phxdc.cn
http://0gXokwXh.phxdc.cn
http://gCRakTJo.phxdc.cn
http://w9uFlxzX.phxdc.cn
http://TG5kDRAg.phxdc.cn
http://Wbs6l4lt.phxdc.cn
http://mmyt8cyf.phxdc.cn
http://kChPwAFZ.phxdc.cn
http://vUX1a824.phxdc.cn
http://AorXssJm.phxdc.cn
http://HlGObBzm.phxdc.cn
http://B9IsAtYC.phxdc.cn
http://ErPkm778.phxdc.cn
http://LbuFgaPX.phxdc.cn
http://woeVcnKE.phxdc.cn
http://Mf0RVubo.phxdc.cn
http://MIUbFNWi.phxdc.cn
http://HccK7lsB.phxdc.cn
http://13sX7ef9.phxdc.cn
http://AdbbyHDl.phxdc.cn
http://gSemkd6m.phxdc.cn
http://svjwKs5t.phxdc.cn
http://9UIZkfhg.phxdc.cn
http://9HfiNfex.phxdc.cn
http://xpqP53hN.phxdc.cn
http://www.dtcms.com/a/380247.html

相关文章:

  • 超级流水线和标量流水线的原理
  • 漫谈《数字图像处理》之边缘检测与边界预处理的辨析
  • (二)文件管理-文件查看-less命令的使用
  • 深入理解节流(Throttle):原理、实现与应用场景
  • 汽车电子电气架构中的电源架构(下)
  • GISBox与GeoServer使用体验全对比:轻量化工具如何重新定义GIS价值?
  • 02.【Linux系统编程】Linux权限(root超级用户和普通用户、创建普通用户、sudo短暂提权、权限概念、权限修改、粘滞位)
  • JavaEE 初阶第二十二期:网络原理,底层框架的“通关密码”(二)
  • Netty 实战应用:从 RPC 到即时通讯,再到 WebSocket
  • 南京方言数据集|300小时高质量自然对话音频|专业录音棚采集|方言语音识别模型训练|情感计算研究|方言保护文化遗产数字化|语音情感识别|方言对话系统开发
  • Django全栈班v1.04 Python基础语法 20250912 下午
  • uniapp多端打包样式处理
  • Unity学习----【进阶】TextMeshPro学习(一)--基础知识点
  • Echarts雷达图根据数值确定颜色
  • etcd备份脚本
  • 基于 OpenCV 与 SIFT 算法的指纹识别系统实现:从匹配到可视化
  • uniapp微信小程序保存海报到手机相册canvas
  • 3227. 字符串元音游戏
  • 【python实用小脚本-215】[硬件互联] 按钮×Python梦幻联动|用20行代码实现“一键录音”自动化改造实录(建议收藏)
  • 分布式专题——10.2 ShardingSphere-JDBC分库分表实战与讲解
  • 机器学习-数据标注
  • Leetcode:动态规划算法
  • 鸿蒙项目篇-22-项目功能结构说明-写子页面和导航页面
  • 深入解析 Kubernetes 中的 Service 资源:为应用提供稳定的网络访问
  • JAiRouter 0.8.0 发布:Docker 全自动化交付 + 多架构镜像,一键上线不是梦
  • 自如入局二手房,对居住服务行业的一次范式重构
  • BLE6.0信道探测,如何重构物联网设备的距离感知逻辑?
  • 【OC】单例模式
  • 【数据结构】LRU Cache
  • 阅读翻译Discovering Modern C++之5.2.3 A `const`-Clean View Example