MySQL 大事务刷binlog cache引发的DML阻塞问题解析
1. 从阿里云监控案例说起DML阻塞的诡异现象上周排查一个线上问题阿里云监控突然报警显示数据库响应时间飙升。打开SQL洞察一看发现特别诡异的现象同一时间点有的UPDATE语句执行耗时2秒有的却卡了200多秒。更奇怪的是这些慢查询的SQL本身都非常简单就是普通的单行更新。这让我想起去年处理过的一个类似案例。当时有个报表生成任务需要更新百万级数据跑着跑着整个数据库的写入操作都变慢了。最后发现是那个大事务在提交时把其他事务的提交请求全堵住了。这次的问题会不会也是同样的原因2. 大事务如何成为binlog系统的堵车王2.1 binlog cache的工作机制MySQL有个很关键的设计所有DML操作产生的变更会先写入线程私有的binlog cache等到事务提交时才会批量刷到共享的binlog文件。这个cache大小由binlog_cache_size控制默认32KB。我做过一个测试创建一个包含10万行INSERT的事务当cache写满时MySQL会创建临时文件来存储溢出的binlog event。这个切换过程本身就会带来性能抖动但更严重的问题还在后面。2.2 提交阶段的锁竞争重点来了当多个事务同时提交时它们需要把各自cache里的event写入binlog文件。为了保证事务event的连续性MySQL用了一把mutex锁LOCK_log来同步这个写入过程。想象一下早高峰的地铁闸机所有人必须排队刷卡通过。如果前面有个背着超大行李的乘客大事务后面的人小事务就只能干等着。这就是为什么我们会在监控中看到大量会话处于waiting for handler commit状态。3. 为什么有些DML没被阻塞3.1 显式事务的障眼法细心的同学可能发现了监控中有些DML执行时间显示正常。其实这是个假象——这些操作使用了BEGIN/COMMIT的显式事务。在没有执行COMMIT前它们根本不会去抢那把锁。我做过一个对比实验-- 场景1自动提交模式 UPDATE users SET score100 WHERE id1; -- 立即刷binlog -- 场景2显式事务 BEGIN; UPDATE users SET score100 WHERE id1; -- 不刷binlog COMMIT; -- 这时才竞争锁3.2 binlog时间戳的陷阱更迷惑的是binlog里记录的时间。显式事务的COMMIT时间戳是获取锁的时刻不是执行完成的时刻。就像你取号等位时小票上打印的是取号时间不是实际入座时间。这会导致监控数据出现时间倒流的假象。4. 生产环境诊断实战4.1 监控指标三件套根据实战经验我总结出三个关键监控项活跃事务视图重点关注执行时间超过30秒的事务InnoDB状态查看锁等待情况SHOW ENGINE INNODB STATUS系统负载特别是IO等待和上下文切换次数阿里云案例中就是通过活跃事务监控发现有个UPDATE已经执行了7分钟同时存在7个产生1GB级binlog的大事务。4.2 慢日志分析技巧如果没有商业监控工具可以用这个技巧抓凶手-- 查看长时间未提交的事务 SELECT * FROM information_schema.innodb_trx WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) 60; -- 抓取异常的COMMIT语句 SELECT * FROM mysql.slow_log WHERE sql_text LIKE %COMMIT% AND query_time 5;5. 六种解决方案的优劣对比5.1 配置调优方案方案优点缺点适用场景增大binlog_cache_size减少临时文件使用内存消耗大频繁出现大事务设置binlog_group_commit_sync_delay合并刷盘操作增加少量延迟高并发小事务场景启用binlog_order_commits减少锁持有时间对大事务帮助有限混合事务负载5.2 架构改造方案分片处理是我在电商项目中验证过的最有效方案。把那个百万级更新的报表任务拆分成按ID范围分片的100个小事务每个事务只处理1万条数据。虽然总执行时间变长了但系统整体吞吐量提升了8倍。另一个取巧的办法是异步提交让大事务在业务低峰期执行或者通过消息队列异步处理。不过这个方案要特别注意数据一致性问题。6. 特别注意事项binlog_cache_size不是越大越好设置过大会导致内存浪费。建议通过Binlog_cache_disk_use监控临时文件使用频率来调整监控隐藏成本大事务除了阻塞问题还会导致主从延迟加剧备份时间延长崩溃恢复时间变长云数据库的特殊性阿里云RDS的SQL洞察能捕获到原生MySQL看不到的细节比如精确到微秒级的锁等待时间最近遇到一个典型案例某游戏公司的排行榜更新任务每天凌晨会把玩家数据全量刷一遍。改成增量更新分批次提交后数据库凌晨的CPU使用率从90%降到了40%。这种优化往往需要开发者和DBA紧密配合——开发同学可能根本不知道自己的代码会引发数据库级联故障。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2484913.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!