MySQL8.0的參數event_scheduler默認是ON,請注意一些坑

event_scheduler是什麼?

event_scheduler是什麼MySQL定時器的開關,相似於windows操做系統的定時任務的概念,指定某個時間點執行一次定時任務,或者每隔一段時間循環執行定時任務。java

這個東西有企業在用麼?

看了幾個企業的開發規範,都沒有說起須要禁用event功能,因此event功能是容許開發人員使用的。(不過,我相信java開發人員更喜歡用java定時器。)也許是由於mysql默認就不啓用event功能嘛,默認就沒法用event,開發規範就不說起這東西啦。何況能夠經過用戶權限控制來控制開發人員是否可使用event。因此從我手上的幾家公司的開發規範裏,並不能夠實際看出你們有沒有使用event_scheduler這個功能。因爲MySQL8.0默認是開啓event_scheduler功能了,我認爲咱們仍是有必要討論一下event到底有沒有坑?mysql

我能想到的坑——主從複製的坑

首先這個事情並無實際發生在我生產環境,是人爲想出來的一種場景。sql

準備:
兩個MySQL8.0數據庫實例
mysql3308
mysql33081

配置文件不顯示地指定默認值:
[root@192-168-199-198 mysql3308]# cat my.cnf |grep event_scheduler

MySQL8.0的默認值即爲:
mysql> show variables like '%event_scheduler%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.12 sec)

我給你們作了如下的測試。數據庫

1、在已有的主從環境下,創建一個重複插入的event。

主庫上執行
mysql> show variables like '%event_scheduler%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.12 sec)
create database fander;
use fander;
CREATE EVENT IF NOT EXISTS test
ON SCHEDULE EVERY 1 SECOND
ON COMPLETION PRESERVE
DO insert into fander.test values (1);

#這個event表示每一秒都往fander庫的test表插入一行值爲1的數據。

mysql> show create event test\G
*************************** 1. row ***************************
               Event: test
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
           time_zone: SYSTEM
        Create Event: CREATE DEFINER=`root`@`localhost` EVENT `test` ON SCHEDULE EVERY 1 SECOND STARTS '2019-01-23 14:55:19' ON COMPLETION PRESERVE ENABLE DO insert into fander.test values (1)
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

mysql> show tables;
Empty set (0.01 sec)
#我先不創建測試重複插入的test表。
從庫上執行
mysql> show variables like '%event_scheduler%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.12 sec)
mysql> use fander;
mysql> show create event test\G
*************************** 1. row ***************************
               Event: test
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
           time_zone: SYSTEM
        Create Event: CREATE DEFINER=`root`@`localhost` EVENT `test` ON SCHEDULE EVERY 1 SECOND STARTS '2019-01-23 14:55:19' ON COMPLETION PRESERVE DISABLE ON SLAVE DO insert into fander.test values (1)
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

有沒有發現問題?windows

  1. 主從環境的event_scheduler都是開啓的。這意味這從庫有可能會重複寫入數據。一部分數據來源於主庫的event的循環插入的複製,一部分數據來源於從庫自身的event的循環插入。測試

  2. 主從庫的Create Event語句不同?
    在create event時,event在主庫建立後,複製到從庫上是disable的狀態!因此MySQL在設計之初就考慮了這個問題。event在從庫是disable的,沒法執行,從而從庫不會發生寫入操做而致使數據不一致!操作系統

咱們進一步測試,是否是確實如何此。設計

主庫上執行
mysql> create table test (a int);
Query OK, 0 rows affected (0.04 sec)
mysql> select count(1) from test;
+----------+
| count(1) |
+----------+
|       52 |
+----------+
1 row in set (0.01 sec)
從庫上執行
mysql> select count(1) from test;
+----------+
| count(1) |
+----------+
|       52 |
+----------+
1 row in set (0.01 sec)

#注意,也能夠用對比gtid的方法查看從庫,發現從庫確實沒有自身數據寫入。code

結論是,在已有的主從環境下,創建一個重複插入的event,event不會在從庫上執行,不會有數據寫入,從而保證了數據的一致性。這種狀況下event的開啓沒有帶來坑。ci

2、在已有一個重複插入的event的主庫上,擴展創建一個從庫。

主庫:
mysql> show variables like '%event_scheduler%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.12 sec)
mysql> show create event test\G
*************************** 1. row ***************************
               Event: test
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
           time_zone: SYSTEM
        Create Event: CREATE DEFINER=`root`@`localhost` EVENT `test` ON SCHEDULE EVERY 1 SECOND STARTS '2019-01-23 14:55:19' ON COMPLETION PRESERVE ENABLE DO insert into fander.test values (1)
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.06 sec)

冷備的方法創建從庫。

mysql> show variables like '%event_scheduler%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.12 sec)
mysql> CHANGE MASTER TO
    ->   MASTER_HOST='localhost',
    ->   MASTER_USER='rpl_user',
    ->   MASTER_PASSWORD='password',
    ->   MASTER_PORT=3308,
    ->   master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.04 sec)

mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> use fander
Database changed
mysql> show create event test\G
*************************** 1. row ***************************
               Event: test
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
           time_zone: SYSTEM
        Create Event: CREATE DEFINER=`root`@`localhost` EVENT `test` ON SCHEDULE EVERY 1 SECOND STARTS '2019-01-23 14:55:19' ON COMPLETION PRESERVE ENABLE DO insert into fander.test values (1)
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

能夠發現主從庫的Create Event語句這時是如出一轍了。
下面接着測試。

主庫:
mysql>  select count(1) from test;
+----------+
| count(1) |
+----------+
|       14 |
+----------+
1 row in set (0.00 sec)

從庫:
mysql>  select count(1) from test;
+----------+
| count(1) |
+----------+
|       33 |
+----------+
1 row in set (0.00 sec)


mysql> show slave status\G
...
          Retrieved_Gtid_Set: 07b92486-64b0-11e8-b4cf-000c29c71881:501-561
            Executed_Gtid_Set: 07b92486-64b0-11e8-b4cf-000c29c71881:1-561,
59613f3a-1ee0-11e9-a9e7-000c29259487:1-13
...

以上測試用的是物理冷備。我測試在用邏輯備份主庫,擴展從庫後,狀況同樣。
結論是,在已有一個重複插入的event的主庫上,擴展創建一個從庫,會由於從庫也有這個event schedule,致使從庫重複執行insert語句。等於計劃任務從新執行了兩次!數據會形成不一致!

如何避免?

建議:
1.規範my.cnf模板,event_scheduler設置爲0,而不是採用官方默認值1。
2.從庫建議開啓read_only=1; 嚴格防止寫入。

擴展

若是平常備份時備份的是文章"一"狀況的從庫,那麼恢復數據庫後,event默認是disable的,是跑不了的。具體見下面:

[root@192-168-199-198 ~]# cat all2.sql |grep "EVERY 1 SECOND"
/*!50106 CREATE*/ /*!50117 DEFINER=`root`@`localhost`*/ /*!50106 EVENT `test` ON SCHEDULE EVERY 1 SECOND STARTS '2019-01-23 16:03:16' ON COMPLETION PRESERVE DISABLE ON SLAVE DO insert into fander.test values (1) */ ;;

你須要人手修改event讓其能夠跑。這也屬於一個坑吧。

相關文章
相關標籤/搜索