Redis 模式匹配:KEYS vs SCAN 及 Go 实战示例

简介: Redis支持通配符匹配(*、?、[])查找key,但`KEYS`命令会阻塞服务,严禁用于生产;推荐使用非阻塞的`SCAN`命令分批遍历,配合规范命名(如`user:1001:profile`)和合理COUNT值,确保线上稳定。

在使用 Redis 时,我们经常需要按某种命名规则查找一批 key,比如:

  • user:1001:profile
  • user:1002:profile
  • session:abc123
  • session:def456

此时就需要用到 Redis 的模式匹配(Pattern Matching)功能。Redis 提供了两个关键命令:KEYS 和 SCAN。它们都能匹配 key,但使用场景和风险差异巨大。


🔍 1. 通配符匹配规则

Redis 支持以下通配符:

模式 含义 示例匹配(pattern = "user:*")
* 匹配任意数量字符(含 0) user:1, user:100:info, user:
? 匹配单个字符 user:a? → user:a1, user:ab ✅;user:abc ❌
[abc] 匹配括号中任一字符 log:[123] → log:1, log:2 ✅
[a-z] 匹配区间内任一字符 temp:[a-c] → temp:a, temp:c ✅

💡 实际开发建议:统一 key 命名规范,比如 namespace:id:field,让匹配更可靠。


⚠️ 2. KEYS 命令:快但危险!

KEYS user:*
  • ✅ 简单直接:一次性返回所有匹配 key
  • ❌ 阻塞 Redis 单线程!大数据量时可能导致服务卡顿甚至超时
  • 🚫 严禁在生产环境使用(除非你 100% 确认 key 总数极少)

✅ Go 示例(仅限开发/调试)

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

func main() {
   
    rdb := redis.NewClient(&redis.Options{
   
        Addr: "localhost:6379",
    })

    ctx := context.Background()
    keys, err := rdb.Keys(ctx, "user:*").Result()
    if err != nil {
   
        panic(err)
    }

    fmt.Println("Found keys:", keys)
    // Output: [user:1001:profile user:1002:profile]
}

📌 注意:Keys() 是 KEYS 命令的封装,切勿用于线上。


✅ 3. SCAN 命令:安全、分批、推荐!

SCAN 0 MATCH user:* COUNT 10
→ 返回 [cursor, [key1, key2, ...]]
  • ✅ 非阻塞:每次只查一小批,不影响线上服务
  • ✅ 游标迭代:直到 cursor 回到 0 表示结束
  • ✅ 完美适配生产环境大规模 key 遍历

Go 实战:安全遍历所有匹配 key

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

func scanKeys(ctx context.Context, rdb *redis.Client, pattern string, count int64) ([]string, error) {
   
    var keys []string
    var cursor uint64 = 0

    for {
   
        var err error
        var scanned []string
        scanned, cursor, err = rdb.Scan(ctx, cursor, pattern, count).Result()
        if err != nil {
   
            return nil, err
        }

        keys = append(keys, scanned...)

        // cursor == 0 表示迭代结束
        if cursor == 0 {
   
            break
        }
    }

    return keys, nil
}

func main() {
   
    rdb := redis.NewClient(&redis.Options{
   
        Addr: "localhost:6379",
    })
    ctx := context.Background()

    keys, err := scanKeys(ctx, rdb, "user:*", 10) // 每次最多查 10 个
    if err != nil {
   
        panic(err)
    }

    fmt.Println("Scanned keys:", keys)
    // Output: [user:1001:profile user:1002:profile]
}

⚙️ 参数说明:

  • cursor: 初始为 0,后续用上一次返回的 cursor
  • pattern: "user:*", "session:*" 等
  • count: 建议值(非精确),如 10/100。太小效率低,太大影响性能。

✅ 即使 Redis 有百万 key,SCAN 也能零感知完成遍历。


🛠️ 4. 最佳实践总结

项目 建议
✅ 生产环境 只用 SCAN,禁用 KEYS
✅ 命名规范 使用层级命名:{type}:{id}:{field}(如 order:20251203001:status)
✅ 性能调优 COUNT 初始可设 100;若响应慢,调低至 10~50
✅ 防误用 代码审查时 grep "KEYS",或通过 Redis 配置禁用:rename-command KEYS ""

