Skip to content

Commit

Permalink
Add IME document (#19118)
Browse files Browse the repository at this point in the history
  • Loading branch information
overvenus authored Dec 9, 2024
1 parent 49f76f0 commit 2610627
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 4 deletions.
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 @@ -1025,7 +1025,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 @@ -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 大小。
Expand Down Expand Up @@ -2504,3 +2504,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 @@ -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)功能缓解。

0 comments on commit 2610627

Please sign in to comment.