Skip to content
Open
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
104 changes: 104 additions & 0 deletions configure-memory-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,110 @@ TiDB 支持对执行算子的数据落盘功能。当 SQL 的内存使用超过
9 rows in set (1 min 37.428 sec)
```

## 全局内存管理架构

TiDB 从 v9.0.0 开始引入全局内存管理框架 `Global Memory Arbitrator`,可通过系统变量 [`tidb_mem_arbitrator_mode`](/system-variables.md#tidb_mem_arbitrator_mode-从-v900-版本开始引入) 或 TiDB 配置文件参数 `instance.tidb_mem_arbitrator_mode` 开启。

`tidb_mem_arbitrator_mode` 默认为 `disable`。该模式下内存资源先使用后上报,[相关控制行为同上](#如何配置-tidb-server-实例使用内存的阈值)。

设置 `tidb_mem_arbitrator_mode``standard``priority` 启用先订阅后分配模式,由各个 TiDB 实例中唯一的仲裁者统筹内存资源。

仲裁者会通过终止 SQL 来回收内存资源,并向客户端返回编号为 `8180` 的错误。错误格式为:`Query execution was stopped by the global memory arbitrator [reason=?, path=?] [conn=?]`

- `conn`:连接(会话)ID
- `reason`:终止 SQL 的具体原因
- `path`:SQL 被终止的阶段(无 `path` 字段则默认为执行阶段),例如:`ParseSQL`(解析);`CompilePlan`(编译执行计划);

### `standard` 模式

SQL 运行过程中会动态地向仲裁者订阅内存资源,仲裁者按先来先服务原则处理订阅请求。如果全局内存资源不足,仲裁者令请求失败并终止 SQL。返回错误中 `reason` 字段为 `CANCEL(out-of-quota & standard-mode)`

### `priority` 模式

SQL 运行过程中会动态地向仲裁者订阅内存资源,仲裁者根据 SQL 的[资源组优先级](/information-schema/information-schema-resource-groups.md) (`LOW | MEDIUM | HIGH`) 处理订阅请求。

- 所有请求按照优先级从高到低排队等待资源,同级别请求按照发起顺序排序
- 当全局内存资源不足时,仲裁者按顺序(优先级从低到高,内存使用量从大到小)终止低优先级 SQL,回收资源来满足高优先级 SQL
- 如果所有 SQL 的优先级相同,仲裁者会调度资源直到所有 SQL 运行完,可能因此导致部分 SQL 延迟明显增大
- 返回错误中 `reason` 字段为 `CANCEL(out-of-quota & priority-mode)`

如果需要 SQL 避免因等待内存资源所带来的延迟开销,可以设置 session 变量 [`tidb_mem_arbitrator_wait_averse`](/system-variables.md#tidb_mem_arbitrator_wait_averse-从-v900-版本开始引入) 为 `1`。该参数令 SQL 自动绑定 `HIGH` 优先级。当全局内存资源不足时,仲裁者直接终止 SQL。返回错误中 `reason` 字段为 `CANCEL(out-of-quota & wait-averse)`。

### 内存风险控制

当 TiDB 实例的内存用量达到 [`tidb_server_memory_limit`](/system-variables.md#tidb_server_memory_limit-从-v640-版本开始引入) 的 95% 这一阈值时,仲裁者开始处理内存风险。如果内存用量短期无法低于到安全线或者内存使用速率过小,仲裁者会按顺序(优先级从低到高,内存使用量从大到小)强制终止 SQL,返回错误中 `reason` 字段为 `KILL(out-of-memory)`。

如果需要在内存资源不足时强制运行 SQL,可以设置 session 变量 [`tidb_mem_arbitrator_wait_averse`](/system-variables.md#tidb_mem_arbitrator_wait_averse-从-v900-版本开始引入) 为 `nolimit`。该参数令 SQL 使用内存不受框架限制,但可能导致 TiDB 实例内存风险。

### 手动保障内存安全

通过系统变量 [`tidb_mem_arbitrator_soft_limit`](/system-variables.md#tidb_mem_arbitrator_soft_limit-从-v900-版本开始引入) 或 TiDB 配置文件参数 `instance.tidb_mem_arbitrator_soft_limit` 可以设置 TiDB 实例的内存资源份额上限。上限越小,全局内存越安全,但内存资源利用率越低。该变量可用于手动快速收敛内存风险。

框架内部会缓存部分 SQL 的历史最大内存资源用量,并在 SQL 下次执行前预先订阅足量内存资源份额。如果已知 SQL 存在大量内存使用不受控制的问题,可通过 session 变量 [`tidb_mem_arbitrator_query_reserved`](/system-variables.md#tidb_mem_arbitrator_query_reserved-从-v900-版本开始引入) 指定 SQL 订阅的份额。该值越大,全局内存越安全,但内存资源利用率越低。预先订阅足量或超量的份额可以有效地保障 SQL 的内存资源隔离性。

### 监控和观测指标

`Grafana` 监控新增 `TiDB / Memory Arbitrator` 面板,包含以下指标:

- Work Mode:各个 TiDB 实例的内存管理模式
- Arbitration Exec:框架处理各类请求的统计
- Events:框架内各类事件的统计
- Mem Quota Stats:各类内存资源份额占用
- Mem Quota Arbitration:内存资源订阅请求处理耗时
- Mem Pool Stats:各类内存池的数量
- Runtime Mem Pressure:内存压力值(实际内存使用和内存资源份额使用的比率)
- Waiting Tasks:排队等待中的各类任务数量

[`SLOW_QUERY`](/information-schema/information-schema-slow-query.md) 新增 `Mem_arbitration` 字段表示 SQL 等待内存资源的总耗时。

[`PROCESSLIST`](/information-schema/information-schema-processlist.md) 新增以下字段:

- `MEM_ARBITRATION`:目前为止 SQL 等待内存资源的总耗时
- `MEM_WAIT_ARBITRATE_START`:当前内存资源订阅请求的开始时间(没有则为 NULL
- `MEM_WAIT_ARBITRATE_BYTES`:当前内存资源订阅请求的申请字节数(没有则为 NULL

[Expensive query](/identify-expensive-queries.md) 新增字段 `mem_arbitration`,用于记录 SQL 等待资源耗时和当前订阅请求的信息,例如:

- `cost_time 2.1s, wait_start 1970-01-02 10:17:36.789 UTC, wait_bytes 123456789123 Bytes (115.0 GB)`

[`STATEMENTS_SUMMARY`](/statement-summary-tables.md):表 `statements_summary``statements_summary_history``cluster_statements_summary``cluster_statements_summary_history` 新增字段以下字段:

- `AVG_MEM_ARBITRATION`:平均 SQL 等待内存资源耗时
- `MAX_MEM_ARBITRATION`:最大 SQL 等待内存资源耗时

### 实践

默认系统变量 [`tidb_server_memory_limit`](/system-variables.md#tidb_server_memory_limit-从-v640-版本开始引入) 较小,启用先订阅后分配模式后建议设置为 `95%`。

部署单节点 TiDB 场景

- 开启 `priority` 模式:绑定 OLTP 相关或重要 SQL 到高优先级,按需绑定其他 SQL 到中或低优先级
- 开启 `standard` 模式:遇到 `8180` 错误需等待并重试 SQL

部署多节点 TiDB 场景

- [1] 开启 `standard` 模式
- 遇到 `8180` 错误则重试 SQL 到其他 TiDB 节点

- [2] 开启 `priority` 模式
- 为 OLTP 相关或重要 SQL 绑定高优先级
- 按需绑定其他 SQL 到中/低优先级
- 通过 [`max_execution_time`](/system-variables.md#max_execution_time) 限制 SQL 最大执行时间
- 遇到超时或 `8180` 错误则重试 SQL 到其他 TiDB 节点
- 可通过设置 [`tidb_mem_arbitrator_wait_averse`](/system-variables.md#tidb_mem_arbitrator_wait_averse-从-v900-版本开始引入) 使 SQL 尽快重试到内存资源充足的节点

- [3] TiDB 实例分组
- 各组内通过配置文件参数 `instance.tidb_mem_arbitrator_mode` 设置 TiDB 实例内存管理模式
- 各组内通过配置文件参数 `instance.tidb_mem_arbitrator_soft_limit` 按需设置 TiDB 实例内存资源份额上限
- 按需分发 SQL 到不同组,并按照上述不同模式处理

保障重要 SQL 执行

- 通过 [`tidb_mem_arbitrator_query_reserved`](/system-variables.md#tidb_mem_arbitrator_query_reserved-从-v900-版本开始引入) 保障 SQL 的内存资源隔离性
- 绑定高优先级的资源组
- 设置 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 为较大值以免 SQL 执行被中断
- 保底方案为设置 [`tidb_mem_arbitrator_wait_averse`](/system-variables.md#tidb_mem_arbitrator_wait_averse-从-v900-版本开始引入) 为 `nolimit` 并承担内存风险

## 其它

### 设置环境变量 `GOMEMLIMIT` 缓解 OOM 问题
Expand Down
65 changes: 65 additions & 0 deletions system-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -3328,6 +3328,71 @@ v5.0 后,用户仍可以单独修改以上系统变量(会有废弃警告)
- 单位:线程
- TiFlash 中 request 执行的最大并发度。默认值为 `-1`,表示该系统变量无效,此时最大并发度取决于 TiFlash 配置项 `profiles.default.max_threads` 的设置。`0` 表示由 TiFlash 系统自动设置该值。

### `tidb_mem_arbitrator_mode` <span class="version-mark">从 v9.0.0 版本开始引入</span>

> **警告:**
>
> 该变量控制的功能为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。

- 作用域:GLOBAL
- 是否持久化到集群:是
- 是否受 Hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value) 控制:否
- 类型:枚举型
- 默认值:`disable`
- 可选值:`disable``standard`, `priority`
- 该变量用于设置 TiDB 实例的全局内存管理模式,详见 [TiDB 内存控制](/configure-memory-usage.md#全局内存管理架构):
- `disable` 为默认模式,[控制行为同上](/system-variables.md#tidb_server_memory_limit-从-v640-版本开始引入):内存资源先使用后上报
- `standard``priority` 为先订阅后分配模式:
- `standard`:SQL 订阅内存资源失败后终止执行
- `priority`:TiDB 根据 SQL 的[资源组优先级](/information-schema/information-schema-resource-groups.md) 处理内存资源订阅任务

### `tidb_mem_arbitrator_query_reserved` <span class="version-mark">从 v9.0.0 版本开始引入</span>

> **警告:**
>
> 该变量控制的功能为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。

- 作用域:SESSION
- 是否受 Hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value) 控制:是
- 类型:整数型
- 默认值:`0`
- 单位:字节
- 范围:`[0, 9223372036854775807]`
- 当通过 [`tidb_mem_arbitrator_mode`](/system-variables.md#tidb_mem_arbitrator_mode-从-v900-版本开始引入) 启用先订阅后分配的全局内存管理模式后,该变量设置 SQL 执行前预先订阅指定数量的内存资源份额,详见 [TiDB 内存控制](/configure-memory-usage.md#全局内存管理架构)。

### `tidb_mem_arbitrator_soft_limit` <span class="version-mark">从 v9.0.0 版本开始引入</span>

> **警告:**
>
> 该变量控制的功能为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。

- 作用域:GLOBAL
- 是否持久化到集群:是
- 是否受 Hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value) 控制:否
- 类型:字符串
- 默认值:`0`
- 可选值:`0`,浮点数 `(0, 1]`,整数 `(1, 9223372036854775807]`
- 当通过 [`tidb_mem_arbitrator_mode`](/system-variables.md#tidb_mem_arbitrator_mode-从-v900-版本开始引入) 启用先订阅后分配的全局内存管理模式后,该变量设置 TiDB 实例的内存资源份额上限,详见 [TiDB 内存控制](/configure-memory-usage.md#全局内存管理架构)。
- `0`:默认资源份额上限为 [`tidb_server_memory_limit`](/system-variables.md#tidb_server_memory_limit-从-v640-版本开始引入) 的值的 `95%`
- 浮点数 `(0, 1]`:指定比率,资源份额上限为 `tidb_mem_arbitrator_soft_limit *` [`tidb_server_memory_limit`](/system-variables.md#tidb_server_memory_limit-从-v640-版本开始引入)
- 整数 `(1, 9223372036854775807]`:指定字节数

### `tidb_mem_arbitrator_wait_averse` <span class="version-mark">从 v9.0.0 版本开始引入</span>

> **警告:**
>
> 该变量控制的功能为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。

- 作用域:SESSION
- 是否受 Hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value) 控制:否
- 类型:枚举型
- 默认值:`0`
- 可选值:`0``1``nolimit`
- 当通过 [`tidb_mem_arbitrator_mode`](/system-variables.md#tidb_mem_arbitrator_mode-从-v900-版本开始引入) 启用先订阅后分配的全局内存管理模式后,该变量控制 SQL 避免阻塞式等待内存资源的相关行为,详见 [TiDB 内存控制](/configure-memory-usage.md#全局内存管理架构)。
- `0`:无
- `1``priority` 模式下,SQL 订阅内存资源时自动绑定高优先级,全局内存资源不足时就终止执行而非等待
- `nolimit`:SQL 使用内存资源不受限制,可能导致 TiDB 实例内存风险

### `tidb_mem_oom_action` <span class="version-mark">从 v6.1.0 版本开始引入</span>

- 作用域:GLOBAL
Expand Down