Redis SCAN 命令的詳細介紹

Redis SCAN 命令的詳細介紹

以下是 Redis SCAN? 命令的詳細介紹,結合其核心特性、使用場景及底層原理進行綜合說明:

工作原理圖 :


Editor _ Mermaid Chart-2025-04-21-022556?


一、核心特性

  1. 非阻塞式迭代

    • 通過游標(Cursor) 分批次遍歷鍵,避免一次性全量掃描阻塞主線程。
    • 每次迭代僅返回少量數據(默認約 10 個鍵),分散服務器壓力。
  2. 弱一致性保證

    • 迭代過程中若鍵被修改(新增/刪除),可能導致重復或遺漏。
    • 采用快照機制,但無法保證強一致性,需業務層處理重復數據。
  3. 支持模式匹配與類型過濾

    • ?MATCH?? 參數支持通配符(如 user:*?)過濾鍵名。
    • ?TYPE? 參數(Redis 6.0+)可指定鍵類型(如 hash??、string??)。

二、命令語法與參數

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
  • **cursor?**
    初始值為 0?,后續使用前次返回的新游標。當游標返回 0? 時,迭代結束。
  • **COUNT?**
    建議單次返回的鍵數量(默認 10),但實際結果可能多于或少于該值。
    (例:??COUNT 1000?? 提示 Redis 嘗試每批返回約 1000 個鍵)

三、底層原理

  1. 高位進位加法遍歷

    • 通過二進制高位進位順序遍歷字典槽(Slot),避免擴容/縮容導致的數據遺漏或重復。
    • 例如:從 0000? → 1000? → 0100? → 1100?,確保新舊哈希表遍歷順序連續。
  2. 字典擴容與漸進式 Rehash

    • 擴容時新舊哈希表共存,SCAN? 會同時遍歷兩個表,保證數據完整性。
    • 縮容可能導致部分鍵被重復掃描,需客戶端去重。

四、使用場景

  1. 生產環境大數據量遍歷

    • 替代 KEYS? 命令,避免因全量掃描導致服務阻塞
    • 示例:遍歷百萬級用戶會話鍵(session:*?)進行清理。
  2. 數據結構專用迭代

    • ?SSCAN?(集合)、HSCAN?(哈希)、ZSCAN?(有序集合)支持按類型迭代元素。
  3. 模糊查詢與分頁

    • 結合 MATCH? 實現模糊匹配,利用 ?COUNT?? 近似分頁控制返回量。

五、注意事項

  1. 重復鍵處理

    • 迭代期間鍵空間變動可能導致重復結果,需客戶端去重。
  2. COUNT 參數優化

    • 根據數據規模調整 COUNT? 值(如 1000~10000),平衡網絡往返次數與單次負載。
  3. 弱一致性的影響

    • 不適用于需精確統計的場景(如實時計數),建議改用其他方案(如維護索引集合)。

使用案例:

從redis中取出數據同步到后臺的其他持久化數據庫 demo 這種分批掃描的方法可以避免一次返回大量 key 而導致 Redis 阻塞,同時可以根據需要對每批數據進行處理

