vault backup: 2026-05-25 20:51:57

This commit is contained in:
hhs
2026-05-25 20:51:57 +08:00
parent 383d98a4dc
commit 7e4671fe25
8 changed files with 1673 additions and 43 deletions
+95 -25
View File
@@ -1,5 +1,5 @@
---
tags: [Redis, 缓存, 命令]
tags: [Redis, 缓存, 命令, Stream, PubSub, Lua]
create time: 2026-05-15 18:12
---
@@ -7,27 +7,35 @@ create time: 2026-05-15 18:12
## 概述
按使用频率排序的常用命令,标注时间复杂度、典型场景和避坑点。完整命令参考官方文档。
本文按数据类型分类梳理 Redis 常用命令,标注**时间复杂度**、典型场景和生产避坑点。覆盖 String / Hash / List / Set / ZSet 五大基础类型,以及 Pub/Sub、Stream、Geo、Lua 脚本等进阶能力。每条命令配有 Go(go-redis)代码示例,方便直接复制使用。
### 数据类型选型速查
> [!NOTE] 怎么用这份速查表?
> - 日常开发直接 Ctrl+F 搜命令名
> - 遇到新业务需求先看数据类型选型流程图,再查对应章节
> - 每个章节末尾的 callout 是"老手踩过的坑",建议通读一遍
## 数据类型选型速查
遇到业务需求时,按以下流程选择合适的 Redis 数据结构:
```mermaid
flowchart TD
A["需要存什么?"] --> B{"单值 / 键值对?"}
B -- 是 --> C["String<br/>缓存, 计数器, 分布式锁"]
B -- 否 --> D{"多个字段 / 对象?"}
D -- 是 --> E["Hash<br/>用户信息, 配置, 表单数据"]
D -- 否 --> F{"需要排序 / 排名?"}
F -- 是 --> G["ZSet<br/>排行榜, 延迟队列, 范围查询"]
F -- 否 --> H{"需要去重 / 集合运算?"}
H -- 是 --> I["Set<br/>标签, 共同关注, UV 统计"]
H -- 否 --> J{"需要队列 / 栈?"}
J -- 是 --> K["List<br/>消息队列, 最新列表, 栈"]
J -- 否 --> L["Pub/Sub<br/>广播, 实时通知"]
start["需要存什么?"] --> q1{"单值 / 键值对?"}
q1 -- 是 --> s1["String<br/>缓存, 计数器, 分布式锁"]
q1 -- 否 --> q2{"多个字段 / 对象?"}
q2 -- 是 --> s2["Hash<br/>用户信息, 配置, 表单数据"]
q2 -- 否 --> q3{"需要排序 / 排名?"}
q3 -- 是 --> s3["ZSet<br/>排行榜, 延迟队列, 范围查询"]
q3 -- 否 --> q4{"需要去重 / 集合运算?"}
q4 -- 是 --> s4["Set<br/>标签, 共同关注, UV 统计"]
q4 -- 否 --> q5{"需要队列 / 栈?"}
q5 -- 是 --> s5["List<br/>消息队列, 最新列表, 栈"]
q5 -- 否 --> s6["Pub/Sub 或 Stream<br/>广播通知 / 可靠消息队列"]
```
> [!TIP] Stream 也是数据类型
> Redis 5.0 新增的 Stream 适合**需要持久化和消费确认**的消息场景。选型时如果 Pub/Sub 的 "fire-and-forget" 不满足需求,直接上 Stream(详见下方 Stream 章节)。
## String — 字符串操作
| 命令 | 返回值 | 复杂度 | 说明 |
@@ -302,14 +310,14 @@ redis-cli --pipeline <<< $'SET k1 v1\nSET k2 v2\nSET k3 v3'
sequenceDiagram
participant C as "客户端"
participant S as "Redis 服务端"
C->>S: MULTI(开启事务)
C->>S: "MULTI 开启事务"
S-->>C: OK
C->>S: SET acc:A 900
S-->>C: QUEUED(排队,不立即执行)
C->>S: SET acc:B 1100
C->>S: "SET acc:A 900"
S-->>C: "QUEUED 排队,不立即执行"
C->>S: "SET acc:B 1100"
S-->>C: QUEUED
C->>S: EXEC(提交)
S-->>C: [OK, OK](依次执行,一次性返回结果)
C->>S: "EXEC 提交"
S-->>C: "[OK, OK] 依次执行,一次性返回"
```
> [!QUESTION] "QUEUED" 是什么意思?
@@ -344,9 +352,9 @@ sequenceDiagram
A->>S: WATCH stock:1001
A->>S: MULTI
A->>S: DECR stock:1001
B->>S: SET stock:1001 999(被其他客户端修改)
B->>S: "SET stock:1001 999 被其他客户端修改"
A->>S: EXEC
S-->>A: nil(事务被取消,因为 stock:1001 已变)
S-->>A: "nil 事务被取消,stock:1001 已变"
```
> [!NOTE] WATCH 的使用范式
@@ -402,6 +410,64 @@ fmt.Printf("delivered to %d subscribers\n", receivers)
> - **Pub/Sub**:实时广播,不关心历史,用完即丢(适合通知、缓存失效广播)
> - **Stream**:持久化消息队列,支持消费组、ACK、回溯(适合业务事件、任务队列)
> - 简单规则:**需要"至少一次"保证就用 Stream,否则 Pub/Sub 足够**
> - 两者命令对比详见 [[hhs/Redis/15-Stream]]
## Stream — 消息队列
Redis 5.0 引入的日志型数据结构,弥补了 Pub/Sub 不持久化的缺陷。底层用 Radix Tree + Listpack 实现,支持消费组(Consumer Group)和消息确认(ACK),可胜任轻量级任务队列。
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `XADD key [MAXLEN ~ n] ID field value [field value ...]` | entry ID | O(1) | 追加消息,`*` 自动生成 ID(时间戳-序号) |
| `XLEN key` | length | O(1) | 消息总数 |
| `XRANGE key start end [COUNT n]` | entries | O(N) | 按 ID 范围正序读取(`-`/`+` 表示最小/最大) |
| `XREVRANGE key end start [COUNT n]` | entries | O(N) | 按 ID 范围倒序读取 |
| `XREAD [COUNT n] [BLOCK ms] STREAMS key [key ...] ID [ID ...]` | entries | O(N) | 读取消息,`$` 表示仅新消息,BLOCK 阻塞等待 |
| `XGROUP CREATE key groupname ID [MKSTREAM]` | OK | O(1) | 创建消费者组,`$` 只消费新消息,`0` 从头消费 |
| `XREADGROUP GROUP group consumer [COUNT n] [BLOCK ms] [NOACK] STREAMS key [key ...] ID` | entries | O(N) | 组内消费,`>` 表示未分配的新消息 |
| `XACK key group ID [ID ...]` | acked count | O(N) | 确认消费,释放消息 |
| `XDEL key ID [ID ...]` | deleted count | O(N) | 删除指定消息 |
| `XTRIM key MAXLEN [~] n` | trimmed count | O(N) | 裁剪流长度,`~` 近似裁剪(性能更好) |
| `XPENDING key group [start end count] [consumer]` | pending info | O(N) | 查看未确认(pending)消息 |
| `XCLAIM key group consumer min-idle-time ID [ID ...]` | entries | O(N) | 认领超时未 ACK 的消息(故障转移) |
| `XINFO STREAM key` | stream info | O(1) | 查看流元信息 |
| `XINFO GROUPS key` | group info | O(N) | 查看所有消费者组 |
```go
// 生产者——追加消息
id, _ := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "order:events",
MaxLen: 10000, // 近似裁剪,控制内存
Approx: true,
Values: map[string]interface{}{"orderId": "1001", "status": "paid"},
}).Result()
fmt.Println("entry ID:", id)
// 消费者组——组内竞争消费
msgs, _ := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Group: "order-consumers",
Consumer: "worker-1",
Streams: []string{"order:events", ">"},
Count: 10,
Block: 5 * time.Second,
}).Result()
for _, stream := range msgs {
for _, msg := range stream.Messages {
// 处理消息...
rdb.XAck(ctx, "order:events", "order-consumers", msg.ID) // 确认消费
}
}
```
> [!WARNING] 消息丢失的两个陷阱
> 1. **生产端**:`XADD` 返回后消息已写入内存,但若 Redis 崩溃且未配置 AOF,消息会丢失。对可靠性要求高的场景请开启 `appendfsync everysec`
> 2. **消费端**:`XREADGROUP` 读取后消息进入 Pending List(PEL),必须显式 `XACK` 才算消费完成。忘记 ACK 会导致消息堆积在 PEL 中,需要用 `XPENDING` + `XCLAIM` 清理
> [!TIP] MAXLEN vs MINID
> - `XADD key MAXLEN ~ 10000`:限制流最大约 10000 条(近似裁剪,性能好)
> - `XADD key MINID ~ 1685000000000-0`:限制最小消息 ID(按时间裁剪,7.0+)
> - 两者都建议加 `~` 做近似裁剪,避免精确裁剪带来的 O(N) 阻塞
## Geo — 地理位置
@@ -482,6 +548,10 @@ result, _ := script.Run(ctx, rdb, []string{"stock:sku:1001"}, 1).Int()
## 关联笔记
- [[hhs/Redis/02-核心数据类型]] — 每种类型的底层编码原理
- [[hhs/Redis/05-AOF持久化]] — 持久化策略对性能的影响
- [[hhs/Redis/09-高级特性]] — Pipeline / Lua / 事务详解
- [[02-核心数据类型]] — 每种类型的底层编码原理(ziplist → hashtable 切换机制)
- [[02-核心数据类型/02-2-skiplist]] — ZSet 底层跳表实现,理解 ZRANGE 为什么是 O(log N+M)
- [[04-RDB持久化]] / [[05-AOF持久化]] — 持久化策略对命令性能的影响
- [[08-SortedSet精解]] — ZSet 进阶玩法:排行榜、延迟队列、优先级队列
- [[09-高级特性]] — Pipeline / Lua / 事务深入解析
- [[15-Stream]] — Stream 完整指南:Consumer Group 模式、消息确认、故障转移
- [[16-GEO]] — Geo 底层原理与围栏检测实战