TiDB高手进阶:揭秘自增ID热点现象与高级调优技巧

目录

一、热点问题简介

二、热点场景

        2.1 表热点

        2.2 索引热点

三、TiDB 索引介绍

四、热点问题实战

        4.1 使用 AUTO_RANDOM 处理自增主键热点表

        4.2 自增 ID 热点问题方案

五、总结


一、热点问题简介

        TiDB 作为分布式数据库,内建负载均衡机制,尽可能将业务负载均匀地分布到不同计算或存储节点上,更好地利用上整体系统资源。然而,机制不是万能的,在一些场景下仍会有部分业务负载不能被很好地分散,影响性能,形成单点的过高负载,也称为热点。

        TiDB 提供了完整的方案用于排查、解决或规避这类热点。通过均衡负载热点,可以提升整体性能,包括提高 QPS 和降低延迟等。

        在 MySQL 中都会指定自增主键,从 MySQL 迁移到TIDB上时,可能会习惯性的创建自增主键 ID,TiDB 官方文档已经明确说明使用自增主键时 TiDB 会有热点问题,写入的数据都是连续的,那么就会插入到少数几个 Region 中,造成写入热点,那自增 ID 的情况下如何将数据打散呢?这篇文章带你深入解读。

二、热点场景

        TiDB 是通过 KV 类型的结构来保存数据,关于 TiDB 是如何通过键值对来保存数据的问题,请参考往期文章:TiDB内核解密:揭秘其底层KV存储引擎如何玩转键值对-CSDN博客 ,这里就不详细介绍了。

        TiDB 对每个表分配一个 TableID,每一个索引都会分配一个 IndexID,每一行分配一个 RowID(默认情况下,如果表使用整数型的 Primary Key,那么会用 Primary Key 的值当做 RowID)。其中 TableID 在整个集群内唯一,IndexID/RowID 在表内唯一,这些 ID 都是 int64 类型。

        2.1 表热点

        同一个表的数据会在以表 ID 开头为前缀的一个 range 中,数据的顺序按照 RowID 的值顺序排列。在表 insert 的过程中如果 RowID 的值是递增的,则插入的行只能在末端追加。当 Region 达到一定的大小之后会进行分裂,分裂之后还是只能在 range 范围的末端追加,永远只能在一个 Region 上进行 insert 操作,形成热点。

        常见的 increment 类型自增主键就是顺序递增的,默认情况下,在主键为整数型时,会用主键值当做 RowID,此时 RowID 为顺序递增,在大量 insert 时形成表的写入热点。

        同时,TiDB 中 RowID 默认也按照自增的方式顺序递增,主键不为整数类型时,同样会遇到写入热点的问题。

        2.2 索引热点

        索引热点与表热点类似,常见的热点场景出现在时间顺序单调递增的字段,或者插入大量重复值的场景。

三、TiDB 索引介绍

        TiDB 中的索引分为聚簇索引和非聚簇索引。

        聚簇索引 (clustered index) 是 TiDB 从 v5.0 开始支持的特性,用于控制含有主键的表数据的存储方式。通过使用聚簇索引,TiDB 可以更好地组织数据表,从而提高某些查询的性能。有些数据库管理系统也将聚簇索引称为“索引组织表” (index-organized tables)。

  • NONCLUSTERED:表示该表的主键为非聚簇索引,在非聚簇索引中,行数据的键由 TiDB 内部隐式分配的 _tidb_rowid 构成,而主键本质上时唯一索引,因此非聚簇索引表存储一行至少需要两个键值对,分别为:
    • _tidb_rowid(键)-行数据(值)
    • 主键列数据(键)-行数据(值)
  • CLUSTERED,表示该表的主键为聚簇索引。在聚簇索引表中,行数据的键由用户给定的主键列数据构成,因此聚簇索引表存储一行至少只要一个键值对,即
    • - 主键列数据(键) - 行数据(值)

