vault backup: 2026-05-25 20:51:57
This commit is contained in:
+57
-6
@@ -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 心跳)
|
||||
|
||||
Reference in New Issue
Block a user