問題描述
線上一個很有意思的現象,發現binlog文件大小是15G,查看了參數max_binlog_size
是1073741824[1G], max_binlog_cache_size是21474836480[20G]。那么為什么會文件大小會超過max_binlog_file_size的設置。這個問題比較好理解,如果是大事務呢?那么這里有一個小問題,binlog里面是以event為單位來記錄的,那么事務有可能跨binlog嗎?使用BEGIN;***;***;commit進行測試
第二個問題,以上面的設置為例,在文件快到1G的時候,如果來了一個大事務,這個大事務接近20G,那么是不是可以任務binlog文件的最大可能值是接近1G+20G=21G呢,因為超過max_binlog_cache_size就會報錯了。這個也是可以測試下的。
實驗證明
問題1:實驗測試
root@test10:39:24>set global max_binlog_size=4096; root@test10:48:23>begin; Query OK, 0 rows affected (0.00 sec) root@test10:48:39>insert into testb select * from testa limit 32; Query OK, 32 rows affected (0.00 sec) Records: 32 Duplicates: 0 Warnings: 0 root@test10:49:05>insert into testb select * from testa limit 32; Query OK, 32 rows affected (0.00 sec) Records: 32 Duplicates: 0 Warnings: 0 root@test10:49:10>insert into testb select * from testa limit 32; Query OK, 32 rows affected (0.00 sec) Records: 32 Duplicates: 0 Warnings: 0 root@test10:49:14>insert into testb select * from testa limit 32; Query OK, 32 rows affected (0.00 sec) Records: 32 Duplicates: 0 Warnings: 0 root@test10:49:18>commit; Query OK, 0 rows affected (0.00 sec)
# at 3994 -- 上一個event結束的地方
#190130 10:49:14 server id 21036055 end_log_pos 4064 CRC32 0x64e8a1c6 Rows_query
# insert into testb select * from testa limit 32
# at 4064
#190130 10:49:14 server id 21036055 end_log_pos 4113 CRC32 0x7ef21b8c Table_map: `test`.`testb` mapped to number 11496
# at 4113
#190130 10:49:14 server id 21036055 end_log_pos 4692 CRC32 0xfc3f78bd Write_rows: table id 11496 flags: STMT_END_F -- 這已經是下一個insert 語句了,在一個binlog文件中,說明binlog是以事務為單位來進行切割的,不是事務里面的單個sql語句,這也是比較好理解的,因為事務只有執行完了, 才能在內存中生成完整的binlog,才存在刷盤的操作。
問題2:實驗測試
root@test11:01:52>set global max_binlog_cache_size=4096;
root@test11:15:20>insert into testb select * from testb limit 200; -- 3.9K Jan 30 11:15 mysql-bin.003691
root@test11:15:28>insert into testb select * from testb limit 460; -- 12K Jan 30 11:16 mysql-bin.003691
root@test11:17:34>insert into testb select * from testb limit 470; -- 最大就是在460到470之間
ERROR 1197 (HY000): Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
這個實驗說明binlog文件最大應該是max_binlog_size + max_binlog_cache_size的和,但是
max_binlog_cache_size在文件大小上可能比實際設置的值要大,見下問題。所有嚴格來講應該是大於兩者的和的。
在實驗的過程中遇見一個新問題
root@test11:07:21>insert into testb select * from testb limit 400;
# at 331
#190130 11:07:32 server id 21036055 end_log_pos 402 CRC32 0x62bb0a5e Rows_query
# insert into testb select * from testb limit 400
# at 402
#190130 11:07:32 server id 21036055 end_log_pos 451 CRC32 0x3177b22e Table_map: `test`.`testb` mapped to number 11496
# at 451
#190130 11:07:32 server id 21036055 end_log_pos 7286 CRC32 0x35efff16 Write_rows: table id 11496 flags: STMT_END_F
能正常插入證明內存中產生的binlog應該是小於4096的,但是實際在binlog中看見的確實7286,明顯是比4094大的,為啥會這樣呢,在從內存中把binlog落盤的過程中做了什么處理嗎?
root@test11:21:01>show create table testb\G *************************** 1. row *************************** Table: testb Create Table: CREATE TABLE `testb` ( `a` bigint(20) DEFAULT NULL, `b` bigint(20) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 1 row in set (0.00 sec)
root@test11:24:10>select version();
+---------------+
| version() |
+---------------+
| 5.7.21-21-log |
+---------------+
1 row in set (0.00 sec)
以上是表結構以及MySQL的版本
如有任何問題,歡迎指正。
參考文獻:
https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_max_binlog_size