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.mzph.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;强制重命名…