定时任务是我们开发, 运维人员经常用到的, 比如 cron,job,schedule,events scheduler 等都是为了方便我们重复执行某项工作而无需人工参与而设计, 这里我要说的是 MySQL 数据库本身的定时任务, 即 events scheduler 的风险案例.
一, 现象描述
这里有一个从库出现数据不同步现象, 具体报错如下:
- Slave_IO_Running: Yes
- Slave_SQL_Running: No
- Last_SQL_Errno: 1032
- Last_SQL_Error: Could not execute Delete_rows event on table bs.dg_sale; Can't find record in'dg_sale', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log MySQL-bin.000079, end_log_pos 159513315
这个现象出现是由于主键问题导致数据删除失败, 进而引发数据同步错误.
二, 原因分析
出现上述错误比较常见的是从库做了一些删除操作, 然后数据同步的时候通过主键寻找条件删除的时候无法执行删除操作, 进而导致主从错误.
通过对比主库数据和从库数据发现表数据记录数都是 0, 然后自增值不同, 从库始终没有外部账户访问, 这里就有点懵逼了吧? 没错, 还有一种情况可能导致从库被操作, 那就是定时任务. 通过排查发现, 果然主库设有几个 events 事件, 其中有个定时任务就设计到这个表的多次查询, 删除, 插入等操作.
正常情况下主库创建 event schedule, 从库自动的将 event disable 掉, 如果切换需要手动 enable event scheduler, 如果搭建主从实现创建好的定时任务复制到从库, 从库的 scheduler 可能会被激活, 导致主从的 scheduler 都被执行.
三, 处理过程
1. 查看从库状态和错误代码信息.
2. 检查主库, 从库表数据信息, 表结构信息.
- show slave status \G
- show create table bs.dg_sale \G
- select count(1) from bs.dg_sale;
3. 分析产生错误的 binlog 信息.
主库:
- show binlog events in 'mysql-bin.000079' from 159512534 limit 10;
- mysqlbinlog --base64-output='decode-rows' --start-position=159512534 --stop-position=159512838 -vv MySQL-bin.000079>binlog.txt
4. 查看主库 / 从库 events scheduler 信息
show variables like 'event_scheduler';
- show events;
- select EVENT_SCHEMA,EVENT_NAME,STATUS ,EXECUTE_AT,INTERVAL_VALUE from events;
这里看到 events scheduler
5. 禁用从库的 events scheduler
set global event_scheduler=0; 或者在主创建的时候加入 DISABLE ON SLAVE
在从库 my.cnf 配置文件中加入 set global event_scheduler=0
6. 重新完成数据同步
四, 总结和知识扩展
含有 scheduler 事件的风险项:
1) 主从切换的时候, 新主库需要 enable scheduler events
2) 含有 scheduler 的数据库搭建从库, 需要特别注意从库的 scheduler events 需要被 disable
1. 创建 MySQL events scheduler
语法:
- CREATE [DEFINER = { user | CURRENT_USER }]
- EVENT
- [IF NOT EXISTS]
- event_name
- ON SCHEDULE schedule
- [ON COMPLETION [NOT] PRESERVE]
- [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'string']
- DO event_body;
- schedule:
AT timestamp [+ INTERVAL interval] ...
- | EVERY interval
- [STARTS timestamp [+ INTERVAL interval] ...]
- [ENDS timestamp [+ INTERVAL interval] ...]
- interval:
- quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
- WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
- DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
实例:
- CREATE EVENT myevent
- ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
- DO
- UPDATE myschema.mytable SET mycol = mycol + 1;
2. 删除 MySQL events scheduler
语法:
DROP EVENT [IF EXISTS] event_name
3. 更改 MySQL events scheduler
语法:
- ALTER [DEFINER = { user | CURRENT_USER }]
- EVENT event_name
- [ON SCHEDULE schedule] [ON COMPLETION [NOT] PRESERVE]
- [RENAME TO new_event_name] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'string'] [DO event_body]
实例:
- ALTER EVENT no_such_event
- ON SCHEDULE
- EVERY '2:3' DAY_HOUR;
五, 案例回放测试
名称 | 主库 | 备库 |
IP 地址 | 192.168.1.1 | 192.168.1.2 |
OS | RHEL6.6 | RHEL6.6 |
MySQL | 5.7.21-20 | 5.7.21-20 |
1. 部署主从 (略)
2. 检查主从 scheduer 是否开启 (mysqladmin var |grep event_scheduler)
主:
从:
3. 主库创建 schedure 相关信息
- (root:localhost:Fri Jul 27 14:32:52 2018)[dbtest]>create table t(id int primary key,name varchar(30));
- CREATE EVENT ev_test
- ON SCHEDULE EVERY 1 MINUTE STARTS '2018-07-27 15:58:00' ON COMPLETION PRESERVE ENABLE DO
- BEGIN
- insert into t values(1,'N1'),(2,'N2'),(3,'N3');
- END
4. 主从数据检查
show slave status \G
select * from t;
主从状态正常, 数据正常.
这里发现并无异常, 原因主从状态本身存在的情况下, 在主库新建 scheduler, 从库的 scheduler event 会被默认设置为 disable
主库:
(root:localhost:Fri Jul 27 16:29:12 2018)[dbtest]>show events;
从库:
(root:localhost:Fri Jul 27 16:29:49 2018)[dbtest]>show events;
5. 调整从库的 schedule 为 enable 状态
(root:localhost:Fri Jul 27 16:31:37 2018)[dbtest]>alter event ev_test enable;
Query OK, 0 rows affected (0.00 sec) 此时从库的 scheduer 也会被执行, 如果因为时间等原因的关系, 从库先执行了 scheduler events, 主库再执行然后传输 binlog 到从库再次执行会导致主从数据不一致, 进而导致复制失败, 这也就是为什么含有 scheduer event 的主从架构需要特别注意的原因了.
来源: http://www.linuxidc.com/Linux/2018-11/155305.htm