四、热点问题实战

        上面介绍了那么多概念,到这里该讲一下如何解决热点数据问题了,解决方案有两种。

        4.1 使用 AUTO_RANDOM 处理自增主键热点表

        使用 AUTO_RANDOM 处理自增主键热点表,适用于代替自增主键,解决自增主键带来的写入热点。

        使用该功能后,将由 TiDB 生成随机分布且空间耗尽前不重复的主键,达到离散写入、打散写入热点的目的。

        注意 TiDB 生成的主键不再是自增的主键,可使用 LAST_INSERT_ID() 获取上次分配的主键值。

        虽然使用随机自增键值能解决写入热点问题,但也存在一些问题,具体如下:

  1. 性能:生成随机 ID 相比连续递增 ID 可能会有更高的 CPU 消耗,尤其是在高并发写入场景下,因为这涉及到更多的计算和协调工作。
  2. 范围分配与管理:AUTO_RANDOM 需要在每次插入时从预分配的ID范围内选择一个随机值,这意味着需要有效的管理这些ID范围,以避免范围耗尽或冲突。虽然TiDB内部会处理这个问题,但是极端情况下,如果ID空间使用不当,可能会导致分配效率降低或错误。
  3. 兼容性和迁移:使用 AUTO_RANDOM 的表在与其他数据库系统(尤其是那些不支持此特性的系统)之间迁移时,可能需要特别的处理,因为不是所有数据库都支持类似的随机主键生成策略。
  4. 索引和查询优化:随机ID可能导致二级索引的插入顺序随机,影响B-Tree索引的局部性,进而可能影响查询性能,尤其是在进行范围查询时。

        使用随机 ID 还是有很多问题需要考虑的,这就要求你进行权衡。那么在使用中,由于习惯了单机关系型数据的自增主键,尤其是从 MySQL 等数据库中迁移到 TiDB 中的数据,有的主键ID 可能关联了其他表,这种数据处理起来比较麻烦。那自增ID如何避免热点问题呢?

        4.2 自增 ID 热点问题方案

        首先需要将自增主键设置为非聚簇索引,那么这行数据的主键其实是 TiDB 隐式的 _tidb_rowid,然后通过设置 SHARD_ROW_ID_BITS,可以把 RowID 打散写入多个不同的 Region,缓解写入热点问题。不同的值代表设置不同的分片

SHARD_ROW_ID_BITS = 4 表示 2^4 = 16 个分片
SHARD_ROW_ID_BITS = 6 表示 64 个分片
SHARD_ROW_ID_BITS = 0 表示默认值 1 个分片

        通过增加分片数量,可以有效分散因使用隐式单调递增主键导致的写入热点问题,使得数据更均匀地分布在不同的 Region 上,提高写入性能并平衡存储资源的平衡。

        分片增加后可能会对那些依赖连续 ID 范围扫描的查询有一定影响,因为数据现在分布在更多的Region中,可能需要更多的查询计划和网络往返。

        SHARD_ROW_ID_BITS 是可以修改的,但是注意,每次修改之后,只对新写入的数据生效。

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) NOT NULL
  PRIMARY KEY (`id`) /*T![clustered_index] NONCLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin/*!90000 SHARD_ROW_ID_BITS=4 */;

五、总结

        TiDB 作为分布式数据库,设计目标是提供高并发、高可扩展性和容错能力。然而,当系统中出现热点问题时,会对整体性能和稳定性产生一系列负面影响,可能产生性能瓶颈、写入延迟、读取性能下降。

        所以需要通过合理的评估设计来预防和避免热点问题,以保障系统稳定运行。

往期经典推荐:

TiDB内核解密:揭秘其底层KV存储引擎如何玩转键值对_tidb架构-CSDN博客

TiDB 数据库调度(PD)揭秘_tidb的pd-CSDN博客

大数据的前世今生-CSDN博客

揭秘MyBatis插件:深入理解与实战运用-CSDN博客

Maven核心概念全解析-CSDN博客

  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超越不平凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值