为什么有时候binlog文件会很大于max_binlog_size以及max_binlog_cache_size
问题描述
线上一个很有意思的现象,发现binlog文件大小是15g,查看了参数是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