mysql主从复制中如何避免死锁_并发控制方案

8次阅读

mysql主从复制本身不产生死锁,死锁仅发生在主库单机事务并发执行时;从库因单线程(或逻辑多线程)回放relay log且无行锁竞争,不会出现死锁。

mysql主从复制中如何避免死锁_并发控制方案

MySQL 主从复制本身不产生死锁,但写操作在主库可能引发死锁

死锁只发生在**单机事务并发执行时**,从库是单线程(或逻辑多线程)回放 relay log,不涉及行锁竞争,因此从库不会出现死锁。真正要关注的是:主库上高并发写入时,INSERTUPDATEdelete 语句因锁顺序不一致触发的死锁——它会中断主库事务,导致 binlog 写入不完整,进而让从库 SQL 线程报错卡住(如 Deadlock found when trying to get lock)。

实操建议:

  • 主库开启 innodb_deadlock_detect = ON(默认开启),确保死锁能被快速发现并回滚一个事务
  • 监控主库状态变量:SHOW STATUS LIKE 'Innodb_deadlocks';,持续上升说明应用层存在锁序混乱
  • 避免在事务中跨多个无关表更新,尤其不要混合操作大表和小表且顺序不固定
  • select ... for UPDATE 时,务必按相同顺序访问表和索引(例如总是先锁 users 再锁 orders

从库回放阶段的并发控制:如何安全启用 parallel replication

MySQL 5.7+ 支持基于 LOGICAL_CLOCK 的并行复制(slave_parallel_type = LOGICAL_CLOCK),但它依赖事务组提交(group commit)信息。若主库未开启 binlog_group_commit_sync_delaybinlog_group_commit_sync_no_delay_count,事务组提交效果弱,从库并行度低,还可能因依赖关系错乱导致数据不一致。

关键配置与避坑点:

  • 主库必须设 binlog_format = ROW,STATEMENT 或 MIXED 模式下无法保证事务间逻辑独立性
  • 主库开启 binlog_transaction_dependency_tracking = WRITESET(MySQL 8.0.26+),比 COMMIT_ORDER 更细粒度识别无冲突事务
  • 从库设置 slave_parallel_workers = 4~8(不宜超过 CPU 核数),同时开 slave_preserve_commit_order = ON 防止从库最终一致性被破坏
  • 注意 WRITESET 依赖 primary keynot NULL unique key,若表无此类键,退化为 COMMIT_ORDER,并行效果下降

应用层写入优化:减少主库锁冲突的直接手段

很多“死锁报警”实际源于应用批量写入没控制节奏,比如循环执行 1000 次 INSERT INTO t VALUES (...) 单条语句,每条都启事务、加锁、提交,极大增加锁等待和冲突概率。

更稳的做法:

  • 合并写入:用 INSERT INTO t VALUES (...), (...), (...) 批量插入,减少事务数量和锁持有时间
  • 显式控制事务边界:避免 ORM 自动开启短事务,对关联更新用 BEGIN; UPDATE a; UPDATE b; COMMIT; 显式包裹,确保锁顺序可预测
  • 读多写少场景下,考虑用 INSERT ... ON DUPLICATE KEY UPDATE 替代先 SELECTINSERT/UPDATE,省去一次锁竞争
  • 高频更新计数器类字段,改用 INSERT ... SELECT ... FROM DUAL ON DUPLICATE KEY UPDATE cnt = cnt + 1,避免 SELECT FOR UPDATE 引入长锁

从库延迟与死锁误判:为什么 Seconds_Behind_Master 为 0 还卡住

有时 SHOW SLAVE STATUS 显示 Seconds_Behind_Master: 0,但 Slave_SQL_Running_State 却停在 Waiting for dependent transaction to commit ——这不是死锁,而是 WRITESET 并行复制机制在等上游事务提交,本质是依赖等待(dependency wait),不是锁等待。

排查方向:

  • performance_schema.replication_applier_status_by_coordinator,看 APPLIED_TRANSACTIONLAST_APPLIED_TRANSACTION 是否一致
  • 若从库有大事务(如 ALTER table 或全表更新),它会阻塞后续所有事务的并行回放,此时应避免在业务高峰期做 DDL
  • slave_parallel_type = LOGICAL_CLOCK 下,主库单个长事务会导致从库 worker 线程集体空转等待,不如临时切回 database 模式(按库分发)保可用性

真正难处理的,是主库事务设计本身没考虑锁粒度和顺序——这类问题不会因为调参数消失,得回到业务 SQL 和事务划分上去动刀。

text=ZqhQzanResources