Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IME document (#19118) #19247

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions analyze-slow-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 太多:

Expand All @@ -108,6 +108,8 @@ summary: 学习如何定位和分析慢查询。
...
```

TiDB v8.5.0 引入了内存引擎功能,可以加速这类慢查询。详见 [TiKV MVCC 内存引擎](/tikv-in-memory-engine.md)。

### 其他关键阶段慢

#### 取 TS 慢
Expand Down
Binary file added media/tikv-ime-data-organization.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 35 additions & 2 deletions tikv-configuration-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ raftstore 相关的配置项。
+ 最小值:0
+ 单位:秒

### `evict-cache-on-memory-ratio` <span class="version-mark">从 v7.5.0 版本开始引入</span>
### `evict-cache-on-memory-ratio` <span class="version-mark">从 v7.5.0 版本开始引入</span>

+ 当 TiKV 的内存使用超过系统可用内存的 90%,并且 Raft 缓存条目占用的内存超过已使用内存 * `evict-cache-on-memory-ratio` 时,TiKV 会逐出 Raft 缓存条目。
+ 设置为 `0` 表示禁用该功能。
Expand Down Expand Up @@ -1681,7 +1681,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 大小。
Expand Down Expand Up @@ -2503,3 +2503,36 @@ Raft Engine 相关的配置项。

+ 设置 TiKV 堆内存分析每次采样的数据量,以 2 的指数次幂向上取整。
+ 默认值:512KiB

## in-memory-engine <span class="version-mark">从 v8.5.0 版本开始引入</span>

TiKV MVCC 内存引擎 (In-Memory Engine) 在 TiKV 存储层相关的配置项。

### `enable` <span class="version-mark">从 v8.5.0 版本开始引入</span>

> **注意:**
>
> 该配置项支持在配置文件中进行配置,但不支持通过 SQL 语句查询。

+ 是否开启内存引擎以加速多版本查询。关于内存引擎的详细信息,参见 [TiKV MVCC 内存引擎](/tikv-in-memory-engine.md)。
+ 默认值:false(即关闭内存引擎)

### `capacity` <span class="version-mark">从 v8.5.0 版本开始引入</span>

> **注意:**
>
> + 开启内存引擎后,`block-cache.capacity` 会自动减少 10%。
> + 手动配置 `capacity` 时,`block-cache.capacity` 不会自动减少,需手动调整为合适的值以避免 OOM。

+ 配置内存引擎可使用的内存大小。最大值为 5 GiB。你可以手动调整配置以使用更多内存。
+ 默认值:系统内存的 10%。

### `gc-run-interval` <span class="version-mark">从 v8.5.0 版本开始引入</span>

+ 控制内存引擎 GC 缓存 MVCC 版本的时间间隔。调小该参数可加快 GC 频率,减少 MVCC 记录,但会增加 GC 的 CPU 消耗,以及增加内存引擎失效的概率。
+ 默认值:3m

### `mvcc-amplification-threshold` <span class="version-mark">从 v8.5.0 版本开始引入</span>

+ 控制内存引擎选取加载 Region 时 MVCC 读放大的阈值。默认为 `10`,表示在某个 Region 中读一行记录需要处理的 MVCC 版本数量超过 10 个时,有可能会被加载到内存引擎中。
+ 默认值:10
134 changes: 134 additions & 0 deletions tikv-in-memory-engine.md
Original file line number Diff line number Diff line change
@@ -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)
```
4 changes: 4 additions & 0 deletions troubleshoot-hot-spot-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,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)功能缓解。
Loading