Region split 是不是从 Region Key Range 的中间位置二分分裂?

【 TiDB 使用环境】生产环境 /测试/ Poc
【 TiDB 版本】all
【复现路径】
【遇到的问题:问题现象及影响】

在聊天中有大佬提出了如上的问题,本着不懂就问的原则,在这里也请教一下社区的各位大佬, Region 达到调度阈值后需要进行 split 的时候,它开始分裂的位置是哪里,怎么判断的?

最先想到的是从 Region Key Range 的中间位置二分分裂,但原理确实如此吗?

  1. 官网 https://docs.pingcap.com/zh/tidb/stable/sql-statement-split-region#split-region-的使用 这里提到的是手动设置PD策略可以实现均匀切分或者非均匀切分

  2. 源码案例这里可以查看默认的方式,没梯子暂时访问不了 GitHub ,根据文档的描述也可以看到一些线索。
    TiKV 源码解析系列文章(二十)Region Split 源码解析 | PingCAP

split_check 有以下几种:

1 检查 Region 的总或者近似 Size,代码位于 size.rs。
2 检查 Region 的总或者近似 Key 数量是否超过阈值,代码位于 key.rs。
3 根据 Key 范围二分 Split,代码位于 half.rs,除了上文讲的 PD 指定 key 来 Split,这种方式也是由 PD 触发的,目前只有通过 pd-ctl 和 tikv-ctl 的命令来手动触发。
4 根据  Key 所属 Table 前缀 Split,代码位于 table.rs,配置默认关闭。

split_check 这里提到了 几种方式。ApplyDelegate::exec_batch_split 是实现split的地方:

1 更新原 Region 的 version,新 Region 的 epoch 继承原 Region 的 epoch。
2 right_derive 为 true 的,原 Region 要分裂到右侧,为 false 则反之,依次设置每个 Region 的 start key 与 end key。
3 对每个 Split 出来的新 Region 调用 write_peer_state 与 write_initial_apply_state 创建元数据。

感觉答案就在 ApplyDelegate::exec_batch_split 这里

1 个赞

默认就是从中间分,以前测试过

看上面的源码分析文章,由于leader 租期约定和超时设计等机制,可以保证切完之后两个 leader 默认都还是在原来的 TiKV store 里 。
后面如果有必要,再通过集群的调度策略 进行均衡调度。

二分法

如果主键自增的从中间分合理吗

rust实在不熟,看了代码也是一脸懵。 :sweat_smile:
需要尽快学习rust了。

二分不二分的,研究这个原理是干啥用啊?小白表示一脸懵
splitpoint是整个region中最大store中的最大文件中最中心的一个block的首个rowkey 然后就以此值切分了 是这样不?

Region 的分裂都是尽可能地从靠近中间的位置开始。对这个位置的选择支持两种策略,即 scan 和 approximate。它们之间的区别是,前者通过扫描这个 Region 的方式来确定中间的 key,而后者是通过查看 SST 文件中记录的统计信息,来得到近似的位置。一般来说,前者更加精确,而后者消耗更少的 I/O,可以更快地完成。
pd-ctl:

operator add split-region 1 --policy=approximate // 将 Region 1 对半拆分成两个 Region,基于粗略估计值
operator add split-region 1 --policy=scan // 将 Region 1 对半拆分成两个 Region,基于精确扫描值

1 个赞

是的,应该是从整个Region中最中心的数据的 StartKey进行分裂。

手动添加 operator 的话,pd 肯定是会根据我们设置的方式进行 split 的,这块内容的理解大家应该都没有问题。

主要是不确定 TiKV 对 Region 进行 Split 时的 Default 方式。

这里有讲到“Region 的分裂和合并由 PD 调度器负责,它会根据 Region 的大小、数据量、访问量等指标来决定是否需要分裂或合并 Region,并选择合适的切分或合并点。

有没有测试过,比如1-10,1-5只有很少或一个,大部分值在5-10,也会从中间切还是会评估值的多少

hhhhhh~你们看上去都看上源码了。太厉害了~

主要是包老师这个问题既朴素又直击灵魂,激起来了探索好奇心 :grinning:

如果值的间隙足够大,新值大部分都在末尾,哪二分会一直分下去

应该不可能无限大,每个文件的最大值应该有限定,这样每个region的startKey和endKey应该有固定范围的,超过之后应该就自动从最大的那个region从中间切分了。不知道你了解hbase吗,原理基本和tidb类似,hbase的默认单个region的最大是10G存储

好像你说的跟我说的不是一个问题,我说的是比如已经满足拆分region,100000-160000 只有10个值160000-200000有50000个值,如果只是根据key的中间切分,哪两个region 一个10个值,一个50000个值,是不是50000值的还是再切分,如果间隙足够大是不是会一直切分

拆分是按region的文件大小进行操作的,跟数据量没关系,官方是单个region超过144M进行拆分,不会说是一个region为1G然后多次拆分的情况,所以不会存在间隙足够大一直拆分,而是到了一定大小就自动处理了

region是可以拆分和合并的,如果存在你说的这种情况,比如现在有3个region,region的区间是1-100,100-200,200-300,但是可能1-100存的很少,200-300也一样,只有100-200之间的region存取的数据量比较多,这种情况就是热点问题,但是100-200之间的存储过多时,超过单个region文件的大小时,可能就会拆分多个region,不会说特别大到一定程度多次拆分的情况。然后其他过小的region也可能会重新合并成新的region

分裂后新 Region 的大小=Region 容量空间最大值 / 2 * 3
region-max-keys=region-split-keys / 2 * 3
默认不是从三分之二处切割?
image
image