线上沙龙 - 技术流第 40 期回放来啦
splitQueue 负责 Range 的分裂,触发 Range 分裂的条件如下: 新建数据库或表。 Range 大小超过 range_max_bytes。 Range 的 QPS 过高,超过 kv.range_split.load_qps_threshold (默认值 250,可配置)。 修改 index 或 partition 的 Configure zone,使其从父级别中独立出来。在特殊情况下,会不经过 splitQueue,而直接调用 adminSplit 分裂。 在导入大量数据时,1 个 Range 自动分裂成多个 Range。 在导入数据时,为后续可能导入的数据预分裂出一个空白 Range。 手动分裂:alter table table_name split at values (key1,key2,…);其中 Values 表示主键值,若为联合主键可写多个,不能超过主键列数。 KaiwuDB 的某个节点后台有单独的线程/ worker 保持运行,用以处理相关 Range 的分裂。Range 分裂为 2 个阶段:第 1 阶段 — Range 分裂参数准备;第 2 阶段 — 更新 Range 及其索引结构。 如图所示,左边流程主要为分裂 Range 的准备工作: 首先锁定分裂 Range 的 Key 的键值。找到这个键值后,系统会把当前的 Range 范围调整,用分裂的 Key 键值作为分区的结束键值。 流程会为右边创建一个新的 Range,它的起始键值就是分裂所用键值,结束键值即是原始 Range 的结束键值。同时,原始 Range 被分裂后,它的版本会迭代更新加 1,该更新版本会被同时应用到左右两个分裂后的 Range。 当 Range 左边和右边的分裂参数准备好后,流程进入系统数据更新环节,概括来说需要准备写请求和处理请求,该过程关联到事务,整个事务需要完成如下事项: 开始新的事务,状态为 pending 更新左边 Range 写入新的右边 Range 更新左边 Range 的巨无霸索引二层树状结构的相应查找路径 插入右边 Range 的巨无霸索引二层树状结构的相应查找路径 更新事务的状态为 Committed 更新左右 Range 的 MVCC 清理写意图 到此为止,整个 Range 的分裂完成。 如下调试触发场景是在 Range 大小超过预定的临界值后发生的。 每处理一个 Range,是按照 timer 等待串行方式进行的。在时钟唤醒后,会检查 Range 大小,如果发现这个 Range 大小在 70MB 左右,超过预定范围 64 M,就会触发系统调用分裂 Range 函数,对这个超过容量限度的 Range 进行分裂。 该后台线程或者 worker 会一直循环不断地检查所有的 Range 进行处理。 如图所示,当用户删除了大量数据后,两个相邻 Range 的大小急剧变小,此时系统会将它们进行合并。 下图是合并后的效果示意,此前的两个 Range:lem-str, str- 合并后,str- 消失,只剩下 lem-,原有两个 Range 的 Key 键值均合并到同一个 Range lem-。相应的巨无霸索引二层数据结构也发生调整,一层树状索引结构里的 pea- 消失。 合并 Range 的条件比较严格,主要包括: 合并没有被禁用 有下一个 Range 且有相同的 Configure zone 两个待合并的 Range 大小都小于 range_min_bytes 合并后不会触发 QPS 的 Range 分裂 其中最后一条是指,假如数据所在的 Range 有热点数据,即不执行合并,因为合并后又会触发分裂,反反复复将导致系统无法正常运行。 如图所示,合并与分裂一样,也是分 2 个阶段:第1个阶段 — Range 参数准备;第 2 阶段 — 启用事务进行 Range 更新处理。更多详情可点击视频查看完整版回放。 如下两个示意图为调试 Range 合并的具体流程以及对应的 Range 相关参数。