0
0
1
0
博客/.../

什么是数据库热点处理?TiDB 自动热点分裂与负载均衡机制

 Billmay表妹  发表于  2026-06-02
原创

摘要

数据库热点是分布式系统中常见的性能瓶颈:当大量读写请求集中到少数数据分片时,即使集群整体资源充足,这些热点分片也会成为系统的短板。本文分析热点问题的成因与影响,深入解析 TiDB 的自动热点检测、Region 分裂与负载均衡机制,以及手动优化策略。

本文适合谁:正在解决数据库性能瓶颈、遇到负载不均问题的 DBA、后端工程师和架构师。


一、什么是热点问题

在分布式数据库中,数据被划分为多个分片(TiDB 中称为 Region),由不同节点承载。当某些分片承载的请求量远超其他分片时,就产生了热点

1.1 热点类型

热点类型 成因 典型场景
写入热点 大量新数据写入同一 Region 自增主键插入、时间序列数据、消息队列
读取热点 高频查询集中到少数 Region 热门商品查询、用户活跃数据、缓存穿透
混合热点 读写同时集中 社交信息流、即时通讯消息、实时排行榜

1.2 热点的典型成因

自增主键是最常见的写入热点来源

-- 问题:所有 INSERT 写入同一 Region(最大主键所在的 Region)
CREATE TABLE orders (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,  -- 自增主键!
    user_id BIGINT,
    amount DECIMAL(10,2),
    created_at DATETIME
);

-- 每次 INSERT 都写入主键最大值附近的 Region
INSERT INTO orders (user_id, amount, created_at) VALUES (1001, 99.9, NOW());

由于自增主键的写入总是递增的,新数据始终集中在主键最大值所在的 Region,导致该 Region 成为写入瓶颈。


二、热点对性能的影响

2.1 性能退化表现

指标 正常状态 热点状态
P99 写入延迟 5-10ms 50-500ms+
P99 读取延迟 3-5ms 20-100ms+
单节点 CPU 使用率 30%-50% 80%-100%
单节点 IO 利用率 20%-40% 70%-90%
QPS 线性扩展 瓶颈不随扩容提升

2.2 为什么扩容不能解决热点?

热点问题的本质是请求分布不均,而非总资源不足。即使增加更多 TiKV 节点,如果请求仍然集中到某几个 Region,新增节点的资源也无法被利用。

正常分布:                热点分布:
Node-1: ████             Node-1: ████████████ (过载)
Node-2: ████             Node-2: ████████████ (过载)
Node-3: ████             Node-3: ██ (空闲)
Node-4: ████             Node-4: ██ (空闲)

结果:扩容无用

三、TiDB 热点处理机制

TiDB 提供了从自动检测到自动处理的全链路热点解决方案。

3.1 Region 自动分裂

TiDB 将数据按 Key Range 划分为 Region,默认每个 Region 约 96MB。当 Region 的大小或写入量超过阈值时,PD 会自动触发 Region 分裂:

分裂前:
Region-1: [min_key ──────────────────── max_key]  ← 192MB,超阈值

分裂后:
Region-1: [min_key ──────── mid_key)              ← 96MB
Region-2: [mid_key ──────────── max_key]          ← 96MB

分裂后的两个 Region 可以被调度到不同的 TiKV 节点,实现负载分散。

3.2 热点检测

TiDB 的热点检测分为两个层面:

TiDB Server 层检测

TiDB Server
├── 接收 SQL 请求
├── 解析 Key Range
├── 统计每个 Key Range 的读写频率
├── 定期(每 10s)上报热点信息到 PD
└── 热点判定阈值:单 Region 写入 > 1000 ops/s 或 1 MB/s

PD Server 层检测

PD Server
├── 收集所有 TiDB 节点的热点上报
├── 汇总 Region 级别热点统计
├── 判定热点程度(hot/very-hot)
└── 触发负载均衡调度

3.3 负载均衡调度

PD 检测到热点后,自动执行以下调度策略:

调度操作 说明 触发条件
Region 分裂 将大 Region 拆分为小 Region Region 大小或写入量超阈值
Leader 迁移 将热点 Region 的 Leader 迁到空闲节点 某节点 Leader 负载过高
Replica 迁移 将热点 Region 的副本迁到空闲节点 某节点整体负载过高
热点打散 将连续热点 Region 分散到不同节点 连续 Key Range 的多个 Region 都很热
热点处理流程:
检测到热点 Region → 评估负载分布 → 执行分裂 → 迁移 Leader/Replica
                                                         ↓
                                              负载均衡,写入分散

3.4 自动分裂的局限

TiDB 的自动热点处理有一定局限:

  • Key Range 连续性:自增主键的写入虽然集中在最大值附近,但分裂后新数据仍然写入分裂后的最大 Region,热点只是暂时缓解
  • 检测延迟:热点检测周期为 10 秒,调度执行需要额外时间,存在短暂的热点窗口
  • 分裂粒度:Region 不能无限分裂(最小约 96MB),对于极端热点仍需要手动优化

四、手动热点处理策略

4.1 主键设计优化

方案 1:使用非自增主键

-- 推荐:使用随机分布的主键
CREATE TABLE orders (
    id BIGINT PRIMARY KEY,         -- 应用层生成 ID(雪花算法 / UUID)
    user_id BIGINT,
    amount DECIMAL(10,2),
    created_at DATETIME
);

