Skip to content

Latest commit

 

History

History
134 lines (101 loc) · 7.88 KB

tikv-in-memory-engine.md

File metadata and controls

134 lines (101 loc) · 7.88 KB
title summary
TiKV MVCC 内存引擎
了解内存引擎的适用场景和工作原理,使用内存引擎加速多版本记录查询。

TiKV MVCC 内存引擎

TiKV MVCC 内存引擎 (In-Memory Engine, IME) 主要用于加速需要扫描大量 MVCC 历史版本的查询,即查询扫描的总共版本数量 (total_keys) 远大于处理的版本数量 (processed_keys)

TiKV MVCC 内存引擎适用于以下场景:

  • 业务需要查询频繁更新或删除的记录。
  • 业务需要调整 tidb_gc_life_time,使 TiDB 保留较长时间的历史版本(比如 24 小时)。

工作原理

TiKV MVCC 内存引擎在内存中缓存最近写入的 MVCC 版本,并实现独立于 TiDB 的 MVCC GC 机制,使其可快速 GC 内存中的 MVCC 记录,从而减少查询时扫描版本的个数,以达到降低请求延时和减少 CPU 开销的效果。

下图为 TiKV 如何组织 MVCC 版本的示意图:

IME 通过缓存近期的版本以减少 CPU 开销

以上示意图中共有 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。以下是配置说明:

[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 restore 会驱逐内存引擎中涉及恢复的 Region,BR restore 完成后,如果对应 Region 还是热点,则会被内存引擎自动加载。
  • TiDB Lightning:内存引擎与 TiDB Lightning 可同时使用,但 TiDB Lightning 的物理导入模式会驱逐内存引擎中涉及恢复的 Region,TiDB Lightning 使用物理导入模式完成导入数据后,如果对应 Region 还是热点,则会被内存引擎自动加载。
  • Follower ReadStale Read:内存引擎可与这两个特性同时开启,但内存引擎只能加速 Leader 上的 coprocessor 请求,无法加速 Follower Read 和 Stale Read。
  • FLASHBACK CLUSTER:内存引擎与 Flashback 可同时使用,但 Flashback 会导致内存引擎缓存失效。Flashback 完成后,内存引擎会自动加载热点 Region。

FAQ

内存引擎能否减少写入延时,提高写入吞吐?

不能。内存引擎只能加速扫描了大量 MVCC 版本的读请求。

如何判断内存引擎是否能改善我的场景?

可以通过执行以下 SQL 语句查看是否存在 Total_keys 远大于 Process_keys 的慢查询:

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)