# [Critical bug] v4.0.11 load base split 采样问题，在一定条件下会导致 TiKV Panic

## Issue

[https://github.com/tikv/tikv/issues/9733](https://github.com/tikv/tikv/issues/9733)

load base split 采样问题，在一定条件下会导致 TiKV Panic. 问题现象： TiKV Panic，并且 panic 堆栈有以下类似的错误：

```
 UniformSampler::sample_single: low >= high"] \[backtrace="stack backtrace:
```

workload 存在单个 Region 读请求 QPS 高于 split.qps-threshold（默认3000），在采样请求过程中出现各线程的处理请求数出现倾斜的的情况下会触发；

## Root Cause

在去除重复采样数据后未正确判断空的采样值。

因为 load base split 在 #9256 移除了对 sample num 的判断，对不均匀的负载请求会概率性触发 panic。

具体来说，每个线程会用 tls 收集请求，然后汇总成 read_stat 发出来，在 collect_read_stats 的时候按照 region_id 重新组织，每个 region_id 对应一个 region_infos，他的每个元素都是来自于一个线程。

在采样的时候，为了避免重复，会 remove 掉采样过的 key，所以如果一个 region 的 qps 大于阈值(默认3000) 且存在一个线程处理请求低于 sample_num(默认20) 的话，而且被反复选中的次数大于 key 的数目，就会导致出现 panic 的情况。

## Diagnostic Steps

复现步骤及截图详细见：[https://docs.google.com/document/d/1MGO8FWqgdNm-Ws4oT7I4ir9_-qGGbxrILmEFG5l5x68/edit?n=load_base_split_panic#](https://docs.google.com/document/d/1MGO8FWqgdNm-Ws4oT7I4ir9_-qGGbxrILmEFG5l5x68/edit?n=load_base_split_panic)

以下是摘要：

复现测试环境

1 tidb + 1 pd + 8 tikv （预计 3 tikv 即可）

tikv版本：master 分支的 4c88ae6（引入修复的前一个 PR）

tikv 配置: split.detect-times=2(调低以增加触发概率） split.qps-threshold=500(调低以保证触发，低于 sysbench 的 qps 即可） split.sample-num=500(调高以增加触发概率，低于 qps 阈值即可) split.size-threshold=1(调低以保证触发，高于 sysbench 请求的 region 的大小即可） 构造测试

所以构造的时候，就努力让负载类型存在倾斜，点查的 qps 为1，剩下 500 及以上全部是 coprocessor，增加触发概率。

构造一个全表扫的的 sysbench，注意表的大小，保证请求落且仅落在一个 region 内。此外，threads=512，以保证 coprocessor 占绝对多数。

准备数据：sysbench --table_size=10000 --range_size=10000 --point_selects=0 --sum_ranges=0 --order_ranges=0 --distinct_ranges=0 --config-file=config oltp_read_only prepare

运行测试：sysbench --table_size=10000 --range_size=10000 --point_selects=0 --sum_ranges=0 --order_ranges=0 --distinct_ranges=0 --config-file=config oltp_read_only run

同时启动一个按照 detect-times 的点查，点查位置尽可能靠近边缘，以保证不会连续触发正常的 split。

File: select.sql use load_base_split; SELECT c FROM sbtest1 WHERE id=500;

File: test.sh for i in {1..3000} do mysql -h10.68.208.230 -P4000 -u root < select.sql sleep 2 done

## Resolution

将 QPS 阈值设高 以下是动态配置设置方法，可以调整相应 tikv 的配置文件： 

mysql >> set config tikv split.qps-threshold=3000000

## Workaround

1. 升级至 v4.0.12
2. 动态修改 tikv.split.qps-thread hold 至一个较大值（即关闭按 qps split region 的功能）

## Affacted-Version
 
 v4.0.11