-- 或者使用 SHARD_ROW_ID_BITS 自动打散
CREATE TABLE orders (
    id BIGINT AUTO_INCREMENT PRIMARY KEY SHARD_ROW_ID_BITS = 4,
    -- _tidb_rowid 的高 4 位会随机分配,将写入分散到 16 个 Region
    user_id BIGINT,
    amount DECIMAL(10,2),
    created_at DATETIME
);
方案 写入分散效果 改造成本 注意事项
应用层生成 ID(雪花算法) 优秀 中(需改写入逻辑) ID 有序性降低,范围查询受限
`SHARD_ROW_ID_BITS` 良好(2^n 倍分散) 低(建表参数) 仅影响隐式 Row ID,不影响自增列
复合主键 优秀 需要合理选择分片键

4.2 分片键选择

对于需要手动分片的场景,选择合适的分片键至关重要:

好的分片键特征:
✓ 基数大(不同取值多)
✓ 分布均匀(无偏斜)
✓ 查询模式匹配(不会导致跨 Region 查询过多)

不好的分片键特征:
✗ 基数小(如性别、状态)
✗ 分布偏斜(如大部分数据集中在一个取值)
✗ 与查询模式不匹配(每次查询都要扫描多个 Region)

4.3 读取热点优化

-- 方案 1:增加 TiFlash 副本,分析查询走列存
ALTER TABLE orders SET TIFLASH REPLICA 2;

-- 方案 2:使用缓存层减轻数据库压力
-- 应用层引入 Redis 缓存热点查询结果

-- 方案 3:优化查询,减少不必要的全表扫描
-- 为高频查询添加合适的索引

4.4 预分区

对于已知的分区键,可以创建表时预先分区:

-- 按 user_id 范围预分区
CREATE TABLE orders (
    id BIGINT,
    user_id BIGINT,
    amount DECIMAL(10,2),
    created_at DATETIME,
    PRIMARY KEY (id, user_id)
) PARTITION BY RANGE (user_id) (
    PARTITION p0 VALUES LESS THAN (1000000),
    PARTITION p1 VALUES LESS THAN (2000000),
    PARTITION p2 VALUES LESS THAN (3000000),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

五、热点监控

5.1 TiDB Dashboard

TiDB 内置的 Dashboard 提供热点可视化监控:

路径:TiDB Dashboard → Hot Spot → Load Distribution

可视化内容:
- 每个 TiKV 节点的读写流量分布
- 热点 Region 列表(Key Range、QPS、流量)
- 调度操作历史记录
- 自动分裂和迁移事件

5.2 Grafana 监控指标

指标 说明 告警阈值建议
`tikv_region_read_keys_count` 各 Region 读取 key 数量 最大值 > 平均值 3 倍
`tikv_region_write_keys_count` 各 Region 写入 key 数量 最大值 > 平均值 3 倍
`pd_hot_spot_status` PD 热点状态 出现 hot/very-hot
`tikv_scheduler_leader_count` 各节点 Leader 数量 偏差 > 20%
`tikv_engine_write_size` 各节点写入流量 最大值 > 平均值 2 倍

5.3 SQL 级热点定位

-- 查看慢查询中涉及的表和 Key Range
SELECT * FROM information_schema.slow_query
WHERE time > NOW() - INTERVAL 1 HOUR
ORDER BY query_time DESC LIMIT 20;

-- 查看 Region 信息
-- 通过 tikv-ctl 或 PD API 查看热点 Region 的 Key Range

FAQ

Q1:如何检测 TiDB 中的热点?

推荐以下方法:

  1. TiDB Dashboard:最直观,可直接查看 Hot Spot 面板的负载分布图
  2. Grafana 监控:通过 `pd_hot_spot_status` 和 `tikv_region_*_count` 指标设置告警
  3. 性能诊断:观察 P99 延迟突增且 CPU 使用不均时,大概率存在热点
  4. PD API:调用 `/pd/api/v1/hotspot/regions/tables` 获取热点 Region 列表

Q2:热点分裂有什么代价?

Region 分裂的主要代价:

  • 短暂延迟:分裂过程中涉及的 Region 有短暂的读写延迟升高(通常 < 100ms)
  • 元数据增加:更多 Region 意味着 PD 需要管理更多的元数据,PD 负载增加
  • 调度开销:更多 Region 需要更多的 Leader 选举和心跳维护
  • 通常情况下这些代价可以忽略,但在极端小数据量场景下(Region 过小),分裂反而会增加调度开销

Q3:写入热点和读取热点分别怎么处理?

写入热点:通过主键设计优化(SHARD_ROW_ID_BITS、雪花算法 ID)打散写入分布是根本方案。TiDB 的自动分裂只能暂时缓解,无法从根本上解决连续写入热点。

读取热点:增加 TiFlash 副本将分析查询卸载到列存引擎,应用层引入缓存(Redis),优化索引和查询减少不必要的全表扫描。TiDB 的 Leader 迁移可以在一定程度上分散读取负载。

Q4:哪些业务场景容易产生热点?

场景 热点类型 典型表现
自增主键的插入密集型业务 写入热点 订单、日志、消息队列
时间序列数据(按时间写入) 写入热点 IoT 数据、监控指标、审计日志
社交 Feed 流 读取热点 活跃用户的动态被频繁读取
秒杀/促销活动 混合热点 少数商品的并发读写
实时排行榜 读取热点 TOP N 查询集中在头部数据
用户行为事件流 写入热点 点击流、埋点数据连续写入

总结

数据库热点是分布式系统中常见的性能问题,其本质是请求分布不均导致的局部过载。TiDB 通过自动热点检测、Region 分裂和负载均衡调度提供了基础的热点处理能力,但对于极端热点(如自增主键写入),仍需要通过合理的主键设计和分片策略从根本上解决。结合 TiDB Dashboard 和 Grafana 监控,可以及时发现和处理热点问题,保障集群的稳定性和性能。


下一步行动

相关资源

0
0
1
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论