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)
我給你們作了如下的測試。數據庫
主庫上執行 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
主從環境的event_scheduler都是開啓的。這意味這從庫有可能會重複寫入數據。一部分數據來源於主庫的event的循環插入的複製,一部分數據來源於從庫自身的event的循環插入。測試
主從庫的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
主庫: 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讓其能夠跑。這也屬於一個坑吧。