MARK--2020年第一次事故
事故起因
某研发同事需要关联更新2600万数据量的表,考虑到单条语句更新会造成超大事务影响业务(预发布环境),因此将更新操作拆分成多个小批次处理(每次更新10万,休息5秒)。
通过运维平台跑起来就没管,运行半小时后想起来运维平台自动在脚本上增加事务,虽然进行拆分,但仍是在一个事务中处理,由于中间还有停顿,因此真个操作比单条SQL执行影响还严重。
在之前的类似操作中,通常会通过Python生成拼接好的SQL脚本并存成文件,如:
UPDATE `SUBJECT` AS T1 INNER JOIN course_category AS T2 ON T1.c_id=T2.ID SET T1.book_type_id=T2.book_type_id WHERE T2.book_type_id IS NOT NULL AND ((T1.book_type_id IS NULL) OR (T1.book_type_id<>T2.book_type_id)) AND T1.id>=0 and T1.ID<100000; SELECT SLEEP(5); UPDATE `SUBJECT` AS T1 INNER JOIN course_category AS T2 ON T1.c_id=T2.ID SET T1.book_type_id=T2.book_type_id WHERE T2.book_type_id IS NOT NULL AND ((T1.book_type_id IS NULL) OR (T1.book_type_id<>T2.book_type_id)) AND T1.id>=100000 and T1.ID<200000; SELECT SLEEP(5);
再通过mysql命令使用-vvv参数来执行,默认采用auto_commit的方式,因此每个SQL语句一个事务,影响范围小,并通过SLEEP来控制单位时间内的数据更新,防止主从延迟。
自动化运维平台的执行DML思路:
使用mysql命令行执行SQL文件过程中,在SQL文件开头和结尾增加事务控制BEGIN+COMMIT,如果未指定--force参数,则执行过程中遇到执行异常会断开,事务会自动进行回滚,降低DML操作执行异常带来的风险。
由于考虑不充分,直接将拆分后的更新语句合并提交给自动化运维平台处理,导致上面描述的异常。
虽然在发现问题后第一时间KILL操作,但由于事务开始时间较长且已更新大量数据,导致事务需要很长时间进行事务回滚。
事务回滚过程中,在SHOW PROCESSLIST输出结果中查询不到相关信息,但可以通过SHOW ENGINE INNODB STATUS来查看到事务信息:
---TRANSACTION 1104494899, ACTIVE 2075 sec rollback ROLLING BACK 794517 lock struct(s), heap size 70754512, 17094753 row lock(s), undo log entries 7589902 MySQL thread id 1874581, OS thread handle 139785461737216, query id 30036445 192.168.5.47 xxxx_root
在事务中持有的锁资源需要等事务提交或回滚后才释放,因此如果此时再次执行类似语句,会发现存在锁等待:
---TRANSACTION 1104511461, ACTIVE 47 sec starting index read mysql tables in use 2, locked 2 LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 1879058, OS thread handle 139785472575232, query id 30049665 192.168.5.47 dada_root Sending data UPDATE `SUBJECT` AS T1 INNER JOIN course_category AS T2 ON T1.c_id=T2.ID SET T1.book_type_id=T2.book_type_id WHERE T2.book_type_id IS NOT NULL AND ((T1.book_type_id IS NULL) OR (T1.book_type_id<>T2.book_type_id)) AND T1.id>=0 and T1.ID<100000
监控漏洞
在监控系统方面,主要关注长期未提交事务和执行时间较长SQL,对开启事务时间较长和持有行锁较多的事务缺乏监控,导致问题没有第一时间发现。
总结
开年没几天就踩坑,虽然是预发布环境不影响生产,但仍需要认真自我反思,避免后面出现类似问题。