如何分析和解决 TiDB 4.0 的写热点问题

作者:翟玉龙,施闻轩

本文适用于 TiDB 4.0 版本,介绍了如何定位和解决写入热点问题。关于读热点的处理方法,可临时参考下面的帖子,也请期待我们的后续补充

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

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

需要说明的是,性能问题不一定是热点造成的,也有可能有多个因素共同影响,在排查前需要先确认是否与热点相关(见下文)。另外,即使业务负载严重不均衡、热点明显,也不会引发正确性问题。

确认存在写热点

判断依据:打开监控面板 TiKV-Trouble-Shooting 中 Hot Write 面板(如下图所示),观察 Raftstore CPU 监控是否存在个别 TiKV 节点的指标明显高于其他节点的现象。

示例:存在写热点

18:30 前有单个 TiKV 实例的 Raft store CPU 比其他节点高出将近一倍,存在写入热点。在 18:30 后,写入热点得到了缓解。

示例:负载均衡、不存在明显热点

WX20200429-113915%402x

示例:负载不够均衡,但不是热点

需要注意排除以下案例,监控中负载有一定的不均衡,但因为并非个别 TiKV CPU 指标过高,因此不构成热点:

WX20200429-113958%402x

使用 TiDB Dashboard 定位热点表

TiDB Dashboard 中的「热点可视化」功能可帮助用户缩小热点排查范围到表级别。以下是一个「热点可视化」功能展示的热力图样例,该图横坐标是时间,纵坐标排列了各个表和索引,颜色越亮代表其流量越大。可在工具栏中切换显示读或写流量。

当图中写入流量图出现以下明亮斜线(斜向上或斜向下)时,说明该大流量表构成了写入热点:

WX20200429-114207%402x

将鼠标移到亮色块上,即可看到是什么表或索引具有大流量,如下所示:

WX20200429-114255%402x

大多数情况下,显著的热点都会来自于表数据。索引热点有存在的可能性,但一般不大显著,因此本文不覆盖。

这类写入热点主要有以下几种成因:

成因 规避或解决方案
自增主键 不要使用自增主键,可改用 UUID 等,或使用 AUTO_RANDOM
无主键/联合主键/非 INT 类型主键 使用 SHARD_ROW_ID_BITS
INT 类型主键,且连续写入数值接近的主键 将该主键改为普通索引,再使用 SHARD_ROW_ID_BITS

写入流量图中以下这类亮色横线对应的则是另一种热点模式:热点小表,但 TiDB 内置机制还不能很好地缓解这个情况,建议通过业务侧增加缓存等方法绕过:

WX20200429-114338%402x

可阅读「TiDB in Action - 2.1 识别集群热点和业务模式」进一步了解「热点可视化」工具的使用。

使用 SHARD_ROW_ID_BITS 处理热点表

本方法不适用于自增主键,自增主键可用下文的 AUTO_RANDOM 方法。另外如果热点表的主键是 INT 类型,使用本方法前需先去除主键改为普通索引。

通过设置表的 SHARD_ROW_ID_BITS 属性可以将相邻的行写入转化为离散的行写入,缓解热点。样例如下:

CREATE TABLE t (a INT) SHARD_ROW_ID_BITS = 4;

ALTER TABLE t SHARD_ROW_ID_BITS = 4;

SHARD_ROW_ID_BITS 的值决定了打散程度,用户可根据 TiKV 个数以及打散效果决定和调整该值的大小:

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

SHARD_ROW_ID_BITS 的值可以动态修改,每次修改之后,只对新写入的数据生效。

注意:SHARD_ROW_ID_BITS 不宜设置得过大,否则会造成 TiDB 与 TiKV 之间内部请求数放大(与分片数相关),增加 CPU 和网络开销,无法取得最佳性能。

以下是两张无主键情况下使用 SHARD_ROW_ID_BITS 打散热点后的流量图,第一张展示了打散前的情况,第二张展示了打散后的情况。

WX20200429-114456%402x WX20200429-114506%402x

由流量图可见,设置 SHARD_ROW_ID_BITS 后,流量热点可以由之前的很集中变得很分散。

更详细的使用方法可以阅读 SHARD_ROW_ID_BITS 文档

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

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

该功能目前还是实验性功能,不推荐生产环境使用。可使用以下配置启用:

[experimental]

allow-auto-random = true

使用该功能后,将由 TiDB 生成随机分布且空间耗尽前不重复的主键,达到离散写入、打散写入热点的目的。注意,TiDB 生成的主键不再是自增的主键,可使用 LAST_INSERT_ID() 获取上次分配的主键值。

接下来,将建表语句中的 AUTO_INCREMENT 改为 AUTO_RANDOM 即可使用该功能,示例如下:

以下是将 AUTO_INCREMENT 表改为 AUTO_RANDOM 打散热点后的流量图,第一张是 AUTO_INCREMENT,第二张是 AUTO_RANDOM。

WX20200429-114826%402x WX20200429-114839%402x

由流量图可见,使用 AUTO_RANDOM 代替 AUTO_INCREMENT 可以很好地打散热点情况。

更详细的使用方法可以阅读 AUTO_RANDOM 文档

阅读其他相关资料

TiDB 高并发写入场景最佳实践

Split Region 使用文档

4赞

所以怎么去掉 int 类型主键,报错 pkIsHandle is true。

有两个方案:

好可爱~

了解了,非常感谢你的回复,那就了解了,我还以为只能能删除呢? alter-primary-key 这个参数是已经配置了的。

还怀疑自己,是不是姿势不对。我以为可以绕过 pkishandle,还在想那底层的数据咋办,有的 key 和 value 都是保存了 handle id 的。

okok,这个样才是符合预期的

1赞