diff --git a/TOC.md b/TOC.md index ed58f67f1945..242202e7ec55 100644 --- a/TOC.md +++ b/TOC.md @@ -314,6 +314,7 @@ - [TiKV 线程调优](/tune-tikv-thread-performance.md) - [TiKV 内存调优](/tune-tikv-memory-performance.md) - [TiKV Follower Read](/follower-read.md) + - [TiKV MVCC 内存引擎](/tikv-in-memory-engine.md) - [Region 性能调优](/tune-region-performance.md) - [TiFlash 调优](/tiflash/tune-tiflash-performance.md) - [下推计算结果缓存](/coprocessor-cache.md) diff --git a/analyze-slow-queries.md b/analyze-slow-queries.md index 17dcbc6d70a2..8005c593560e 100644 --- a/analyze-slow-queries.md +++ b/analyze-slow-queries.md @@ -96,9 +96,9 @@ summary: 学习如何定位和分析慢查询。 如上图,发给 `10.6.131.78` 的一个 `cop-task` 等待了 110ms 才被执行,可以判断是当时该实例忙,此时可以打开当时的 CPU 监控辅助判断。 -#### 过期 key 多 +#### 过期 MVCC 版本和 key 过多 -如果 TiKV 上过期的数据比较多,在扫描的时候则需要处理这些不必要的数据,影响处理速度。 +如果 TiKV 上过期 MVCC 版本过多,或 GC 历史版本数据的保留时间长,导致累积了过多 MVCC。处理这些不必要的 MVCC 版本会影响扫描速度。 这可以通过 `Total_keys` 和 `Processed_keys` 判断,如果两者相差较大,则说明旧版本的 key 太多: @@ -108,6 +108,8 @@ summary: 学习如何定位和分析慢查询。 ... ``` +TiDB v8.5.0 引入了内存引擎功能,可以加速这类慢查询。详见 [TiKV MVCC 内存引擎](/tikv-in-memory-engine.md)。 + ### 其他关键阶段慢 #### 取 TS 慢 diff --git a/media/tikv-ime-data-organization.png b/media/tikv-ime-data-organization.png new file mode 100644 index 000000000000..4ccd51f56236 Binary files /dev/null and b/media/tikv-ime-data-organization.png differ diff --git a/tikv-configuration-file.md b/tikv-configuration-file.md index dbe4f8099fc6..f041d100d5fc 100644 --- a/tikv-configuration-file.md +++ b/tikv-configuration-file.md @@ -1025,7 +1025,7 @@ raftstore 相关的配置项。 + 最小值:0 + 单位:秒 -### `evict-cache-on-memory-ratio` 从 v7.5.0 版本开始引入 +### `evict-cache-on-memory-ratio` 从 v7.5.0 版本开始引入 + 当 TiKV 的内存使用超过系统可用内存的 90%,并且 Raft 缓存条目占用的内存超过已使用内存 * `evict-cache-on-memory-ratio` 时,TiKV 会逐出 Raft 缓存条目。 + 设置为 `0` 表示禁用该功能。 @@ -1682,7 +1682,7 @@ rocksdb defaultcf titan 相关的配置项。 + 指定 zstd 字典大小,默认为 `"0KiB"`,表示关闭 zstd 字典压缩,也就是说 Titan 中压缩的是单个 value 值,而 RocksDB 压缩以 Block(默认值为 `32KiB`)为单位。因此当关闭字典压缩、且 value 平均小于 `32KiB` 时,Titan 的压缩率低于 RocksDB。以 JSON 内容为例,Titan 的 Store Size 可能比 RocksDB 高 30% 至 50%。实际压缩率还取决于 value 内容是否适合压缩,以及不同 value 之间的相似性。你可以通过设置 `zstd-dict-size`(比如 `16KiB`)启用 zstd 字典以大幅提高压缩率(实际 Store Size 可以低于 RocksDB),但 zstd 字典压缩在有些负载下会有 10% 左右的性能损失。 + 默认值:`"0KiB"` + 单位:KiB|MiB|GiB - + ### `blob-cache-size` + Blob 文件的 cache 大小。 @@ -2504,3 +2504,36 @@ Raft Engine 相关的配置项。 + 设置 TiKV 堆内存分析每次采样的数据量,以 2 的指数次幂向上取整。 + 默认值:512KiB + +## in-memory-engine 从 v8.5.0 版本开始引入 + +TiKV MVCC 内存引擎 (In-Memory Engine) 在 TiKV 存储层相关的配置项。 + +### `enable` 从 v8.5.0 版本开始引入 + +> **注意:** +> +> 该配置项支持在配置文件中进行配置,但不支持通过 SQL 语句查询。 + ++ 是否开启内存引擎以加速多版本查询。关于内存引擎的详细信息,参见 [TiKV MVCC 内存引擎](/tikv-in-memory-engine.md)。 ++ 默认值:false(即关闭内存引擎) + +### `capacity` 从 v8.5.0 版本开始引入 + +> **注意:** +> +> + 开启内存引擎后,`block-cache.capacity` 会自动减少 10%。 +> + 手动配置 `capacity` 时,`block-cache.capacity` 不会自动减少,需手动调整为合适的值以避免 OOM。 + ++ 配置内存引擎可使用的内存大小。最大值为 5 GiB。你可以手动调整配置以使用更多内存。 ++ 默认值:系统内存的 10%。 + +### `gc-run-interval` 从 v8.5.0 版本开始引入 + ++ 控制内存引擎 GC 缓存 MVCC 版本的时间间隔。调小该参数可加快 GC 频率,减少 MVCC 记录,但会增加 GC 的 CPU 消耗,以及增加内存引擎失效的概率。 ++ 默认值:3m + +### `mvcc-amplification-threshold` 从 v8.5.0 版本开始引入 + ++ 控制内存引擎选取加载 Region 时 MVCC 读放大的阈值。默认为 `10`,表示在某个 Region 中读一行记录需要处理的 MVCC 版本数量超过 10 个时,有可能会被加载到内存引擎中。 ++ 默认值:10 diff --git a/tikv-in-memory-engine.md b/tikv-in-memory-engine.md new file mode 100644 index 000000000000..7e0b3291afa0 --- /dev/null +++ b/tikv-in-memory-engine.md @@ -0,0 +1,134 @@ +--- +title: TiKV MVCC 内存引擎 +summary: 了解内存引擎的适用场景和工作原理,使用内存引擎加速多版本记录查询。 +--- + +# TiKV MVCC 内存引擎 + +TiKV MVCC 内存引擎 (In-Memory Engine, IME) 主要用于加速需要扫描大量 MVCC 历史版本的查询,即[查询扫描的总共版本数量 (`total_keys`) 远大于处理的版本数量 (`processed_keys`)](/analyze-slow-queries.md#过期-mvcc-版本和-key-过多)。 + +TiKV MVCC 内存引擎适用于以下场景: + +- 业务需要查询频繁更新或删除的记录。 +- 业务需要调整 [`tidb_gc_life_time`](/garbage-collection-configuration.md#gc-配置),使 TiDB 保留较长时间的历史版本(比如 24 小时)。 + +## 工作原理 + +TiKV MVCC 内存引擎在内存中缓存最近写入的 MVCC 版本,并实现独立于 TiDB 的 MVCC GC 机制,使其可快速 GC 内存中的 MVCC 记录,从而减少查询时扫描版本的个数,以达到降低请求延时和减少 CPU 开销的效果。 + +下图为 TiKV 如何组织 MVCC 版本的示意图: + +![IME 通过缓存近期的版本以减少 CPU 开销](/media/tikv-ime-data-organization.png) + +以上示意图中共有 2 行记录,每行记录各有 9 个 MVCC 版本。在开启内存引擎和未开启内存引擎的情况下,行为对比如下: + +- 左侧(未开启内存引擎):表中记录按主键升序保存在 RocksDB 中,相同行的 MVCC 版本紧邻在一起。 +- 右侧(开启了内存引擎):RocksDB 中的数据与左侧一致,同时内存引擎缓存了 2 行记录最新的 2 个 MVCC 版本。 +- 当 TiKV 处理一个范围为 `[k1, k2]`,开始时间戳为 `8` 的扫描请求时: + - 左侧未开启内存引擎时需要处理 11 个 MVCC 版本。 + - 右侧开启内存引擎时只需处理 4 个 MVCC 版本,因此减少了请求延时和 CPU 消耗。 +- 当 TiKV 处理一个范围为 `[k1, k2]`,开始时间戳为 `7` 的扫描请求时: + - 由于右侧缺少需要读取的历史版本,因此内存引擎缓存失效,回退到读取 RocksDB 中的数据。 + +## 使用方式 + +如果要开启 TiKV MVCC 内存引擎 (IME) 功能,需要调整 TiKV 配置并重启 TiKV。以下是配置说明: + +```toml +[in-memory-engine] +# 该参数为内存引擎功能的开关,默认为 false,调整为 true 即可开启。 +enable = false + +# 该参数控制内存引擎可使用的内存大小。默认值为系统内存的 10%,同时最大值为 5 GiB, +# 可通过手动调整配置以使用更多内存。 +# 注意:当内存引擎开启后,block-cache.capacity 会减少 10%。 +capacity = "5GiB" + +# 该参数控制内存引擎 GC 缓存 MVCC 的版本的时间间隔。 +# 默认为 3 分钟,代表每 3 分钟 GC 一次缓存的 MVCC 版本。 +# 调小该参数可加快 GC 频率,减少 MVCC 记录,但会增加 GC CPU 的消耗和增加内存引擎失效的概率。 +gc-run-interval = "3m" + +# 该参数控制内存引擎选取加载 Region 时 MVCC 读放大的阈值。 +# 默认为 10,表示在某个 Region 中读一行记录需要处理的 MVCC 版本数量超过 10 个时,将有可能会被加载到内存引擎中。 +mvcc-amplification-threshold = 10 +``` + +> **注意:** +> +> + 内存引擎默认关闭,并且从关闭状态修改为开启状态后,需要重启 TiKV。 +> + 除 `enable` 之外,其他配置都可以动态调整。 + +### 自动加载 + +开启内存引擎之后,TiKV 会根据 Region 的读流量和 MVCC 放大程度,选择要自动加载的 Region。具体流程如下: + +1. Region 按照最近时间段的 `next` (RocksDB Iterator next API) 和 `prev` (RocksDB Iterator prev API) 次数进行排序。 +2. 使用 `mvcc-amplification-threshold` 配置项对 Region 进行过滤,该配置项的默认值为 `10`。MVCC amplification 衡量读放大程度,计算公式为 (`next` + `prev`) / `processed_keys`)。 +3. 载入前 N 个 MVCC 放大严重的 Region,其中 N 基于内存估算而来。 + +内存引擎也会定期驱逐 Region。具体流程如下: + +1. 内存引擎会驱逐那些读流量过小或者 MVCC 放大程度过低的 Region。 +2. 如果内存使用达到了 `capacity` 的 90%,并且有新的 Region 需要被载入,那么内存引擎会根据读取流量来筛选 Region 并进行驱逐。 + +## 兼容性 + ++ [BR](/br/br-use-overview.md):内存引擎与 BR 可同时使用,但 BR restore 会驱逐内存引擎中涉及恢复的 Region,BR restore 完成后,如果对应 Region 还是热点,则会被内存引擎自动加载。 ++ [TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md):内存引擎与 TiDB Lightning 可同时使用,但 TiDB Lightning 的物理导入模式会驱逐内存引擎中涉及恢复的 Region,TiDB Lightning 使用物理导入模式完成导入数据后,如果对应 Region 还是热点,则会被内存引擎自动加载。 ++ [Follower Read](/develop/dev-guide-use-follower-read.md) 与 [Stale Read](/develop/dev-guide-use-stale-read.md):内存引擎可与这两个特性同时开启,但内存引擎只能加速 Leader 上的 coprocessor 请求,无法加速 Follower Read 和 Stale Read。 ++ [`FLASHBACK CLUSTER`](/sql-statements/sql-statement-flashback-cluster.md):内存引擎与 Flashback 可同时使用,但 Flashback 会导致内存引擎缓存失效。Flashback 完成后,内存引擎会自动加载热点 Region。 + +## FAQ + +### 内存引擎能否减少写入延时,提高写入吞吐? + +不能。内存引擎只能加速扫描了大量 MVCC 版本的读请求。 + +### 如何判断内存引擎是否能改善我的场景? + +可以通过执行以下 SQL 语句查看是否存在 `Total_keys` 远大于 `Process_keys` 的慢查询: + +```sql +SELECT + Time, + DB, + Index_names, + Process_keys, + Total_keys, + CONCAT( + LEFT(REGEXP_REPLACE(Query, '\\s+', ' '), 20), + '...', + RIGHT(REGEXP_REPLACE(Query, '\\s+', ' '), 10) + ) as Query, + Query_time, + Cop_time, + Process_time +FROM + INFORMATION_SCHEMA.SLOW_QUERY +WHERE + Is_internal = 0 + AND Cop_time > 1 + AND Process_keys > 0 + AND Total_keys / Process_keys >= 10 + AND Time >= NOW() - INTERVAL 10 MINUTE +ORDER BY Total_keys DESC +LIMIT 5; +``` + +示例: + +以下结果显示 `db1.tbl1` 表上存在 MVCC 放大严重的查询,TiKV 在处理 1358517 个 MVCC 版本后,仅返回了 2 个版本。 + +``` ++----------------------------+-----+-------------------+--------------+------------+-----------------------------------+--------------------+--------------------+--------------------+ +| Time | DB | Index_names | Process_keys | Total_keys | Query | Query_time | Cop_time | Process_time | ++----------------------------+-----+-------------------+--------------+------------+-----------------------------------+--------------------+--------------------+--------------------+ +| 2024-11-18 11:56:10.303228 | db1 | [tbl1:some_index] | 2 | 1358517 | SELECT * FROM tbl1 ... LIMIT 1 ; | 1.2581352350000001 | 1.25651062 | 1.251837479 | +| 2024-11-18 11:56:11.556257 | db1 | [tbl1:some_index] | 2 | 1358231 | SELECT * FROM tbl1 ... LIMIT 1 ; | 1.252694002 | 1.251129038 | 1.240532546 | +| 2024-11-18 12:00:10.553331 | db1 | [tbl1:some_index] | 2 | 1342914 | SELECT * FROM tbl1 ... LIMIT 1 ; | 1.473941872 | 1.4720495900000001 | 1.3666103170000001 | +| 2024-11-18 12:01:52.122548 | db1 | [tbl1:some_index] | 2 | 1128064 | SELECT * FROM tbl1 ... LIMIT 1 ; | 1.058942591 | 1.056853228 | 1.023483875 | +| 2024-11-18 12:01:52.107951 | db1 | [tbl1:some_index] | 2 | 1128064 | SELECT * FROM tbl1 ... LIMIT 1 ; | 1.044847031 | 1.042546122 | 0.934768555 | ++----------------------------+-----+-------------------+--------------+------------+-----------------------------------+--------------------+--------------------+--------------------+ +5 rows in set (1.26 sec) +``` diff --git a/troubleshoot-hot-spot-issues.md b/troubleshoot-hot-spot-issues.md index 0abce246dc27..24cedca4862f 100644 --- a/troubleshoot-hot-spot-issues.md +++ b/troubleshoot-hot-spot-issues.md @@ -176,3 +176,7 @@ TiDB 的 Coprocessor Cache 功能支持下推计算结果缓存。开启该功 ## 打散读热点 在读热点场景中,热点 TiKV 无法及时处理读请求,导致读请求排队。但是,此时并非所有 TiKV 资源都已耗尽。为了降低延迟,TiDB v7.1.0 引入了负载自适应副本读取功能,允许从其他 TiKV 节点读取副本,而无需在热点 TiKV 节点排队等待。你可以通过 [`tidb_load_based_replica_read_threshold`](/system-variables.md#tidb_load_based_replica_read_threshold-从-v700-版本开始引入) 系统变量控制读请求的排队长度。当 leader 节点的预估排队时间超过该阈值时,TiDB 会优先从 follower 节点读取数据。在读热点的情况下,与不打散读热点相比,该功能可提高读取吞吐量 70%~200%。 + +## 使用 TiKV MVCC 内存引擎缓解因多版本导致的读热点 + +在 GC 历史版本数据的保留时间过长、频繁更新或删除时,可能会因扫描大量 MVCC 版本而导致读热点。针对这类热点,可通过开启 [TiKV MVCC 内存引擎](/tikv-in-memory-engine.md)功能缓解。