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
英文地址,請注明出處:http://en.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…