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
+57 -6
View File
@@ -59,6 +59,24 @@ EXEC
# → [OK, 124] — 两个都成功了
```
```mermaid
sequenceDiagram
participant C as "Client"
participant S as "Redis Server"
C->>S: MULTI
S-->>C: OK
C->>S: SET k v
S-->>C: QUEUED
C->>S: INCR counter
S-->>C: QUEUED
C->>S: EXEC
Note over S: 依次执行所有排队命令
S-->>C: [OK, 1]
```
> [!QUESTION] 既然 MULTI 能批量执行,为什么还需要 Pipeline?
> 关键区别在于**排队阶段是否立即返回结果**。MULTI 的 QUEUED 只是"记下来",命令要等 EXEC 才真正执行——这意味着你**无法根据前一条的结果决定后续命令**。而 Lua 脚本能做"读-判断-写",Pipeline 则纯粹为减少 RTT。三者各有分工,切勿混淆。
> [!WARNING] Redis 事务 ≠ 数据库事务
> - 没有 ROLLBACK / ACID 保证
> - 不能捕获异常后回滚
@@ -179,18 +197,17 @@ EVALSHA <sha1> numkeys args... # 只传 SHA1,省带宽
### Lua 沙箱限制
```lua
-- 不可用:非确定性函数(传统 Redis)
math.random() -- ❌ 无法预测结果
os.date() -- ❌ 依赖系统时间
time.time() -- ❌ Lua 标准库不存在
-- ❌ 不可用:非确定性函数(传统 Redis < 7.2)
math.random() -- 无法预测结果
os.date() -- 依赖系统时间
-- ✅ 推荐做法:在客户端生成,通过 ARGV 传入
-- ✅ 推荐做法:在客户端生成随机值,通过 ARGV 传入
-- local token = client.generateUUID()
-- redis.call('set', KEYS[1], ARGV[1]) -- 带 token 写入
```
> [!NOTE] Redis 7.2+ 更新
> Redis 7.2 起开放了部分确定性数学函数:`math.random`(需自行 set seed)、`math.max`、`math.min`、`math.log`。但不建议在状态机类脚本中使用随机性。
```
> [!QUESTION] 为什么 Lua 脚本不能有随机函数?
> Lua 脚本在主线程中同步执行,如果引入随机性或时间依赖,会导致两个严重问题:
@@ -410,6 +427,40 @@ for msg := range ch {
> - **从节点不会推送**:默认只在写入节点生效,哨兵/集群切换后需重新订阅
> - **建议**:只订阅你需要的事件类型(如 `KElx`),而非 `KExa` 通配一切
## 六、选型指南——如何选择?
面对一个需求,到底该用事务、Lua、Pipeline 还是 Stream?以下是决策流程:
```mermaid
flowchart TD
A["需求场景"] --> B{"批量命令?"}
B -->|"否"| C["单条命令即可"]
B -->|"是"| D{"需要原子性?"}
D -->|"否"| E["Pipeline"]
D -->|"是"| F{"读-判断-写?"}
F -->|"是"| G["Lua 脚本"]
F -->|"否"| H{"支持 Cluster?"}
H -->|"是"| G
H -->|"否"| I["MULTI / EXEC"]
A --> J{"消息传递?"}
J -->|"可靠投递/任务队列"| K["Stream"]
J -->|"实时广播/通知"| L["Pub/Sub"]
```
| 需求 | 推荐方案 | 理由 |
|------|---------|------|
| 批量写入、减少 RTT | Pipeline | 无原子性要求,纯性能优化 |
| 读-判断-写原子操作 | Lua 脚本 | 逻辑原子性,一气呵成 |
| 简单批量 + 单机 | MULTI / EXEC | 轻量,无需写 Lua |
| 任务队列、事件溯源 | Stream | 持久化 + Consumer Group |
| 实时通知、WebSocket 广播 | Pub/Sub | 无状态、低延迟 |
> [!TIP] 一句话总结
> - **Pipeline**:省网络,不保证顺序
> - **MULTI**:保证顺序,不保证逻辑原子
> - **Lua**:真正的原子性,但阻塞主线程(脚本要短小精悍)
> - **Stream**:需要消息可靠投递时的首选
## 关联笔记
- [[hhs/Redis/06-主从与哨兵]] — Sentinel 故障检测(也是基于 PING/PONG 心跳)