vault backup: 2026-05-25 22:24:47

This commit is contained in:
hhs
2026-05-25 22:24:47 +08:00
parent 7e4671fe25
commit 9000c90abe
2 changed files with 22 additions and 14 deletions
@@ -223,15 +223,23 @@ flowchart TB
> [!insight] 紧凑结构不是万能的
> ziplist/listpack 的查找是 O(N)——要从头遍历到目标 entry。当元素少时,这块连续内存对 CPU cache 非常友好,遍历也很快。但元素一多,O(N) 的代价就压不住了,必须切到 hashtable(O(1))或 skiplist(O(logN))。
各类型的切换阈值:
各类型的切换阈值——**阈值内**用紧凑编码省内存,**超过阈值**切到通用结构保性能:
| 数据类型 | 配置项 | 默认值 | 切换到 |
|---------|--------|--------|-------|
| Hash | `hash-max-ziplist-entries` | 512 | hashtable |
| Hash | `hash-max-ziplist-value` | 64 字节 | hashtable |
| ZSet | `zset-max-ziplist-entries` | 128 | skiplist+hashtable |
| ZSet | `zset-max-ziplist-value` | 64 字节 | skiplist+hashtable |
| List | `list-max-ziplist-size` | -2 (每个节点 8KB) | quicklist 新节点 |
| 数据类型 | 阈值内编码 | 配置项 | 默认值 | 超过阈值切到 |
|---------|-----------|--------|--------|------------|
| Hash | listpack ¹ | `hash-max-ziplist-entries` | 512 个 field | **dict**(hashtable) |
| Hash | listpack ¹ | `hash-max-ziplist-value` | 64 字节 | **dict**(hashtable) |
| ZSet | listpack ¹ | `zset-max-ziplist-entries` | 128 个 member | **skiplist + dict** |
| ZSet | listpack ¹ | `zset-max-ziplist-value` | 64 字节 | **skiplist + dict** |
| List | quicklist 节点内的 listpack | `list-max-ziplist-size` ² | -2(每节点 8KB) | quicklist **新节点** |
¹ Redis 6 为 ziplist,7.0+ 为 listpack。配置参数名不变。
² Redis 7.2+ 配置项更名为 `list-max-listpack-size`。
> [!question] 切换后各自长什么样?
> - **Hash**:从一块连续内存(listpack)变成 **dict**——两张 hashtable 交替 rehash,查找从 O(N) → O(1)
> - **ZSet**:从一块连续内存(listpack)变成 **skiplist + dict** 的双结构——skiplist 负责有序遍历和范围查询 O(logN),dict 负责按 member 查 score O(1)
> - **List**:不是"丢弃 listpack",而是 quicklist 继续以 listpack 为节点内容,只是**单个节点的容量上限**受此阈值控制;超限时 quicklist 不会转换编码,而是把新元素放进一个**新的 listpack 节点**
## 关联笔记
@@ -134,12 +134,12 @@ entry := ht.table[idx] // 拿到链表头,遍历查找
```mermaid
flowchart TB
S1["1. 分配 ht[1]"] --> S2["2. rehashidx = 0, 开始渐进式迁移"]
S2 --> S3["3. 每次 CRUD 操作时, 迁移 ht[0] 上 rehashidx 指向的整个 bucket 到 ht[1]"]
S3 --> S4["4. rehashidx++"]
S1["分配 ht[1]"] --> S2["rehashidx = 0, 开始渐进式迁移"]
S2 --> S3["每次 CRUD 操作时, 迁移 ht[0] 上 rehashidx 指向的整个 bucket 到 ht[1]"]
S3 --> S4["rehashidx++"]
S4 --> S5{"所有 bucket 已迁移?"}
S5 -->|"否"| S3
S5 -->|"是"| S6["5. 释放 ht[0], ht[1] 变成 ht[0], 分配新空 ht[1]"]
S5 -->|"是"| S6["释放 ht[0], ht[1] 变成 ht[0], 分配新空 ht[1]"]
classDef step fill:#e1f5fe,stroke:#2196f3
classDef check fill:#fff3e0,stroke:#ff9800
@@ -261,8 +261,8 @@ flowchart LR
| 数据类型 | hashtable 的角色 | 特殊之处 |
|---------|-----------------|---------|
| **Hash** | 唯一存储结构(大 Hash 时) | field→value 直接映射 |
| **Set** | 唯一存储结构(含非整数元素时) | member→NULL,只用 key |
| **Hash** | 存储结构之一(超过 `hash-max-listpack-entries` / `hash-max-listpack-value` 阈值后;小 Hash 优先使用 listpack) | field→value 直接映射 |
| **Set** | 存储结构之一(含非整数元素或超过 `set-max-intset-entries` 阈值时;全整数小集合优先使用 intset) | member→NULL,只用 key |
| **ZSet** | skiplist 的"辅助索引" | member→score,配合 skiplist 实现 O(1) 定位 |
> [!insight] 为什么 Set 用 hashtable 而不是直接存数组?