MySQL 自增主键热点与分布式 ID 实践

在高并发写入场景下,InnoDB 的自增主键(AUTO_INCREMENT)会在聚簇索引上形成尾部写热点,导致插入抖动与间歇性锁等待。本文从 InnoDB 聚簇索引结构、插入缓冲、间隙锁协同等维度拆解热点成因,并给出分布式 ID 的落地实践与权衡。

1. 聚簇索引与尾部写热点

  • InnoDB 的聚簇索引以主键排序存储,AUTO_INCREMENT 会将新记录追加到 B+Tree 右侧叶子。
  • 高并发插入时,右侧叶子页存在锁竞争与页分裂放大,表现为插入 TPS 下降与 P95/P99 波动。
CREATE TABLE orders (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT NOT NULL,
  amount DECIMAL(10,2) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  KEY idx_user (user_id)
) ENGINE=InnoDB;

2. AUTO_INCREMENT 锁与并发

  • MySQL 5.7 之前,AUTO_INCREMENT 使用表级锁(不同模式);8.0 之后改进为持久化计数器与更细粒度控制,但热点依旧存在。
  • 插入批量提交(group commit)可缓解 WAL 压力,但右边界叶子页仍是竞争点。

3. 方案对比

  • 雪花算法(Snowflake):时间戳 + 机房ID + 机器ID + 自增序列,单机内有序,跨机整体趋势递增。
  • 数据库号段(Segment):业务方一次申请号段,内存发号,落库更新游标,吞吐高但需要容灾与幂等。
  • Redis INCR:实现简单,单点需高可用(主从/哨兵/集群),序列漂移与冷启动需评估。
方案 顺序性 吞吐 复杂度 依赖
AUTO_INCREMENT MySQL
Snowflake 趋势递增 时钟、节点元数据
号段 趋势递增 极高 DB 持久游标
Redis INCR Redis 可用性

4. 索引与二级索引代价

  • 主键变长(如雪花 ID)会放大二级索引的指针大小(leaf 指向 PK),读放大明显。
  • 建议:保持主键定长 BIGINT,避免 UUID(36) 直接做 PK,可用 BINARY(16) 存储 UUIDv1/v7。

5. 可复现实验(sysbench + 尾部热点)

# 1) 准备数据与表结构
mysql -e "DROP DATABASE IF EXISTS demo; CREATE DATABASE demo;"
mysql demo < <(cat <<SQL
CREATE TABLE t_hot (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  k  BIGINT NOT NULL,
  v  VARCHAR(64) NOT NULL,
  KEY idx_k(k)
) ENGINE=InnoDB;
SQL
)

# 2) 并发插入压测(64 线程,持续 120s)
sysbench oltp_insert --mysql-db=demo --table-size=0 \
  --threads=64 --time=120 run

# 3) 观察:
# - performance_schema.events_waits_summary_global_by_event_name 中的锁等待
# - information_schema.INNODB_METRICS 中的页分裂、btr_node_split

对照改为雪花 ID(应用侧生成)并将 id 定长 BIGINT,重复压测,观察 TPS 与 P95 改善幅度。


6. 源码走读要点(InnoDB)

  • btr0cur.cc:B+Tree 游标在右侧页插入与分裂路径;
  • trx0i_s.cc:自增计数器的持久化与并发控制;
  • log0write.cc:group commit 对日志刷盘合并的影响。

关注点:右侧叶子页 latch 竞争、页分裂代价、secondary index 指针放大。


7. 生产变更与回滚手册

1) 灰度:在影子表启用新 ID 策略,双写比对一致性(ID 单调、越界、重复)。 2) 切换:将业务写流量按 5%/20%/50%/100% 提升;监控写延迟、死锁、页分裂。 3) 回滚:保留开关,出现异常立即退回 AUTO_INCREMENT;影子表数据对账。


8. 观测指标基线

  • 写延迟 P95/P99、QPS、redo fsync 次数;
  • btr_page_split、lock_time、待提交事务数;
  • 二级索引大小增幅(变长 PK 带来的指针放大)。

9. FAQ

  • 雪花 ID 时钟回拨怎么办?
    • NTP + 单调时钟守护;回拨检测时暂停发号并降级到号段。
  • 二级索引变大影响查询?
    • 评估热点查询是否可走覆盖索引/缩短选择列;必要时引入只读副本。