# TiDB 7.5资源管控能力测试

LLMS 索引： [llms.txt](/llms.txt)

---

> 在7.1时候，其实已经对资源管控做了测试：TiDB 7.1 资源管控验证测试[^1]。本文重点对7.1到7.5期间新增的资源管控能力进行测试，完整的功能特性见：TiDB 6.5升级7.5调研[^2]
>
> 1. 怎么理解`RU Quota`​？如何设置合理的`RU Quota`​？一个复杂查询的RU成本竟然会有`7W`​！  
>    资源组的`RU_PER_SEC`​限制的是资源组整体的消耗速度，可以看到`RU`​的消耗其实是包含对`TiKV`​读写请求封装的，虽然在TiKV层只有基于优先级的概念，没有直接对资源组做`Quota`​限制，但是通过限制`TiDB`​发送给`TiKV`​ 的请求数量，来间接达到`TiKV`​基于 `Quota`的限制。
> 2. 测试计划？？

## 1 什么是 Request Unit (RU)

Request Unit (RU) 是 TiDB 对 CPU、IO 等系统资源的统一抽象的计量单位，用于表示对数据库的单个请求消耗的资源量。请求消耗的 RU 数量取决于多种因素，例如操作类型或正在检索或修改的数据量。目前，RU 包含以下资源的统计信息：

<table>
<colgroup><col /><col /></colgroup><thead><tr>
<th>资源类型</th>
<th>RU 消耗</th>
</tr>
</thead><tbody>
<tr>
<td colspan="1" rowspan="3">**Read**<br /></td>
<td>2 storage read batches 消耗 1 RU</td>
</tr>
<tr>
<td>8 storage read requests 消耗 1 RU</td>
</tr>
<tr>
<td>64 KiB read request payload 消耗 1 RU</td>
</tr>
<tr>
<td colspan="1" rowspan="3">**Write**<br /></td>
<td>1 storage write batch 消耗 1 RU</td>
</tr>
<tr>
<td>1 storage write request 消耗 1 RU</td>
</tr>
<tr>
<td>1 KiB write request payload 消耗 1 RU</td>
</tr>
<tr>
<td>**SQL CPU**</td>
<td>3 ms 消耗 1 RU，也就是SQL执行时间为`1s`​需要消耗的RU为`333`</td>
</tr>
</tbody>
</table>
**查询的RU消耗：**

|SQL类型|示例|RU消耗|
| --------------------------------------------| -------------------| -----------------------|
|普通表主键查询|`explain analyze select * from ying99_fundtxn.fund_market where id='94';`|1.1 RU|
|普通表唯一索引查询|`explain analyze select * from fund_market where FundCode='000117' and UpdateDate='20150924' ;`|3.4 RU|
|普通表批量扫描1.3W行|`explain analyze select * from fund_market where importDay='20220901' ;`|312 RU|
|分区表二级索引点查(包含分区键)|`explain analyze select * from ying99_fundtxn.txn_confirm where AppSheetSerialNo='20190401009797711' and TransactionCfmDate='20190402';`|1.6 RU|
|分区表二级索引点查(不包含分区键、84个分区)|`explain analyze select * from ying99_fundtxn.txn_confirm where AppSheetSerialNo='20190401009797711';`|120 RU|

> 按照`CALIBRATE RESOURCE WORKLOAD TPCC`​​​​预估，三个TiKV节点 + 1 8C64G TiDB节点的集群`Quota`​​​​为：`38760`

# 2 Resource Group日常操作