🔚 结语

  • 想快速查几个 key?👉 KEYS(仅本地/测试)
  • 想安全遍历海量 key?👉 SCAN + Go 循环(生产唯一选择)

掌握这个模式,能帮你避免 Redis 线上事故,写出更健壮的缓存层代码!


相关文章
|
人工智能 开发者
文章和 PPT 配图有救了!SVG 绘图专家智能体大揭秘
本文分享如何使用 DeepSeek-V3-0324 和 Claude 3.5 或 3.7 绘制出高质量的图片,可以作为文章配图也可以为 PPT 配图,效率成倍增长。文章还介绍了原型图绘制、图片重绘修改和彩色报纸风的进阶案例。希望本文提供的技巧对大家有帮助,大家也可以修改提示词定制自己喜欢的风格。
1843 13
|
消息中间件 固态存储 Java
RocketMQ 消息发送system busy、broker busy原因分析与解决方案
RocketMQ 消息发送system busy、broker busy原因分析与解决方案
RocketMQ 消息发送system busy、broker busy原因分析与解决方案
|
8月前
|
安全 Go API
Go1.26新提案:errors.AsType —— 更安全、更简洁的错误类型检查方案
Go 1.26 新增 `errors.AsType[E error](err error) (E, bool)`,以泛型替代反射实现错误类型匹配。相比传统 `errors.As`,它无需预声明变量、避免指针误用、杜绝运行时 panic,支持 `if x, ok := AsType[T](err); ok` 短声明,作用域更安全,性能更高,代码更简洁清晰。(239字)
372 6
|
7月前
|
缓存 项目管理 开发工具
UV实战教程,我啥要从Anaconda切换到uv来管理包?
本文对比Anaconda“手动挡”与uv“全自动挡”环境管理:uv以“项目即环境”为核心,支持`uv init`一键初始化、自动下载Python、智能依赖管理(`uv add/sync/run`)及PyCharm无缝对接,大幅提升Python开发效率与协作体验。(239字)
1938 11
UV实战教程,我啥要从Anaconda切换到uv来管理包?
|
6月前
|
人工智能 监控 前端开发
大模型应用:基于安诊儿AntAngelMed模型+FastAPI构建慢病管理AI助手.86
本项目基于安诊儿AntAngelMed医疗大模型(临床一致率达88.9%),结合FastAPI后端与轻量前端,构建7×24小时慢病AI助手。支持糖尿病、高血压等居家咨询,提供专业、可读、结构化建议,并实时统计Token消耗,兼顾实用性与成本可控性。
835 2
|
8月前
|
安全 Java API
Spring Boot 4 黑科技: 编译期消灭空指针异常!
NPE被称为“幽灵bug”因Java类型系统无法区分可空/非空类型,导致运行时崩溃。Spring Boot 4引入JSpecify标准:`@NullMarked`设包级非空默认,`@Nullable`显式标注例外,配合NullAway在编译期拦截空指针,让NPE从线上事故变为本地错误。(239字)
479 2
|
8月前
|
JSON 编解码 Go
Go 新一代网络请求resty!,比net/http好用10倍
resty 是 Go 语言高性能 HTTP 客户端,比 net/http 简洁 10 倍、比 axios 更 Go 风。零依赖、支持链式调用、自动 JSON 编解码、重试/拦截器/Mock/文件上传下载等,Go 1.18+ 可用,一行代码发起请求,大幅提升开发效率与可维护性。(239 字)
874 1
|
8月前
|
缓存 NoSQL 网络协议
Redis Pipeline 实战指南:提升 Go 后端性能的利器
Redis Pipeline 是一种批量命令优化机制,通过一次网络往返执行多条命令,显著降低RTT开销、提升吞吐(实测快50倍)。它非事务,无原子性保证,适用于批量写入、排行榜更新等场景;强一致性需求应选MULTI/EXEC或Lua脚本。(239字)
500 1
|
8月前
|
前端开发 Java API
Python MyBoot入门:像写SpringBoot 一样写python
MyBoot是Python版Spring Boot,主打“约定优于配置”,支持自动装配、依赖注入与类Spring注解(如@RestController/@service)。内置HTTP/2、Swagger、健康检查等,单文件启动,30秒初始化项目,零样板配置,专为快速开发企业级API而生。
459 2