package com.example.scan;/*** 描述: 從 Redis 批量獲取暫存數據并持久化到數據庫。通過SCAN分批拉取數據,確保系統穩定性* 1. 循環獲取指定開頭的key* 2. 判斷key 的數據類型* 3. 對不同的數據類型做相應的處理* 4. 這里模擬如果是string 同步到數據庫 其他只是簡單的打印 后續可以根據業務場景的不通 做不同的處理* @author ZHOUXIAOYUE* @date 2025/4/21 10:20*/import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;import java.util.List;
import java.util.Map;
import java.util.Set;public class RedisDataMigration {public static void main(String[] args) {// 初始化 Jedis 客戶端Jedis jedis = new Jedis("localhost", 6379);// SCAN 命令參數設置// count 參數表示每次掃描大概處理多少條數據,這里設置為 100ScanParams scanParams = new ScanParams().match("user:*").count(100);// 如果需要,可以通過 match 設置鍵模式// scanParams.match("temp:*");String cursor = "0";do {// 執行 SCAN 命令ScanResult<String> scanResult = jedis.scan(cursor, scanParams);List<String> keys = scanResult.getResult();cursor = scanResult.getCursor();// 模擬持久化到數據庫的操作keys.forEach(key -> {// 獲取 key 的數據類型String type = jedis.type(key);System.out.println("Processing key: " + key + ",類型為:" + type);switch (type) {case "string":// 如果是字符串類型,直接調用 get 方法String strValue = jedis.get(key);System.out.println("String value: " + strValue);persistDataToDB(key, strValue);break;case "list":// 如果是列表類型,通過 lrange 獲取所有列表元素List<String> listValue = jedis.lrange(key, 0, -1);System.out.println("List value: " + listValue);break;case "set":// 如果是集合類型,通過 smembers 獲取所有成員Set<String> setValue = jedis.smembers(key);System.out.println("Set value: " + setValue);break;case "zset":// 如果是有序集合類型,通過 zrange 獲取所有元素(默認按分數從小到大排序)Set<String> zsetValue = jedis.zrange(key, 0, -1);System.out.println("ZSet value: " + zsetValue);break;case "hash":// 如果是 Hash 類型,通過 hgetAll 獲取所有鍵值對Map<String, String> hashValue = jedis.hgetAll(key);System.out.println("Hash value: " + hashValue);break;default:// 對于未知類型或其他類型的值,可以在這里處理System.out.println("Unknown type for key: " + key);break;}});// 可以適當休眠,避免對 Redis 服務器產生太大壓力try {Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("Interrupted: " + e.getMessage());}} while (!"0".equals(cursor)); // cursor 為 "0" 時表示遍歷結束jedis.close();System.out.println("數據遷移完成。");}/*** 模擬持久化數據到數據庫** @param key   Redis 的鍵* @param value Redis 的值*/private static void persistDataToDB(String key, String value) {// 此處僅作模擬,可替換為真實的數據庫持久化操作System.out.println("持久化數據 - key: " + key + ", value: " + value);// 例如:// myDatabase.save(new DataEntity(key, value));}
}


總結

場景推薦方案避免方案
生產環境遍歷海量鍵?SCAN?+ 合理COUNT?值?KEYS?命令
精確統計或強一致性需求維護索引集合/Lua 腳本依賴SCAN?結果
分頁查詢?SCAN?+MATCH?+COUNT?單次全量加載

最佳實踐

  • 優先使用 SCAN? 替代 KEYS?,并在客戶端實現去重邏輯。
  • 結合 TYPE? 參數(Redis 6.0+)減少無效遍歷。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78006.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78006.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78006.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot3集成MyBatis-Plus(解決Boot2升級Boot3)

總結&#xff1a;目前升級僅發現依賴有變更&#xff0c;其他目前未發現&#xff0c;如有發現&#xff0c;后續會繼續更新 由于項目架構提升&#xff0c;以前開發的很多公共的組件&#xff0c;以及配置都需要升級&#xff0c;因此記錄需要更改的配置&#xff08;記錄時間&#…

基于mybatis與PageHelper插件實現條件分頁查詢(3.19)

實現商品分頁例子 需要先引入mybatis與pagehelper插件&#xff0c;在pom.xml里 <!-- Mybatis --> <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3&l…

Spring Bean 全方位指南:從作用域、生命周期到自動配置詳解

目錄 1. Bean 的作用域 1.1 singleton 1.2 prototype 1.3 request 1.4 session 1.5 application 1.5.1 servletContext 和 applicationContext 區別 2. Bean 的生命周期 2.1 詳解初始化 2.1.1 Aware 接口回調 2.1.2 執行初始化方法 2.2 代碼示例 2.3 源碼 [面試題…

C++ (非類型參數)

模板除了定義類型參數之外&#xff0c;也可以在模板內定義非類型參數 非類型參數不是類型&#xff0c;而是值&#xff0c;比如&#xff1a;指針&#xff0c;整數&#xff0c;引用 非類型參數的用法&#xff1a; 1.整數常量&#xff1a;非類型參數最常見的形式是整數常量&…

短視頻+直播商城系統源碼全解析:音視頻流、商品組件邏輯剖析

時下&#xff0c;無論是依托私域流量運營的品牌方&#xff0c;還是追求用戶粘性與轉化率的內容創作者&#xff0c;搭建一套完整的短視頻直播商城系統源碼&#xff0c;已成為提升用戶體驗、增加商業變現能力的關鍵。本文將圍繞三大核心模塊——音視頻流技術架構、商品組件設計、…

5.QT-常用控件-QWidget|enabled|geometry|window frame(C++)

控件概述 實現圖形化界面的程序. Qt中已經給我們提供了很多的“控件" 就需要學習和了解這些控件&#xff0c;學會如何使用這些控件 編程講究的是“站在巨人的肩膀上”&#xff0c;而不是“從頭發明輪子" 一個圖形化界面上的內容&#xff0c;不需要咱們全都從零去實…

2025-04-22| Docker: --privileged參數詳解

在 Docker 中&#xff0c;--privileged 是一個運行容器時的標志&#xff0c;它賦予容器特權模式&#xff0c;大幅提升容器對宿主機資源的訪問權限。以下是 --privileged 的作用和相關細節&#xff1a; 作用 完全訪問宿主機的設備&#xff1a; 容器可以訪問宿主機的所有設備&am…

高性能服務器配置經驗指南1——剛配置好服務器應該做哪些事

文章目錄 安裝ubuntu安裝必要軟件設置用戶遠程連接安全問題ClamAV安裝教程步驟 1&#xff1a;更新系統軟件源步驟 2&#xff1a;升級系統&#xff08;可選但推薦&#xff09;步驟 3&#xff1a;安裝 ClamAV步驟 4&#xff1a;更新病毒庫步驟 5&#xff1a;驗證安裝ClamAV 常用命…

直流絕緣監測解決方案:保障工業與新能源系統的安全運行

一、引言 隨著工業自動化和新能源技術的快速發展&#xff0c;直流供電系統在光伏發電、儲能電站、電動汽車充電樁等領域的應用日益廣泛。然而&#xff0c;直流系統的正負極不接地&#xff08;IT系統&#xff09;特性&#xff0c;使得絕緣故障可能導致漏電、短路甚至設備損毀等…

VSCode 用于JAVA開發的環境配置,JDK為1.8版本時的配置

插件安裝 JAVA開發在VSCode中&#xff0c;需要安裝JAVA的必要開發。當前安裝只需要安裝 “Language Support for Java(TM) by Red Hat”插件即可 安裝此插件后&#xff0c;會自動安裝包含如下插件&#xff0c;不再需要單獨安裝 Project Manager for Java Test Runner for J…

C++入門語法

C入門 首先第一點&#xff0c;C中可以混用C語言中的語法。但是C語言是不兼容C的。C主要是為了改進C語言而創建的一門語言&#xff0c;就是有人用C語言用不爽了&#xff0c;改出來個C。 命名空間 c語言中會有如下這樣的問題&#xff1a; 那么C為了解決這個問題就整出了一個命名…

輸入框僅支持英文、特殊符號、全角自動轉半角 vue3

需求&#xff1a;封裝一個輸入框組件 1.只能輸入英文。 2.輸入的小寫英文自動轉大寫。 3.輸入的全角特殊符號自動轉半角特殊字符 效果圖 代碼 <script setup> import { defineEmits, defineModel, defineProps } from "vue"; import { debounce } from "…

Uniapp:創建項目

目錄 一、前提準備二、創建項目三、項目結構四、運行測試 一、前提準備 首先要創建uniapp項目&#xff0c;需要先下載HBuilderX&#xff0c;HBuilderX是一款開箱即用的工具&#xff0c;下載完畢之后&#xff0c;解壓到指定的目錄即可使用&#xff0c;需要注意的是最好路徑里面…

ESM 內功心法:化解 require 中的奪命一擊!

前言 傳聞在JavaScript與TypeScript武林中,曾有兩大絕世心法:CommonJS與ESM。兩派高手比肩而立,各自稱霸一方,江湖一度風平浪靜。 豈料,時局突變。ESM逐步修成陽春白雪之姿,登堂入室,成為主流正統。CommonJS則漸入下風,功力不濟,逐漸退出主舞臺。 話說某日,一位前…

【STL】unordered_set

在 C C C 11 11 11 中&#xff0c; S T L STL STL 標準庫引入了一個新的標準關聯式容器&#xff1a; u n o r d e r e d _ s e t unordered\_set unordered_set&#xff08;無序集合&#xff09;。功能和 s e t set set 類似&#xff0c;都用于存儲唯一元素。但是其底層數據結…

go語言八股文

1.go語言的接口是怎么實現 接口&#xff08;interface&#xff09;是一種類型&#xff0c;它定義了一組方法的集合。任何類型只要實現了接口中定義的所有方法&#xff0c;就被認為實現了該接口。 代碼的實現 package mainimport "fmt"// 定義接口 type Shape inte…

kafka auto.offset.reset詳解

在 Kafka 中&#xff0c;auto.offset.reset latest 的含義及行為如下&#xff1a; 1. ??核心定義?? 當消費者組??首次啟動??或??無法找到有效的 offset??&#xff08;例如 offset 過期、被刪除或從未提交&#xff09;時&#xff0c;消費者會從分區的??最新位置…

深度學習-損失函數

目錄 1. 線性回歸損失函數 1.1 MAE損失 1.2 MSE損失 2. CrossEntropyLoss 2.1 信息量 2.2 信息熵 2.3 KL散度 2.4 交叉熵 3. BCELoss 4. 總結 1. 線性回歸損失函數 1.1 MAE損失 MAE&#xff08;Mean Absolute Error&#xff0c;平均絕對誤差&#xff09;通常也被稱…

第六篇:linux之解壓縮、軟件管理

第六篇&#xff1a;linux之解壓縮、軟件管理 文章目錄 第六篇&#xff1a;linux之解壓縮、軟件管理一、解壓和壓縮1、window壓縮包與linux壓縮包能否互通&#xff1f;2、linux下壓縮包的類型3、打包與壓縮 二、軟件管理1、rpm1、什么是rpm&#xff1f;2、rpm包名組成部分3、如何…

Redis 鍵管理

Redis 鍵管理 以下從鍵重命名、隨機返回鍵、鍵過期機制和鍵遷移四個維度展開詳細說明&#xff0c;結合 Redis 核心命令與底層邏輯進行深入分析&#xff1a; 一、鍵重命名 1. ?RENAME?? 與 ?RENAMENX?? **RENAME key newkey?**&#xff1a; 功能&#xff1a;強制重命名…