事情本身不复杂,线索都在日志里。业务日志里偶尔出现死锁报错,事务被回滚,用户看到提交失败,重试一次又能成功。
真正麻烦的地方在于,几个原因的现象几乎一样。两个事务以相反顺序更新同一批行。还有一种是唯一索引冲突时加锁范围比预期大。
少数情况下是长事务持有锁等待另一条语句。
上来先看最近一次死锁详情
mysql -e 'show engine innodb status\G' | sed -n '/LATEST DETECTED DEADLOCK/,/TRANSACTION/p'
接着确认事务隔离级别
mysql -e 'select @@transaction_isolation'
再往下把更新顺序统一到同一维度
grep -rn 'for update' app/sql/
缩短事务范围并加重试
mysql -e 'show variables like \"innodb_lock_wait_timeout\"'
报错是间歇性的,我蹲守了半小时才抓到一次完整现场。
白天有业务在跑,能验证的部分都压到了晚上做。
恢复的判定其实很直接。死锁报错频率显著下降,业务提交失败率回到正常水平。
死锁是并发写入的正常现象,完全消除不现实;规范更新顺序并给应用加可重试逻辑才是务实的做法。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。