vault backup: 2026-05-25 23:07:45

This commit is contained in:
hhs
2026-05-25 23:07:45 +08:00
parent 9000c90abe
commit 268ee58de6
49 changed files with 282 additions and 54 deletions
+15 -7
View File
@@ -75,7 +75,7 @@ rdb.Set(ctx, "foo", "bar", 0) // 自动路由到对应节点
### Gossip 协议运作方式
每个节点每秒向其他节点发送 PING/PONG,维持集群状态的一致性:
每个节点每秒向其他节点发送 PING/PONG,维持集群状态的一致性。选择的节点数量动态调整——集群越小越接近全发,集群越大越倾向于随机子集:
```mermaid
sequenceDiagram
@@ -87,7 +87,7 @@ sequenceDiagram
B->>A: PONG (含自身 + 选中节点的状态)
end
Note over A: Gossip 收敛原理:<br/>每次随机选 3 个节点交换信息,<br/>N 个节点 ~ log₃(N) 轮即可全同步
Note over A: Gossip 收敛原理:<br/>集群越大 fanout 越大,约 O(sqrt(N)),<br/>O(log(N)) 轮即可全同步
```
**Gossip 传播的三类信息:**
@@ -96,7 +96,7 @@ sequenceDiagram
3. **FAIL** — 某节点不可达,广播给其他节点
> [!QUESTION] 思考
> 为什么 Gossip 不直接发给所有节点,而是随机选 3 个?当集群扩展到 1000 台节点时,这样做的好处是什么?
> Gossip 节点选择策略会随集群规模动态调整——小集群(<100 节点)向所有节点发 PING,大集群才随机选择子集。为什么不直接广播给所有节点?这样做的带宽开销是怎样的?
### PING/PONG 报文详解
@@ -120,9 +120,9 @@ CLUSTER SETSLOT <slot_id> MIGRATING <target_node_id>
# 在目标节点执行(确认阶段)
CLUSTER SETSLOT <slot_id> IMPORTING <source_node_id>
# 逐 key 迁移(客户端负责搬 data)
for key in $(redis-cli -h source-cluster-scan $slot --count 100); do
redis-cli -h source MIGRATE target "" $key 0 5000
# 逐 key 迁移(GETKEYSINSLOT 返回指定 slot 中的 key,每次最多 100 个)
for key in $(redis-cli -h $SRC -p $SRC_PORT CLUSTER GETKEYSINSLOT $slot 100); do
redis-cli -h $SRC -p $SRC_PORT MIGRATE $DST $DST_PORT $key 0 5000
done
# 完成迁移
@@ -202,7 +202,8 @@ val, _ := rdb.Get(ctx, "key").Result()
|------|------|---------|
| 不支持多数据库 | 固定只有 db 0 | 应用层模拟 db(key 前缀) |
| 命令子集受限 | `KEYS`, `MIGRATE`, `SORT` 等不可用 | 用 `SCAN` 替代 `KEYS` |
| Lua 脚本有限 | 不支持非确定性的函数(time/random) | 使用 `EVALSHA` 减少网络传输 |
| 跨节点多 key 命令受限 | `DEL`, `MGET`, `MSET`, `RENAME` 等多 key 操作要求 key 同 slot | 用 hash tag 或应用层拆分为多次单 key 调用 |
| Lua 脚本有限 | 所有 key **必须映射到同一 slot**;不支持非确定性函数(time/random) | 同 Lua 内 key 用同一 hash tag;用 `EVALSHA` 减少网络传输 |
| Pipeline 受限 | 同一 pipeline 中所有 key 必须在同一节点 | 用 hash tag `{user:100}:x` 对齐 |
| MULTI/EXEC 受限 | 同上,跨 key 事务不支持 | 用 Lua 脚本实现原子操作 |
@@ -376,6 +377,13 @@ let val = await cluster.get("key")
| `maxmemory-policy` | `allkeys-lru` | 集群场景统一设置 LRU 淘汰,避免部分节点 OOM |
| `appendonly` | `yes` | 集群推荐 AOF + 每秒刷盘,兼顾性能与安全 |
| `cluster-replica-validity-factor` | 10 | 乘以 timeout 作为复制链路容忍阈值,0 表示不拒绝主从链接 |
| `cluster-require-full-coverage` | `yes`(默认) | `yes` 时任意 slot 无主节点则集群整体拒绝写入;生产环境若追求可用性可设 `no`,允许部分 slot 不可用时其余 slot 正常服务 |
| `cluster-allow-reads-when-down` | `no` | 设为 `yes` 时集群即使处于 FAIL 状态也允许读请求(前提:该 key 所在 slot 有可达节点),适合读密集型业务容忍短暂降级 |
> [!IMPORTANT] `cluster-require-full-coverage` 的取舍
> 当某个 Master 和它的所有 Replica 同时宕机时,该 Master 负责的 slot 就"裸奔"了。
> - **`yes`(默认)**:集群整体拒绝读写,宁可停机也不允许数据不一致——适合对一致性要求极高的金融场景。
> - **`no`**:集群只拒绝访问故障 slot 的请求,其他 slot 继续服务——适合追求可用性的互联网业务,牺牲部分可用 slot 换取整体不宕机。
### 架构最佳实践