From 9000c90abe07114c18c237e54902b693296e9b22 Mon Sep 17 00:00:00 2001 From: hhs <386998068@qq.com> Date: Mon, 25 May 2026 22:24:47 +0800 Subject: [PATCH] vault backup: 2026-05-25 22:24:47 --- .../02-核心数据类型/02-1-ziplist与listpack.md | 24 ++++++++++++------- hhs/Redis/02-核心数据类型/02-3-hashtable.md | 12 +++++----- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/hhs/Redis/02-核心数据类型/02-1-ziplist与listpack.md b/hhs/Redis/02-核心数据类型/02-1-ziplist与listpack.md index 23d09a1..e0456aa 100644 --- a/hhs/Redis/02-核心数据类型/02-1-ziplist与listpack.md +++ b/hhs/Redis/02-核心数据类型/02-1-ziplist与listpack.md @@ -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 节点** ## 关联笔记 diff --git a/hhs/Redis/02-核心数据类型/02-3-hashtable.md b/hhs/Redis/02-核心数据类型/02-3-hashtable.md index edcd47f..34482b5 100644 --- a/hhs/Redis/02-核心数据类型/02-3-hashtable.md +++ b/hhs/Redis/02-核心数据类型/02-3-hashtable.md @@ -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 而不是直接存数组?