高并发写入优化需综合调整日志刷盘策略、批量插入、避免锁冲突及异步化非核心数据。具体包括:1. 调整innodb_flush_log_at_trx_commit=2和sync_binlog=0或1000;2. 使用多值insert+显式事务;3. 替换on duplicate key update为应用层幂等;4. 从库启用并行复制;5. 将日志类数据异步落库。

高并发写入卡住,先看 innodb_flush_log_at_trx_commit 和 sync_binlog
MySQL 写入慢,90% 以上不是磁盘本身慢,而是日志刷盘太保守。默认 innodb_flush_log_at_trx_commit=1 要求每次事务都 fsync redo log 到磁盘,sync_binlog=1 同样强制每次提交都同步 binlog——这在 SSD 上也扛不住每秒几百次小事务。
实操建议:
-
innodb_flush_log_at_trx_commit=2:日志写入 OS 缓冲即返回,崩溃最多丢 1 秒数据,写入吞吐常翻倍以上 -
sync_binlog=0或sync_binlog=1000:关闭或批量同步 binlog,主从延迟略增但避免频繁fsync - 两个参数必须一起调,单独改一个效果有限;且要确认业务能接受对应的数据一致性折衷
INSERT 别单条循环,改用多值批量 + 显式事务
循环执行 INSERT INTO t VALUES (1) 这种语句,在高并发下会迅速打满连接线程、锁竞争加剧、网络往返开销爆炸。即使用了预编译,也逃不开 SQL 解析和协议层重复消耗。
实操建议:
- 把 100–500 行合并成一条
INSERT INTO t (a,b) VALUES (1,2),(3,4),...,(999,1000) - 显式用
BEGIN/COMMIT包裹,避免autocommit=1导致每行都刷日志 - 单批总大小别超
max_allowed_packet(默认 64MB),建议控制在 1MB 内 - 大批量导入优先用
LOAD DATA INFILE,比等量INSERT快 5–20 倍,但需文件在服务端且用户有FILE权限
ON DUPLICATE KEY UPDATE 在高并发下容易锁表
INSERT ... ON DUPLICATE KEY UPDATE 看似方便,但在唯一键冲突频繁时(比如订单号去重、设备上报幂等),InnoDB 会升级为间隙锁(gap lock)甚至 next-key lock,导致大量事务等待甚至死锁。现象是 SHOW PROCESSLIST 中一堆线程卡在 Updating rows 状态。
实操建议:
- 确认这个唯一约束是否真有必要——有时只是防重手段,可换成应用层幂等(如 Redis key + TTL)或分布式锁
- 若必须保留,确保冲突率极低(如用户注册场景),否则改用
SELECT ... FOR UPDATE显式加锁,粒度更可控 - 注意它会对非冲突行也分配自增 ID,造成空洞,干扰容量评估和监控判断
从库写入慢?别调 innodb_flush_log_at_trx_commit
从库的写入动作全部来自复制线程重放 relay log,innodb_flush_log_at_trx_commit 对它影响极小。真正瓶颈通常在解析/锁等待/索引更新,而非 fsync。
实操建议:
- 设
slave_parallel_workers=4~16(视 CPU 核数),并配slave_parallel_type=LOGICAL_CLOCK -
innodb_buffer_pool_size不低于主库的 70%,否则重放时大量页要从磁盘读取再修改 - 检查主库是否开了
binlog_group_commit_sync_delay(MySQL 8.0+ 推荐设为 100000),否则组提交失效,并行回放退化为单线程 - 观察
SHOW PROCESSLIST中多个 Worker 是否真在Executing,还是全卡在Waiting for an event from Coordinator——后者说明 workload 不适合并行(如所有 DML 都集中在同一张表)