> 日常可以查看：
>
> -  [tidb-resource-control#管理资源组](https://docs.pingcap.com/zh/tidb/stable/tidb-resource-control#%E7%AE%A1%E7%90%86%E8%B5%84%E6%BA%90%E7%BB%84 "管理资源组")
> - [管理资源消耗超出预期的查询 ](https://docs.pingcap.com/zh/tidb/stable/tidb-resource-control#%E7%AE%A1%E7%90%86%E8%B5%84%E6%BA%90%E6%B6%88%E8%80%97%E8%B6%85%E5%87%BA%E9%A2%84%E6%9C%9F%E7%9A%84%E6%9F%A5%E8%AF%A2-runaway-queries "管理资源消耗超出预期的查询 ")

## 2.1 Quota对SQL执行的影响

![image](/images/image-20240131151704-hbb230t.png)

![image](/images/image-20240131151408-mo7lzuv.png)

看截图可以发现，一个范围查询的SQL在没做任何限制时，执行时间是4.5s，所需RU是14k。当将session的资源组改成`rg_500`​(`RU_PER_SEC`​为`500`​)后，执行时间变成了`27.7s`，实打实的可以做到削峰效果。

```sql
mysql> select * from information_schema.RESOURCE_GROUPS;
+-------------------+------------+----------+-----------+-------------+------------+
| NAME              | RU_PER_SEC | PRIORITY | BURSTABLE | QUERY_LIMIT | BACKGROUND |
+-------------------+------------+----------+-----------+-------------+------------+
| default           | UNLIMITED  | MEDIUM   | YES       | NULL        | NULL       |
| rg_500            | 500        | MEDIUM   | NO        | NULL        | NULL       |
+-------------------+------------+----------+-----------+-------------+------------+
```

## 2.2 ​`QUERY_LIMIT` 参数设置

> `QUERY_LIMIT`​是自动识别，DBA不用干预，只要用户绑定了`资源组`，就会自动限制。

```sql
-- 查看当前的资源组
select * from information_schema.RESOURCE_GROUPS;

-- 为tableau-user用户创建资源组，执行时间超过60s即，自动KILL
CREATE RESOURCE GROUP IF NOT EXISTS rg_for_tableau RU_PER_SEC = 500 QUERY_LIMIT=(EXEC_ELAPSED='60s', ACTION=KILL, WATCH=SIMILAR DURATION='10m');

-- 为job用户创造资源组，执行时间超过60s，即将优先级调整为最低
CREATE RESOURCE GROUP IF NOT EXISTS rg_for_job RU_PER_SEC = 500 QUERY_LIMIT=(EXEC_ELAPSED='60s', ACTION=COOLDOWN, WATCH=SIMILAR DURATION='10m');

-- 查看runaway_query
select * from mysql.tidb_runaway_queries limit 1;
```

## 2.3 ​`QUERY WATCH` 语句说明

> `QUERY WATCH`​​是被动识别，DBA需要主动对特定的SQL来进行限制。使用场景是，当某个OLTP用户突发出现了慢查询，可以手动将其加到`QUERY WATCH`里，防止影响集群性能。

```sql
QUERY WATCH ADD RESOURCE GROUP rg1 ACTION KILL SQL TEXT SIMILAR TO 'select * from test.t2';

QUERY WATCH ADD RESOURCE GROUP rg1 ACTION KILL SQL DIGEST 'd08bc323a934c39dc41948b0a073725be3398479b6fa4f6dd1db2a9b115f7f57';
```

‍

## 2.4 管理超时语句

```sql
select * from mysql.tidb_runaway_queries limit 1\G
select * from information_schema.runaway_watches

```

![image](/images/image-20240205112404-49gyl0t.png)

‍

[^1]: # TiDB 7.1 资源管控验证测试

    ---

    - [https://tidb.net/blog/9cd7dcb3](https://tidb.net/blog/9cd7dcb3)
    - 本文章的重点在通过实验探索资源管控的一些细节表现，详细来讲就是：TiDB的流控能力和TiKV的调度能力。
    - 2024-01-29 16:48:39

    ---

    # 〇、背景

    我们线上使用环境和李文杰大佬比较类似，我这里就不赘述了，大家可以看[专栏 - TiDB v7.1.0 跨业务系统多租户解决方案 | TiDB 社区](https://tidb.net/blog/2ce19df3)，这里比较清晰的介绍了7.1的资源管控原理和实践验证。

    本文章的重点在通过实验探索资源管控的一些细节表现，详细来讲就是：TiDB的流控能力和TiKV的调度能力。

    - **TiDB流控能力**：是看在tidb-server资源不足的情况，是否能正确按照Quota限制特定用户的使用资源。
    - **TiKV调度能力**：是看在TiKV资源不足时候，能否优先响应高优先级的资源组请求，以及和当前tidb-server的优先级的区别。

    # 一、测试环境准备

    ## 创建用户及资源组

    ```sql
    CREATE RESOURCE GROUP IF NOT EXISTS rg_5000 RU_PER_SEC=5000;
    CREATE RESOURCE GROUP IF NOT EXISTS rg_5000_high RU_PER_SEC=5000 PRIORITY = HIGH;

    CREATE RESOURCE GROUP IF NOT EXISTS rg_3000  RU_PER_SEC = 3000;
    CREATE RESOURCE GROUP IF NOT EXISTS rg_3000_burstable  RU_PER_SEC = 3000 BURSTABLE;

    CREATE RESOURCE GROUP IF NOT EXISTS rg_30000_high RU_PER_SEC=30000 PRIORITY = HIGH;
    CREATE RESOURCE GROUP IF NOT EXISTS rg_30000_low RU_PER_SEC=30000 PRIORITY = LOW;

    CREATE USER 'usr_rg_5000'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_5000;
    GRANT ALL ON *.* TO 'usr_rg_5000'@'%';

    CREATE USER 'usr_rg_5000_high'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_5000_high;
    GRANT ALL ON *.* TO 'usr_rg_5000_high'@'%';

    CREATE USER 'usr_rg_3000'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_3000;
    GRANT ALL ON *.* TO 'usr_rg_3000'@'%';

    CREATE USER 'usr_rg_3000_burstable'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_3000_burstable;
    GRANT ALL ON *.* TO 'usr_rg_3000_burstable'@'%';

    CREATE USER 'usr_rg_30k_high'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_30000_high;
    GRANT ALL ON *.* TO 'usr_rg_30k_high'@'%';

    CREATE USER 'usr_rg_30k_low'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_30000_low;
    GRANT ALL ON *.* TO 'usr_rg_30k_low'@'%';
    ```
    ## 准备测试数据

    ```
    tiup-bench tpcc prepare --warehouses 100 -D tpcc_test --dropdata -H 172.18.x.x -U usr_rg_3000 -p 123 -P 4000 -T 50
    tiup-bench tpcc prepare --warehouses 100 -D tpcc_test2 --dropdata -H 172.18.x.x -U usr_rg_3000 -p 123 -P 4000 -T 50
    ```
    # 二、测评方案

    ## 2.1 TiDB流控测评

    **测试目标：**

    - 不同资源组连到同一个TiDB上，测试不同资源组之间的隔离性
    - 同一个用户连到不同TiDB上，测试同一用户的Quota是否共用
    - 同一资源组不同用户，测试同一资源组的Quota是否共用

    ### 2.1.1 不同资源组的隔离性

    ```bash
    #! /bin/bash

    # 1. 使用usr_rg_3000_burstable用户作为测试的背景噪音，令TiDB的CPU尽可能高
    echo "$(date +"%F %T"): start bench use usr_rg_3000_burstable for 2h"
    nohup tiup-bench tpcc run -D tpcc_test2 --host 172.18.x.x -U usr_rg_3000_burstable -p 123 -P 4000 -T 50 --time 2h  >usr_rg_3000_burstable.log &

    # 2. 5-35min. 3000 for 30m (后续每隔5min启动一个测试用户进行压测)
    sleep 300
    echo "$(date +"%F %T"): start bench use usr_rg_3000 for 30m"
    nohup tiup-bench tpcc run -D tpcc_test2 --host 172.18.x.x -U usr_rg_3000 -p 123 -P 4000 -T 50 --time 30m  >usr_rg_3000.log &

    # 3. 10-45min. 5000 for 30m
    sleep 300
    echo "$(date +"%F %T"): start bench use usr_rg_5000 for 30m"
    nohup tiup-bench tpcc run -D tpcc_test2 --host 172.18.x.x -U usr_rg_5000 -p 123 -P 4000 -T 50 --time 30m  >usr_rg_5000.log &

    # 4. 15-20min. 5000 for 5m
    sleep 300
    echo "$(date +"%F %T"): start bench use usr_rg_5000 for 5m"
    nohup tiup-bench tpcc run -D tpcc_test2 --host 172.18.x.x -U usr_rg_5000 -p 123 -P 4000 -T 50 --time 5m  >usr_rg_5000-2.log &

    #5. 25-55min. 3000 high for 30m
    sleep 300
    echo "$(date +"%F %T"): start bench use usr_rg_3000_high for 30m"
    nohup tiup-bench tpcc run -D tpcc_test2 --host 172.18.x.x -U usr_rg_3000_high -p 123 -P 4000 -T 50 --time 30m  >usr_rg_3000_high.log &

    # 6. 30-35min. 5000 for 5m
    sleep 300
    echo "$(date +"%F %T"): start bench use usr_rg_5000 for 5m"
    nohup tiup-bench tpcc run -D tpcc_test2 --host 172.18.x.x -U usr_rg_5000 -p 123 -P 4000 -T 50 --time 5m  >usr_rg_5000-2.log &
    ```
    **测试结果：**

    **时序图**

    ﻿![](/images/unnamed-1688571691557-20240129164839-m6hx7mh.png)﻿﻿

    **测试结果**

    ﻿![](/images/image-1686991136296-20240129164839-ybxsc8n.png)﻿﻿

    **结果解析**

    1. **阶段1：** 由于只有`<span data-slate-string="true">usr_rg_3000_burstable</span>`​​一个用户在使用集群，虽然Quota设置为3k，但因为设置了`<span data-slate-string="true">BURSTABLE</span>`可以跑到22k
    2. **阶段2-4：** 并发一直在增大，TiDB的负载在逐渐增加，`<span data-slate-string="true">usr_rg_3000_burstable</span>`的流控曲线(黄色曲线)也越来越低，从22k、7.5k、6k逐步降低至4k
    3. **阶段4：** 虽然使用`<span data-slate-string="true">usr_rg_5000</span>`用户新增了一个TPCC压测进程，但是总的资源消耗不变，还是5k。
    4. **阶段5：** 随着`<span data-slate-string="true">usr_rg_5000</span>`​​一个压测进程结束，`<span data-slate-string="true">usr_rg_3000_burstable</span>`​​的资源从4k增加到5k(不过`<span data-slate-string="true">usr_rg_5000</span>`总的资源消耗略有下降，从5k下降至4.8k，可能是TiDB压力太大导致的)
    5. **阶段6：** 继续使用 `<span data-slate-string="true">usr_rg_5000</span>`​​ 用户新增了一个TPCC压测进程， 这一场景其实和阶段4比较类似，不过新增了`<span data-slate-string="true">usr_rg_3000_high</span>`资源组的压测进程，此时TiDB-Server的压力是最大的，几个资源组的曲线都略有波动，不过波动不大
    6. **阶段7-10：** 随着其他资源组的压测进程逐渐结束，TiDB的负载在逐渐降低，`<span data-slate-string="true">usr_rg_3000_burstable</span>`的流控曲线(黄色曲线)也越来越高，逐步回升到24k。

    由此来看，TiDB-Server层的流控还是比较符合预期的，当负载压力小的时候，允许部分用户超额使用资源，当负载压力大的时候，又能保证其他用户的Quota正常。

    ### 2.1.2 同一用户不同 tidb-server

    **测试命令**

    ```bash
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_3000 -p 123 -P 4000 -T 50 --time 5m  >usr_rg_3000.log.1 &
    sleep 60;
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_3000 -p 123 -P 14000 -T 50 --time 5m  >usr_rg_3000.log.2  &
    ```
    **测试结果**

    ﻿![2023-07-04-22-56-13-image.png](/images/2023-07-04-22-56-13-image-1688572062362-20240129164839-fw08k2o.png)﻿﻿

    ﻿![2023-07-04-23-04-14-image.png](/images/2023-07-04-23-04-14-image-1688572088388-20240129164839-xffrmmf.png)﻿﻿

    **结果解析**

    > - 观察RU使用曲线：在第二个压测进程启动后，资源使用会短时间高于Quota；当第一个压测进程结束后，资源使用会短时间低于Quota；不过很快就会回归正常Quota。
    > - 观察tidb-sever的CPU曲线：当只有一个压测进程在跑时候，单个tidb-server的CPU是正常使用的，当两个压测进程共同跑时候，两个tidb-server会平均分配负载，达到负载均衡的状态，更合理使用资源。
    >

    ### 2.1.3 不同用户同一资源组

    **压测命令**

    ```sql
    CREATE USER 'usr_rg_3000_2'@'%' IDENTIFIED BY '123' RESOURCE GROUP rg_3000;
    grant all on *.* to 'usr_rg_3000_2'@'%';
    ```
    ```bash
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_3000 -p 123 -P 4000 -T 50 --time 5m  >usr_rg_3000.log.1 &
    sleep 60;
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_3000_2 -p 123 -P 14000 -T 50 --time 5m  >usr_rg_3000.log.2  &
    ```
    **压测结果**

    ﻿![2023-07-04-23-11-01-image.png](/images/2023-07-04-23-11-01-image-1688572106581-20240129164839-2bfxkjl.png)﻿﻿

    ﻿![2023-07-04-23-12-34-image.png](/images/2023-07-04-23-12-34-image-1688572115316-20240129164839-v7e2qod.png)﻿﻿

    **结果解析**

    > 通过监控曲线，可以看到同一资源组的两个不同用户，和同一用户两个不同压测进程的曲线是基本一致的，说明同一资源组内的不同用户是共享Quota的。
    >

    ### 2.1.4 总结

    因为同一资源组内不同用户是共享Quota的，所以个人理解的TiDB的流控最佳实践为：

    > - 对所有资源组都设置`BURSTABLE`属性，这样才能提高TiDB-Server的资源利用率。
    > - 针对OLAP场景的用户，可以设置一个较小的Quota，当资源紧张时候，让它们尽可能小的占用资源，不影响OLTP的查询。
    >

    ## 2.2 TiKV调度能力测试

    > 由于2.1的测试案例，只有一个TiDB-Server实例，最终的TiKV压力并不大，看不出来TiKV层的优先级调度能力。使用`<span data-slate-string="true">tiup cluster edit-config</span>`​将tikv-server配置修改为`<span data-slate-string="true">resource_control.cpu_quota： 400%</span>`，降低TiKV的CPU资源。
    >

    通过`<span data-slate-string="true">instance.tidb_force_priority</span>`来对特定TiDB-Server上的查询来设置优先级，测试一下通过TiDB-Server隔离，和通过资源组来设置的优先级有什么区别。

    ```sql
    mysql> show config where name like '%tidb_force_priority%';
    +------+------------------+------------------------------+---------------+
    | Type | Instance         | Name                         | Value         |
    +------+------------------+------------------------------+---------------+
    | tidb | 172.18.9.4:4000  | instance.tidb_force_priority | HIGH_PRIORITY |
    | tidb | 172.18.9.4:14000 | instance.tidb_force_priority | LOW_PRIORITY  |
    +------+------------------+------------------------------+---------------+
    2 rows in set (0.01 sec)
    ```
    测试案例包括：

    - 资源组PRIORITY不同，TiDB的PRIORITY相同
    - 资源组PRIORITY相同，TiDB的PRIORITY不同
    - 高PRIORIT的资源组连接低PRIORITY的TiDB vs. 低PRIORIT的资源组连接高PRIORITY的TiDB

    ### 2.2.1 资源组PRIORITY不同，TiDB的PRIORITY相同

    > 为使TiKV的CPU达到瓶颈，使用大Quota的资源组来进行测试
    >

    ```bash
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_30k_low -p 123 -P 4000 -T 100 --time 5m &
    sleep 120;
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_30k_high -p 123 -P 4000 -T 100 --time 5m  &
    ```
    ﻿![2023-07-05-23-14-24-image.png](/images/2023-07-05-23-14-24-image-1688572137093-20240129164839-aqnulkg.png)﻿﻿

    ### 2.2.2 资源组PRIORITY相同，TiDB的PRIORITY不同

    ```bash
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_30k_low -p 123 -P 4000 -T 100 --time 5m &
    sleep 120;
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_30k_low -p 123 -P 14000 -T 100 --time 5m  &
    ```
    ﻿![image.png](/images/image-1688572546229-20240129164839-khvviqm.png)﻿﻿

    ﻿![2023-07-05-23-21-59-image.png](/images/2023-07-05-23-21-59-image-1688572145981-20240129164839-rpwlj0f.png)﻿﻿

    ﻿![2023-07-05-23-25-59-image.png](/images/2023-07-05-23-25-59-image-1688572165077-20240129164839-vueyx31.png)﻿﻿

    ### 2.2.3 高PRIORIT的资源组连接低PRIORITY的TiDB vs. 低PRIORIT的资源组连接高PRIORITY的TiDB

    ```bash
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_30k_low -p 123 -P 4000 -T 100 --time 5m &
    sleep 120;
    nohup tiup-bench tpcc run -D tpcc_test --host 172.18.9.4 -U usr_rg_30k_high -p 123 -P 14000 -T 100 --time 5m  &
    ```
    ﻿![2023-07-05-23-34-56-image.png](/images/2023-07-05-23-34-56-image-1688572172166-20240129164839-c9xhb6n.png)﻿﻿

    ﻿![2023-07-05-23-35-29-image.png](/images/2023-07-05-23-35-29-image-1688572182822-20240129164839-4mh3hhn.png)﻿﻿

    ﻿![2023-07-05-23-35-47-image.png](/images/2023-07-05-23-35-47-image-1688572190558-20240129164839-sagi5d2.png)﻿﻿

    ### 2.2.4 总结

    > 综合三次测试，可以发现不管是资源组优先级还是tidb-server的优先级，在TiKV层都是同样的处理，其调度能力并不能按照预期体现。
    >

    ‍


[^2]: # TiDB 6.5升级7.5调研

    # 新功能调研

    Release Note:

    - [https://docs.pingcap.com/zh/tidb/stable/release-6.6.0](https://docs.pingcap.com/zh/tidb/stable/release-6.6.0)
    - [https://docs.pingcap.com/zh/tidb/stable/release-7.0.0](https://docs.pingcap.com/zh/tidb/stable/release-7.0.0)
    - [https://docs.pingcap.com/zh/tidb/dev/release-7.1.0](https://docs.pingcap.com/zh/tidb/dev/release-7.1.0)
    - [https://docs.pingcap.com/zh/tidb/stable/release-7.5.0](https://docs.pingcap.com/zh/tidb/stable/release-7.5.0)

    杀手特性：

    - **TiFlash延时物化功能GA：**  查询带Where的大表性能会提高很多。相关参数 [tidb_opt_enable_late_materialization](https://docs.pingcap.com/zh/tidb/dev/system-variables#tidb_opt_enable_late_materialization-%E4%BB%8E-v700-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)
    - **资源管控GA：**  资源管控在7.5的能力得到了极大的提升，支持按照用户、session、statement三个维度对SQL进行限制。**还对自动识别并阻断慢查询**，也支持对tiflash进行管控。 [用户文档](https://docs.pingcap.com/zh/tidb/dev/tidb-resource-control)
    - **优化统计信息缓存加载策略：**  可以加快统计信息加载速度，并且可以设置统计信息加载之前不对外提供服务。相关参数[lite-init-stats](https://docs.pingcap.com/zh/tidb/dev/tidb-configuration-file#lite-init-stats-%E4%BB%8E-v710-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)，[force-init-stats](https://docs.pingcap.com/zh/tidb/dev/tidb-configuration-file#force-init-stats-%E4%BB%8E-v710-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)
    - **兼容性增强：**  支持外键、支持 MySQL 兼容的多值索引 (Multi-Valued Indexes)、支持REORGANIZE PARTITION语法、对MySQL 8.0的兼容性更强了。
    - **TiFlash支持**​**[存储计算分离和 S3 共享存储](https://docs.pingcap.com/zh/tidb/stable/tiflash-disaggregated-and-s3)**​ **：** 可以将TiFlash数据存储到S3中，这**样所有的表都可以有TiFlash副本，可以让OLAP的流量只访问TiFlash，和OLTP彻底隔离。**
    - **后台任务管控能力增强：** 可以指定tidb-server机器来执行ddl和import任务，防止后台任务影响OLTP查询。DDL支持暂停和恢复功能。
    - **DM增加**​**[增量数据校验功能](https://docs.pingcap.com/zh/tidb/dev/dm-continuous-data-validation)**​ **：** 可以实时检查DM同步任务是否正常

    其他优化：

    - **支持自适应副本读取缓解读热点:**  减少热点查询的长尾延时，提高吞吐量。相关参数 [tidb_load_based_replica_read_threshold](https://docs.pingcap.com/zh/tidb/dev/system-variables#tidb_load_based_replica_read_threshold-%E4%BB%8E-v700-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)
    - **[store-limit-version](https://docs.pingcap.com/zh/tidb/dev/pd-configuration-file#store-limit-version-%E4%BB%8E-v710-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)**​ **：** 可以根据TiKV负载动态调整region迁移速度，不需要手动调整，可以加快日常将数据迁移到HDD节点的速度。**不过还是实验特性，不建议开启**
    - **TiCDC性能优化：** 修复在上游执行rename table时可能导致changefeed报错的BUG，支持输出变更到S3存储中
    - **DDL 支持分布式并行执行框架：** 可以多节点执行同一DDL，增加DDL执行速度。
    - **Partitioned Raft KV：** 每个region由单独的rocksdb来管理，**可以极大的加快扩缩容速度**，以及热点读写隔离。不过不支持动态修改，只能在创建TiDB集群时指定，不建议开启。
    - **TiKV 支持自动生成空的日志文件用于日志回收：**  [raft-engine.prefill-for-recycle](https://docs.pingcap.com/zh/tidb/stable/tikv-configuration-file#prefill-for-recycle-%E4%BB%8E-v700-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)
    - **Fast Online DDL兼容性更好**，支持更多场景，兼容PITR。
    - **BR 支持备份和恢复统计信息**
    - **TiDB Dashboard 性能分析支持 TiKV 堆内存分析**
    - **​`IMPORT INTO`​**​​ **SQL 语句成为正式功能 (GA)：** 该语句集成了 TiDB Lightning 物理导入模式的能力，可以将 CSV、SQL 和 PARQUET 等格式的数据快速导入到 TiDB 的一张***空表***中，只能适应于新表的导入。[https://docs.pingcap.com/zh/tidb/dev/sql-statement-import-into](https://docs.pingcap.com/zh/tidb/dev/sql-statement-import-into)
    - **优化 ANALYZE 流程：** 引入 [tidb_build_sampling_stats_concurrency](https://docs.pingcap.com/zh/tidb/dev/system-variables#tidb_build_sampling_stats_concurrency-%E4%BB%8E-v750-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5) 精细化控制 ANALYZE 并发度，减少资源消耗。同时优化 ANALYZE 的内存使用，通过复用部分中间结果，减少内存分配，避免频繁 GC
    - 对分区表的常用操作基本完全兼容

      > - 支持普通表 <==> 分区表之间相互转换
      > - 支持`REORGANIZE PARTITION`语法
      >

    ## 启用哪些功能？

    - **资源管控：**​**[用户文档](https://docs.pingcap.com/zh/tidb/dev/tidb-resource-control)**​ **，** 大部分用户不做资源管控，只控制一些特定job用户、以及dms-user的Quota
    - **开启TiFlash存储计算分离和 S3 共享存储：**​[https://docs.pingcap.com/zh/tidb/stable/tiflash-disaggregated-and-s3](https://docs.pingcap.com/zh/tidb/stable/tiflash-disaggregated-and-s3)
    - tidb-server:

      - **[lite-init-stats](https://docs.pingcap.com/zh/tidb/dev/tidb-configuration-file#lite-init-stats-%E4%BB%8E-v710-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)**
      - **[force-init-stats](https://docs.pingcap.com/zh/tidb/dev/tidb-configuration-file#force-init-stats-%E4%BB%8E-v710-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)**
      - **[temp-dir](https://docs.pingcap.com/zh/tidb/stable/tidb-configuration-file#temp-dir-%E4%BB%8E-v630-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)**​ **:**  默认是`/tmp/tidb`​目录在系统盘，读写性能和磁盘大小都有限，调整到`data-dir`中
      - **[tidb\_enable\_ddl](https://docs.pingcap.com/zh/tidb/stable/tidb-configuration-file#tidb_enable_ddl)**​ **：** 将OLTP节点的值设置为false，禁止在OLTP节点上执行DDL语句
      - **[`tidb\_enable\_dist\_task`](https://docs.pingcap.com/zh/tidb/dev/system-variables#tidb_enable_dist_task-%E4%BB%8E-v710-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)**​ **：** 可以多节点执行同一DDL，增加DDL执行速度。
      - **​`tidb_service_scope：`​** 限制tidb-server是否执行后台任务(只能在升级后，在olap tidb-server上设置)​​
      - **[tidb\_enable\_async\_merge\_global\_stats](https://docs.pingcap.com/zh/tidb/dev/system-variables#tidb_enable_async_merge_global_stats-%E4%BB%8E-v750-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)**：用于设置 TiDB 使用异步方式合并统计信息，以避免 OOM 问题，对分区表生效。解决新增分区后，新分区不会自动analyze的BUG
    - **tikv-server**

      - [auto-adjust-pool-size](https://docs.pingcap.com/zh/tidb/stable/tikv-configuration-file#auto-adjust-pool-size-%E4%BB%8E-v630-%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E5%BC%95%E5%85%A5)
    - **tiflash-server：** 开启存算分离架构，操作文档： [https://docs.pingcap.com/zh/tidb/stable/tiflash-disaggregated-and-s3](https://docs.pingcap.com/zh/tidb/stable/tiflash-disaggregated-and-s3)  
      开启TiFlash存算分离架构，需要将现有TiFlash节点释放掉，所以需要找一个低峰期，所有表的tiflash副本都设置为0。(不会导致查询失败，但是某些SQL的查询耗时可能会变大)
    - `Grafana Dashboard`更新
    - `Prometheus Alert`规则更新对比

    ‍

    # 调研文档

    - [TiDB 7.5资源管控能力测试](#20240129170139-cd834kj)
    - TiFlash存算分离架构测试[^3]

    # 性能提升

    |测试案例|6.5|7.5|
    | ----------| ------| -------------------------------------|
    |`ANALYZE TABLE`|`3 min 18.68 sec`|`1 min 26.69 sec`|
    |`br restore`||`635 MB/s`|
    |`tidb-lightning`|||
    |`set tiflash replica`||- local tiflash: <br />- tiflash on s3:|
    |`read on tiflash`||- local tiflash: <br />- tiflash on s3:|
    ||||
    ||||
    ||||
    ||||
    ||||

    ‍


[^3]: # TiFlash存算分离架构测试

    > 已确认问题：
    >
    > 1. 官方不建议设置太多的TiFlash副本，担心PD中`Placement Rule`​​太多，影响PD性能。**~~已经验证修改~~**​**~~​`default`​~~**​​**~~策略不可行：~~** TiFlash修改默认Placement Rule方案测试[^4]
    > 2. 默认情况下对OSS的兼容性还有待调查： OSS兼容性测试[^5]
    > 3. 当前TiFlash挂掉后，只会从TiKV获取数据，不能从S3获取存量数据。也就是说，一旦TiFlash节点挂掉没办法起来，在重做时候，新节点会全量把所有数据都拉一遍，历史信息也会被重新上传到S3上，存在长时间TiFlash不可用的情况，所以官方建议至少设置两个`Write Node`​，两个副本。  
    >    PS：如果设置两个副本，在S3上也会存两份，会存在空间浪费。  
    >    PPS：针对`盈米`​而言，这个问题不大，我们的`Write Node`​到时候会用云盘，数据不会丢。只要IP不变，就不会重做，也就不需要重传数据  
    >         但是这种情况下，**<u>任何访问 TiFlash 的 SQL 都会报错，会影响可用性。同时在升级集群版本时候，也没办法做到平滑升级。</u>**
    >

    # 当前现状

    如下排查所示，当前总共有`12k`​的`表/分区`​，排除掉`kyc_feature_store_offline`​这个库之后，有`7705`​个`表/分区`​。而当前的`Placement Rule`​个数有`6189`​个(包含`kyc_feature_store_offline`​)，如果减去`kyc_feature_store_offline`​的表后，只有`1752`个。

    > 需要确认，在on_dw_ssd下的分区表，会产生多个`Placement Rule`还是只有一个。
    >

    ```sql
    mysql> select count(1) from information_schema.partitions where TABLE_SCHEMA not in ('mysql', 'information_schema', 'METRICS_SCHEMA', 'PERFORMANCE_SCHEMA');
    +----------+
    | count(1) |
    +----------+
    |    12133 |
    +----------+
    1 row in set (7.29 sec)

    mysql> select TABLE_SCHEMA, count(1) from information_schema.partitions where TABLE_SCHEMA not in ('mysql', 'information_schema', 'METRICS_SCHEMA', 'PERFORMANCE_SCHEMA') group by TABLE_SCHEMA order by count(1) desc limit 10;
    +---------------------------+----------+
    | TABLE_SCHEMA              | count(1) |
    +---------------------------+----------+
    | kyc_feature_store_offline |     4437 |
    | ying99_fundtxn            |     1221 |
    | yingmi_dw                 |     1122 |
    | wechatbackend             |      604 |
    | test                      |      443 |
    | ying99_settlement         |      218 |
    | ying99_isac               |      208 |
    | ying99_qieman             |      163 |
    | ying99_pixiu              |      145 |
    | ying99_scrm               |      129 |
    +---------------------------+----------+
    10 rows in set (0.25 sec)
    ```
    # 测试案例

    购买两个机器，一个作为write_node，一个作为`compute_node`，在扩容后，

    1. **Q：通过修改**​**​`default`​**​**策略，是否可以让所有表都有tiflash副本？**   
       **A：** 不可行，索引上的`Region`​​​​​不能设置TiFlash副本，会导致TiFlash报错。详细测试见： TiFlash修改默认Placement Rule方案测试[^4]
    2. **Q:**  **​`write_node`​**​**节点的磁盘是否能有限制？**   
       **A：** 通过监控可以发现`local`​​盘数据量，即便是在迁移期间也一直只有`4 MB`​​。在OSS上的内容在初始上传后有`96 GB`​​，不过在经过一段时间稳定后只有`55 GB`​​。通过这里，也就可以发现`TiFlash on S3`​​架构现阶段时将`S3`​​当成普通的磁盘来使用的，是有多少个write_node节点，在S3上就有多少个子目录，每个目录对应一个`write_node`​​节点。日常的`Merge/Split/Add/Delete`​​操作，都需要直接读写`S3`​​中的数据。  
       ​![image](/images/image-20240202141415-vgefe5t.png)

       ![image](/images/image-20240202141457-pkq9ke7.png)
    3. **在**​**​`set tiflash replica 0`​**​**取消**​**​`Tiflash`​**​**副本后，OSS上数据会不会被清理掉？**   
       当执行`set tiflash replica 0`​​后，`tiflash_replica`​​系统表及`config placement-rules show`​​都立刻看不到之前设置的表，但是tiflash副本是异步删除的，即便tiflash write_node节点状态为`Tombstone`​​后，数据依旧不会马上被清理。正常来说在执行`tiup cluster prune`​​时候应该会把`tiflash`​​的数据给删掉，但是当前只会删除本地的`数据目录`​​，而`OSS`上数据会一直存在，不会自动删除。
    4. 在`增加TiFlash副本`时，对OSS操作的冲击力？  

       ![image](/images/image-20240202173606-636yc3t.png)

       如上图所示，对OSS操作都很低，影响很小，OPS只有几十。

       |类型|OPS|带宽|
       | ------| ----: | ------------: |
       |上传|30|8 `MB/s`|
       |下载|13|38 `MB/s`|

       在用`br restore`​​时候，恢复速度会大幅上升，`10:52 ~ 11:23`​​数据量从`45.2 GB`​​上升到`83.7 GB`​​，速度是 `20.7 MB/s`​​，OSS上数据从`56.191GB`​​上升到`102.619GB`​​, 速度是`24.9 MB/s`​​差别不大。`TiKV`​​数据量是`156 GB`​​，平均速度是`83.9 MB/s`。

       ![image](/images/image-20240204113857-shm7rdn.png)
    5. 在OSS上的平均文件大小是 `79.2 GB * 1024 / 125342 = 0.64 MB = 640 KB`​​。(本地盘情况，平均文件大小是`1.6 MB`​​)  
       ​![image](/images/image-20240202225227-xmbvlqd.png)

       ‍
    6. 在计算时，**​`write_node/compute_node`​**​**的资源使用比例是多大？**   
       Write Node 节点在计算时的资源使用量很少，但是为了维护 TiFlash region 状态，自身的 CPU 和 内存都不能太低，尤其是内存，和数据量基本是成正比关系。
    7. `TiFlash迁移速度`​​：  
       TiDB上`ying99_fundtxn.fund_order`​​在`TiKV`​​上数据量是`220G`​​，经过`15:38 ~ 17:28`​​共上传 `77G`​​ TiFlash数据，平均是`7.6 MB/s`​​，最终是`56 GB`​​，折合TiKV上数据，速率是`34 MB/s`​​，也就是`2 GB/min, 120 GB/h`。
    8. 在`compute_node`​节点故障后，只`write_node`​节点不能对外提供服务，会报错：`ERROR 1105 (HY000): tiflash_compute node is unavailable`  
       PS： write Node 故障后，一样会导致查询报错。
    9. 兼容性测试：

       1. `在br restore`​​恢复库表时候，`TiFlash`节点会自动将数据增加副本
    10. TiFlash存算分离架构的性能如何？  
        ​`写速率`​​：`21:47`​​开始同步，`23:39`​​结束同步，总共迁移`45 GB`​​数据，原始表为`220G`

    |测试案例|调研结果|结论|
    | ---------------------------------------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------------------------------------------------------------------------------------------------------------------------------------------|
    |通过修改default策略，是否可以让所有表都有tiflash副本？|不可行，原因是索引上的Region不能设置TiFlash副本，一旦设置所有region都添加tiflash副本，会导致TiFlash报错没办法启动。|必须逐个表/database来添加tiflash副本，新增表默认是没有tiflash副本的|
    |存算分离架构对OSS兼容性测试|当前TiFlash对OSS的支持还不够完美，在默认配置参数下，会有报错导致没办法在merge或者split后删除历史数据，导致一直在重试。需要设置参数：<br />`# 默认值是1，通过S3的Lifecycle方式自动清理过期数据。设置为2，可以调整为原始的Scan模式，通过ListObject方式来找到过期数据并删除。profiles.default.remote_gc_method: 2`<br />|扩容时候，write_node配置中增加profiles.default.remote_gc_method: 2|
    |write_node节点的磁盘配置？|- 通过监控可以发现local盘数据量，即便是在迁移期间也一直只有4 MB。在OSS上的内容在初始上传后有96 GB，不过在经过一段时间稳定后只有55 GB。<br />- 通过这里，也就可以发现TiFlash on S3架构现阶段时将S3当成普通的磁盘来使用的，是有多少个write_node节点，在S3上就有多少个子目录，每个目录对应一个write_node节点。日常的Merge/Split/Add/Delete操作，都需要直接读写S3中的数据。<br />|write_node节点的配置可以很低，预计4C16G + 20G SSD就够了|
    |缩容tiflash后，OSS上数据会不会被清理掉？|当执行set tiflash replica 0后，tiflash_replica系统表及config placement-rules show都立刻看不到之前设置的表，但是由于tiflash副本是异步删除的，即便tiflash write_node节点状态为Tombstone后，数据依旧不会马上被清理，还在OSS中。<br />正常来说在执行tiup cluster prune时候应该会把tiflash的数据给删掉，但是当前只会删除本地的数据目录，而OSS上的数据只能等待异步清理完成后，才会释放(可能持续很长时间)。|只缩容一个tiflash write_node时，不需要手动清理OSS上数据。只有所有tiflash节点都需要缩容时(比如要切换回旧模式时)，才需要手动清理OSS上文件夹。|
    |在增加TiFlash副本时，对OSS操作的冲击力？|![image](/images/image-20240207144728-cfiifeu.png)<br />如上图所示，对OSS操作都很低，影响很小，OPS只有几十，上传/下载带宽也很小。<br />|对OSS冲击力很小，不需要额外关注|
    |TiFlash迁移速度|**local tiflash:**  <br />16:20开始导入，18:03导入完成，总共是103min，导入后TiFlash总数据量是39G，导入速率是6.3 MB/s，按照TiKV数据量来算是25 MB/s, 87.9 GB/h。<br />- 最终产生的平均文件大小是1.5 MB。<br />**tiflash on s3:**  <br /> *- 09:44开始导入，11:28导入完成，导入后TiFlash总数据量是39G，导入速度是6.8 MB/s。TiKV数据量时156 GB，折合导入速度是25 MB/s, 87.9 GB/h* <br />- 开始：对象总数：72488，对象总大小：73.611GB，平均对象大小为1.4 MB。<br />- 稳定后：对象总数：84692，对象总大小：85.748GB<br />|在同步速度方面，两者速度差不多，单表同步速度大概是  90 GB/h。**需要计算一下大量表一起添加tiflash副本需要的时间**|
    |在计算时，write_node/compute_node的资源使用比例是多大？|<br />|**待测试**|
    |故障测试|在compute_node节点故障后，只write_node节点不能对外提供服务，会报错：ERROR 1105 (HY000): tiflash_compute node is unavailable|<br />|
    |7.5新版本的TiFlash查询效率|走where条件的范围查询：* TiDB 6.5 (两个tiflash节点)： 0.9s* TiDB 7.5 (单个local tiflash节点): 0.36s，性能提升60%。* TiDB 7.5 (存算分离架构，单个compute节点):|**待测试**|

    ‍

    ‍

    # 上线方案

    1. 迁移到sata盘的表，必须增加tiflash副本
    2. 当前的已有tiflash副本的表，需要提前找到，在切换到


[^4]: # TiFlash修改默认Placement Rule方案测试

    1. 导出当前集群的`placement-rules`

       ```shell
       root@perf-asset-tipd-f001:~# tiup ctl:v7.5.0 pd -i
       Starting component `ctl`: /root/.tiup/components/ctl/v7.5.0/ctl pd -i
       » config placement-rules rule-bundle load --out="rules.json"
       ```

    2. 在`PD`默认规则里加上一下的告警规则

       ```json
         {
           "group_id": "tiflash",
           "group_index": 120,
           "group_override":false,
           "rules": [
             {
               "group_id": "tiflash",
               "id": "default",
               "start_key": "",
               "end_key": "",
               "role": "learner",
               "is_witness": false,
               "count": 1,
               "label_constraints": [
                 {
                   "key": "engine",
                   "op": "in",
                   "values": [
                     "tiflash"
                   ]
                 }
               ],
             }
           ]
         }
       ```

    3. 将新的规则导入到`PD`中

       ```shell
       tiup ctl:v7.5.0 pd config placement-rules rule-bundle save --in="rules.json"
       ```

    4. 观察集群：发现这个时候，`TiFlash`​​节点会报错，发生重启。查看日志能发现提示`start_key`​​和`end_key`不对。

       ```log
       [2024/02/01 22:08:56.715 +08:00] [ERROR] [Exception.cpp:91] ["Code: 49, e.displayText() = DB::Exception: Illegal region range, should not happen, start_key=748000000000013CFF9A5F698000000000FF000002010E2B0E30FF00000000FB010E2CFF0E300E310E29FF0EFF290E2B0E2D0E2CFFFF0E2B0E2F0E320E30FFFF0E320000000000FF00F9010E290E290EFF2E0E2DFF0E310E2FFF0E290E31FF000000FF0000000000F7010EFF2B0E290E2A0E31FFFF0E2A0E2A0E2B0E32FFFF00000000000000FF00F7010E2B0E3000FF000000FB010E2C0EFF300E310E29FF0E29FF0E2B0E2D0E2CFF0EFF2B0E2F0E320E30FFFF0E32000000000000FFF900000000000000F8 end_key=748000000000013CFF9A5F698000000000FF000002010E2D0E2CFF00000000FB010E2CFF0E300E310E29FF0EFF290E290E290E2DFFFF0E2E0E2B0E2B0E2EFFFF0E2E0E290E290EFF29FF0E290E290E2AFF0E30FF0000000000FF000000F7010E290EFF290E2A0E31FF0E2DFF0E290E300E32FF00FF00000000000000F7FF010E2B0E290E2A0EFF31FF0E2A0E2A0E2BFF0E2AFF0000000000FF000000F7010E2D0EFF2C00000000FB010EFF2C0E300E310E29FFFF0E290E290E290E2DFFFF0E2E0E2B0E2B0EFF2EFF0E2E0E290E29FF0E29FF0E290E290EFF2A0E30FF00000000FF00000000F7000000FC, e.what() = DB::Exception, Stack trace:\n\n\n       0x8ac3ff1\tDB::Exception::Exception<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) [tiflash+145506289]\n                \tdbms/src/Common/Exception.h:53\n       0x8ac3c05\tDB::RegionRangeKeys::RegionRangeKeys(DB::StringObject<true>&&, DB::StringObject<true>&&) [tiflash+145505285]\n                \tdbms/src/Storages/KVStore/MultiRaft/RegionState.cpp:149\n       0x8ac3121\tDB::RegionState::updateRegionRange() [tiflash+145502497]\n                \tdbms/src/Storages/KVStore/MultiRaft/RegionState.cpp:83\n       0x8ab84d2\tDB::RegionMeta::RegionMeta(metapb::Peer, metapb::Region, raft_serverpb::RaftApplyState) [tiflash+145458386]\n                \tdbms/src/Storages/KVStore/MultiRaft/RegionMeta.cpp:486\n       0x8a22257\tDB::KVStore::genRegionPtr(metapb::Region&&, unsigned long, unsigned long, unsigned long) [tiflash+144843351]\n                \tdbms/src/Storages/KVStore/KVStore.cpp:695\n       0x8a5a9d5\tPreHandleSnapshot [tiflash+145074645]\n                \tdbms/src/Storages/KVStore/FFI/ProxyFFI.cpp:660\n  0x7f167cd8d71c\tproxy_ffi::engine_store_helper_impls::_$LT$impl$u20$proxy_ffi..interfaces..root..DB..EngineStoreServerHelper$GT$::pre_handle_snapshot::hab1c0a0a4ab0e51b [libtiflash_proxy.so+26048284]\n  0x7f167c8b1f2e\tengine_store_ffi::core::forward_raft::snapshot::pre_handle_snapshot_impl::h0f4793d5d00197e2 [libtiflash_proxy.so+20954926]\n  0x7f167d49b266\tyatp::task::future::RawTask$LT$F$GT$::poll::h1973aa5ea2716d33 [libtiflash_proxy.so+33444454]\n  0x7f167f0094eb\t_$LT$yatp..task..future..Runner$u20$as$u20$yatp..pool..runner..Runner$GT$::handle::hb21645385c0bc4a1 [libtiflash_proxy.so+62207211]\n  0x7f167eff9f3c\tstd::sys_common::backtrace::__rust_begin_short_backtrace::h051089b45fd1366c [libtiflash_proxy.so+62144316]\n  0x7f167effa9bc\tcore::ops::function::FnOnce::call_once$u7b$$u7b$vtable.shim$u7d$$u7d$::h97006f1ac1ae8af1 [libtiflash_proxy.so+62147004]\n  0x7f167e6f5075\tstd::sys::unix::thread::Thread::new::thread_start::hd2791a9cabec1fda [libtiflash_proxy.so+52686965]\n                \t/rustc/96ddd32c4bfb1d78f0cd03eb068b1710a8cebeef/library/std/src/sys/unix/thread.rs:108\n  0x7f167b144ac3\t<unknown symbol> [libc.so.6+608963]\n  0x7f167b1d6850\t<unknown symbol> [libc.so.6+1206352]"] [source="DB::RawCppPtr DB::PreHandleSnapshot(DB::EngineStoreServerWrap *, DB::BaseBuffView, uint64_t, DB::SSTViewVec, uint64_t, uint64_t)"] [thread_id=37]
       ```
    5. 根据查了下报错的那个`start_key`​​所在的`region`​​是属于一个索引的，而正常通过`set tiflash replica`​​方式增加的`Placement rule`​​，其`start_key`​和`end_key`都是主表的。

       ```sql
       mysql> select * from information_schema.TIKV_REGION_STATUS where start_key = '748000000000013CFF9A5F698000000000FF000002010E2B0E30FF00000000FB010E2CFF0E300E310E29FF0EFF290E2B0E2D0E2CFFFF0E2B0E2F0E320E30FFFF0E320000000000FF00F9010E290E290EFF2E0E2DFF0E310E2FFF0E290E31FF000000FF0000000000F7010EFF2B0E290E2A0E31FFFF0E2A0E2A0E2B0E32FFFF00000000000000FF00F7010E2B0E3000FF000000FB010E2C0EFF300E310E29FF0E29FF0E2B0E2D0E2CFF0EFF2B0E2F0E320E30FFFF0E32000000000000FFF900000000000000F8' limit 1\G
       *************************** 1. row ***************************
                       REGION_ID: 863149
                       START_KEY: 748000000000013CFF9A5F698000000000FF000002010E2B0E30FF00000000FB010E2CFF0E300E310E29FF0EFF290E2B0E2D0E2CFFFF0E2B0E2F0E320E30FFFF0E320000000000FF00F9010E290E290EFF2E0E2DFF0E310E2FFF0E290E31FF000000FF0000000000F7010EFF2B0E290E2A0E31FFFF0E2A0E2A0E2B0E32FFFF00000000000000FF00F7010E2B0E3000FF000000FB010E2C0EFF300E310E29FF0E29FF0E2B0E2D0E2CFF0EFF2B0E2F0E320E30FFFF0E32000000000000FFF900000000000000F8
                         END_KEY: 748000000000013CFF9A5F698000000000FF000002010E2D0E2CFF00000000FB010E2CFF0E300E310E29FF0EFF290E290E290E2DFFFF0E2E0E2B0E2B0E2EFFFF0E2E0E290E290EFF29FF0E290E290E2AFF0E30FF0000000000FF000000F7010E290EFF290E2A0E31FF0E2DFF0E290E300E32FF00FF00000000000000F7FF010E2B0E290E2A0EFF31FF0E2A0E2A0E2BFF0E2AFF0000000000FF000000F7010E2D0EFF2C00000000FB010EFF2C0E300E310E29FFFF0E290E290E290E2DFFFF0E2E0E2B0E2B0EFF2EFF0E2E0E290E29FF0E29FF0E290E290EFF2A0E30FF00000000FF00000000F7000000FC
                        TABLE_ID: 81038
                         DB_NAME: ying99_fundtxn
                      TABLE_NAME: txn_confirm
                        IS_INDEX: 1
                        INDEX_ID: 2
                      INDEX_NAME: idx_tacode_serialno
                    IS_PARTITION: 1
                    PARTITION_ID: 81050
                  PARTITION_NAME: p201811
                  EPOCH_CONF_VER: 7
                   EPOCH_VERSION: 88794
                   WRITTEN_BYTES: 39
                      READ_BYTES: 0
                APPROXIMATE_SIZE: 53
                APPROXIMATE_KEYS: 189928
         REPLICATIONSTATUS_STATE: NULL
       REPLICATIONSTATUS_STATEID: NULL
       1 row in set (1.49 sec)

       ‍‍```json  -- 正式的某个TiFlash分区产生的`Placement rule`
             {
               "group_id": "tiflash",
               "id": "table-88492-r",
               "index": 120,
               "start_key": "7480000000000159ffac5f720000000000fa",
               "end_key": "7480000000000159ffad00000000000000f8",
               "role": "learner",
               "is_witness": false,
               "count": 1,
               "label_constraints": [
                 {
                   "key": "engine",
                   "op": "in",
                   "values": [
                     "tiflash"
                   ]
                 }
               ],
               "create_timestamp": 1706659758
             }
       ‍‍```

       mysql> select * from information_schema.TIKV_REGION_STATUS where start_key = '748000000000013BFFCA5F720000000000FA' limit 1\G
       *************************** 1. row ***************************
                       REGION_ID: 1066088
                       START_KEY: 748000000000013BFFCA5F720000000000FA
                         END_KEY: 748000000000013BFFCB00000000000000F8
                        TABLE_ID: 80757
                         DB_NAME: ying99_fundtxn
                      TABLE_NAME: fund_order
                        IS_INDEX: 0
                        INDEX_ID: NULL
                      INDEX_NAME: NULL
                    IS_PARTITION: 1
                    PARTITION_ID: 80842
                  PARTITION_NAME: p202412
                  EPOCH_CONF_VER: 6
                   EPOCH_VERSION: 121736
                   WRITTEN_BYTES: 144
                      READ_BYTES: 0
                APPROXIMATE_SIZE: 1
                APPROXIMATE_KEYS: 0
         REPLICATIONSTATUS_STATE: NULL
       REPLICATIONSTATUS_STATEID: NULL
       1 row in set (1.51 sec)
       ```


[^5]: # OSS兼容性测试

    > 当前TiFlash对OSS的支持还不够完美，在默认配置参数下，会有报错导致没办法在merge或者split后删除历史数据，导致一直在重试。需要设置：
    >
    > ```yaml
    > # The method of running GC task on the remote store. 1 - lifecycle, 2 - scan.
    > # 默认值是1，通过S3的Lifecycle方式自动清理过期数据。设置为2，可以调整为原始的Scan模式，通过ListObject方式来找到过期数据并删除。
    > profiles.default.remote_gc_method: 2
    > ```
    >

    ```log
    [2024/02/02 18:36:47.373 +08:00] [WARN] [S3Common.cpp:145] ["tag=AWSErrorMarshaller message=Encountered Unknown AWSError 'NotImplemented': A header you provided implies functionality that is not implemented."] [source=AWSClient] [thread_id=974]
    [2024/02/02 18:36:47.373 +08:00] [ERROR] [S3Common.cpp:145] ["tag=AWSXmlClient message=HTTP response code: 400\nResolved remote host IP address: 100.118.78.2:443\nRequest ID: 65BCC5BFE7447A3130E9E56E\nException name: NotImplemented\nError message: Unable to parse ExceptionName: NotImplemented Message: A header you provided implies functionality that is not implemented.\n7 response headers:\nconnection : close\ncontent-length : 334\ncontent-type : application/xml\ndate : Fri, 02 Feb 2024 10:36:47 GMT\nserver : AliyunOSS\nx-amz-request-id : 65BCC5BFE7447A3130E9E56E\nx-oss-server-time : 0"] [source=AWSClient] [thread_id=974]
    [2024/02/02 18:36:47.374 +08:00] [ERROR] [S3Common.cpp:572] ["S3 PutEmptyObject failed: Unable to parse ExceptionName: NotImplemented Message: A header you provided implies functionality that is not implemented., request_id=65BCC5BFE7447A3130E9E56E bucket=mysql-dts-migrate root=perf-asset-tiflash-data/ key=s1069816/data/t_80772/dmf_2.del"] [source="bucket=mysql-dts-migrate root=perf-asset-tiflash-data/"] [thread_id=974]


    [2024/02/02 18:36:47.396 +08:00] [ERROR] [S3LockService.cpp:136] ["DB Exception: S3 PutEmptyObject failed, bucket=mysql-dts-migrate root=perf-asset-tiflash-data/ key=s1069816/data/t_80772/dmf_2.del s3error=UNKNOWN s3exception_name=NotImplemented s3msg=Unable to parse ExceptionName: NotImplemented Message: A header you provided implies functionality that is not implemented. request_id=65BCC5BFDE10FD3531A4B28E\n\n       0x809e528\tDB::Exception::Exception<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>(int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) [tiflash+134866216]\n                \tdbms/src/Common/Exception.h:53\n       0x808e9ce\tDB::Exception DB::S3::fromS3Error<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>(Aws::S3::S3Error const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) [tiflash+134801870]\n                \tdbms/src/Storages/S3/S3Common.h:57\n       0x808fb28\tDB::S3::uploadEmptyFile(DB::S3::TiFlashS3Client const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int) [tiflash+134806312]\n                \tdbms/src/Storages/S3/S3Common.cpp:584\n       0x89f3cd9\tDB::S3::S3LockService::tryMarkDelete(disaggregated::TryMarkDeleteRequest const*, disaggregated::TryMarkDeleteResponse*) [tiflash+144653529]\n                \tdbms/src/Flash/Disaggregated/S3LockService.cpp:117\n       0x86fa5ea\tDB::FlashService::tryMarkDelete(grpc::ServerContext*, disaggregated::TryMarkDeleteRequest const*, disaggregated::TryMarkDeleteResponse*) [tiflash+141534698]\n                \tdbms/src/Flash/FlashService.cpp:874\n       0x98cb9d7\tgrpc::internal::RpcMethodHandler<tikvpb::Tikv::Service, disaggregated::TryMarkDeleteRequest, disaggregated::TryMarkDeleteResponse, google::protobuf::MessageLite, google::protobuf::MessageLite>::RunHandler(grpc::internal::MethodHandler::HandlerParameter const&) [tiflash+160217559]\n                \tcontrib/grpc/include/grpcpp/impl/codegen/method_handler.h:113\n       0x9242130\tgrpc::Server::SyncRequest::ContinueRunAfterInterception() [tiflash+153362736]\n                \tcontrib/grpc/src/cpp/server/server_cc.cc:433\n       0x9241f61\tgrpc::Server::SyncRequest::Run(std::__1::shared_ptr<grpc::Server::GlobalCallbacks> const&, bool) [tiflash+153362273]\n                \tcontrib/grpc/src/cpp/server/server_cc.cc:421\n       0x9254155\tgrpc::ThreadManager::WorkerThread::WorkerThread(grpc::ThreadManager*)::$_0::__invoke(void*) [tiflash+153436501]\n                \tcontrib/grpc/src/cpp/thread_manager/thread_manager.cc:36\n       0x95ee66a\tgrpc_core::(anonymous namespace)::ThreadInternalsPosix::ThreadInternalsPosix(char const*, void (*)(void*), void*, bool*, grpc_core::Thread::Options const&)::'lambda'(void*)::__invoke(void*) [tiflash+157214314]\n                \tcontrib/grpc/src/core/lib/gprpp/thd_posix.cc:110\n  0x7f89afcecac3\t<unknown symbol> [libc.so.6+608963]\n  0x7f89afd7e850\t<unknown symbol> [libc.so.6+1206352]"] [thread_id=974]
    [2024/02/02 18:36:47.396 +08:00] [ERROR] [S3LockClient.cpp:121] ["meets error, code=13 msg=S3 PutEmptyObject failed, bucket=mysql-dts-migrate root=perf-asset-tiflash-data/ key=s1069816/data/t_80772/dmf_2.del s3error=UNKNOWN s3exception_name=NotImplemented s3msg=Unable to parse ExceptionName: NotImplemented Message: A header you provided implies functionality that is not implemented. request_id=65BCC5BFDE10FD3531A4B28E"] [source="<key=s1069816/data/t_80772/dmf_2,type=MarkDelete>"] [thread_id=966]
    ```
    ‍
