作者:翟玉龙,施闻轩
本文适用于 TiDB 4.0 版本,介绍了如何定位和解决写入热点问题。关于读热点的处理方法,可临时参考下面的帖子,也请期待我们的后续补充
TiDB 作为分布式数据库,自身拥有一些负载均衡机制,尽可能将业务负载均匀地分布到不同计算或存储节点上,更好地利用上整体系统资源。然而,机制不是万能的,在一些场景下仍会有部分业务负载不能被很好地分散,影响性能,形成单点的过高负载,也称为热点。
TiDB 提供了完整的方案用于排查、解决或规避这类热点。通过均衡负载热点,可以提升整体性能,包括提高 QPS 和降低延迟等。
需要说明的是,性能问题不一定是热点造成的,也有可能有多个因素共同影响,在排查前需要先确认是否与热点相关(见下文)。另外,即使业务负载严重不均衡、热点明显,也不会引发正确性问题。
确认存在写热点
判断依据:打开监控面板 TiKV-Trouble-Shooting 中 Hot Write 面板(如下图所示),观察 Raftstore CPU 监控是否存在个别 TiKV 节点的指标明显高于其他节点的现象。
示例:存在写热点
18:30 前有单个 TiKV 实例的 Raft store CPU 比其他节点高出将近一倍,存在写入热点。在 18:30 后,写入热点得到了缓解。
示例:负载均衡、不存在明显热点
示例:负载不够均衡,但不是热点
需要注意排除以下案例,监控中负载有一定的不均衡,但因为并非个别 TiKV CPU 指标过高,因此不构成热点:
使用 TiDB Dashboard 定位热点表
TiDB Dashboard 中的「热点可视化」功能可帮助用户缩小热点排查范围到表级别。以下是一个「热点可视化」功能展示的热力图样例,该图横坐标是时间,纵坐标排列了各个表和索引,颜色越亮代表其流量越大。可在工具栏中切换显示读或写流量。
当图中写入流量图出现以下明亮斜线(斜向上或斜向下)时,说明该大流量表构成了写入热点:
将鼠标移到亮色块上,即可看到是什么表或索引具有大流量,如下所示:
大多数情况下,显著的热点都会来自于表数据。索引热点有存在的可能性,但一般不大显著,因此本文不覆盖。
这类写入热点主要有以下几种成因:
成因 | 规避或解决方案 |
---|---|
自增主键 | 不要使用自增主键,可改用 UUID 等,或使用 AUTO_RANDOM |
无主键/联合主键/非 INT 类型主键 | 使用 SHARD_ROW_ID_BITS |
INT 类型主键,且连续写入数值接近的主键 | 将该主键改为普通索引,再使用 SHARD_ROW_ID_BITS |
写入流量图中以下这类亮色横线对应的则是另一种热点模式:热点小表,但 TiDB 内置机制还不能很好地缓解这个情况,建议通过业务侧增加缓存等方法绕过:
可阅读「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 打散热点后的流量图,第一张展示了打散前的情况,第二张展示了打散后的情况。
由流量图可见,设置 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。
由流量图可见,使用 AUTO_RANDOM 代替 AUTO_INCREMENT 可以很好地打散热点情况。
更详细的使用方法可以阅读 AUTO_RANDOM 文档。