MySQL事务-binlog与分布式事务
Posted 梁小明10000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL事务-binlog与分布式事务相关的知识,希望对你有一定的参考价值。
mysql事务-binlog与分布式事务
1、binlog_rows_query_log_events
这个参数默认是off
"root@localhost:mysql.sock [xx]>show variables like '%binlog_rows_query_log_events%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| binlog_rows_query_log_events | OFF |
+------------------------------+-------+
1 row in set (0.00 sec)
"root@localhost:mysql.sock [xx]>flush binary logs;
Query OK, 0 rows affected (0.05 sec)
"root@localhost:mysql.sock [xx]> create table test_bin_2 (a int);
Query OK, 0 rows affected (0.06 sec)
"root@localhost:mysql.sock [xx]> insert into test_bin_2 values(1),(2);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
"root@localhost:mysql.sock [xx]>commit;
Query OK, 0 rows affected (0.00 sec)
"root@localhost:mysql.sock [xx]>show master status;
+------------+----------+--------------+------------------+--------------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------+----------+--------------+------------------+--------------------------------------------------+
| bin.000040 | 622 | | | 790536c7-1936-11e8-a811-005056ad8986:1-101579736 |
+------------+----------+--------------+------------------+--------------------------------------------------+
1 row in set (0.00 sec)
"root@localhost:mysql.sock [xx]>show binlog events in "bin.000040";
+------------+-----+----------------+-----------+-------------+-----------------------------------------------
----------------------------+| Log_name | Pos | Event_type | Server_id | End_log_pos | Info
|+------------+-----+----------------+-----------+-------------+-----------------------------------------------
----------------------------+| bin.000040 | 4 | Format_desc | 11 | 123 | Server ver: 5.7.17-log, Binlog ver: 4
|| bin.000040 | 123 | Previous_gtids | 11 | 194 | 790536c7-1936-11e8-a811-005056ad8986:1-1015797
34 || bin.000040 | 194 | Gtid | 11 | 259 | SET @@SESSION.GTID_NEXT= '790536c7-1936-11e8-a
811-005056ad8986:101579735' || bin.000040 | 259 | Query | 11 | 360 | use `xx`; create table test_bin_2 (a int)
|| bin.000040 | 360 | Gtid | 11 | 425 | SET @@SESSION.GTID_NEXT= '790536c7-1936-11e8-a
811-005056ad8986:101579736' || bin.000040 | 425 | Query | 11 | 495 | BEGIN
|| bin.000040 | 495 | Table_map | 11 | 546 | table_id: 274 (xx.test_bin_2)
|| bin.000040 | 546 | Write_rows | 11 | 591 | table_id: 274 flags: STMT_END_F
|| bin.000040 | 591 | Xid | 11 | 622 | COMMIT /* xid=82 */
|+------------+-----+----------------+-----------+-------------+-----------------------------------------------
-- 只能看到页的变化
现在设置为on
"root@localhost:mysql.sock [xx]>set binlog_rows_query_log_events=1;
Query OK, 0 rows affected (0.00 sec)
"root@localhost:mysql.sock [xx]>show variables like "binlog_rows_query_log_events";
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| binlog_rows_query_log_events | ON |
+------------------------------+-------+
1 row in set (0.00 sec)
"root@localhost:mysql.sock [xx]> insert into test_bin_2 values(3),(4);
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
"root@localhost:mysql.sock [xx]> commit;
Query OK, 0 rows affected (0.00 sec)
"root@localhost:mysql.sock [xx]>show binlog events in "bin.000040";
+------------+-----+----------------+-----------+-------------+-----------------------------------------------
----------------------------+| Log_name | Pos | Event_type | Server_id | End_log_pos | Info
|+------------+-----+----------------+-----------+-------------+-----------------------------------------------
----------------------------+| bin.000040 | 4 | Format_desc | 11 | 123 | Server ver: 5.7.17-log, Binlog ver: 4
|| bin.000040 | 123 | Previous_gtids | 11 | 194 | 790536c7-1936-11e8-a811-005056ad8986:1-1015797
34 || bin.000040 | 194 | Gtid | 11 | 259 | SET @@SESSION.GTID_NEXT= '790536c7-1936-11e8-a
811-005056ad8986:101579735' || bin.000040 | 259 | Query | 11 | 360 | use `xx`; create table test_bin_2 (a int)
|| bin.000040 | 360 | Gtid | 11 | 425 | SET @@SESSION.GTID_NEXT= '790536c7-1936-11e8-a
811-005056ad8986:101579736' || bin.000040 | 425 | Query | 11 | 495 | BEGIN
|| bin.000040 | 495 | Table_map | 11 | 546 | table_id: 274 (xx.test_bin_2)
|| bin.000040 | 546 | Write_rows | 11 | 591 | table_id: 274 flags: STMT_END_F
|| bin.000040 | 591 | Xid | 11 | 622 | COMMIT /* xid=82 */
|| bin.000040 | 622 | Gtid | 11 | 687 | SET @@SESSION.GTID_NEXT= '790536c7-1936-11e8-a
811-005056ad8986:101579737' || bin.000040 | 687 | Query | 11 | 757 | BEGIN
|| bin.000040 | 757 | Rows_query | 11 | 817 | # insert into test_bin_2 values(3),(4)
|| bin.000040 | 817 | Table_map | 11 | 868 | table_id: 274 (xx.test_bin_2)
|| bin.000040 | 868 | Write_rows | 11 | 913 | table_id: 274 flags: STMT_END_F
|| bin.000040 | 913 | Xid | 11 | 944 | COMMIT /* xid=88 */
通过信息可以看到多了Rows_query,可以看到对应着SQL信息
2、ROW
1. 当写入的数据量较小时,ROW和Statement所占用的空间差不多;
2. 当写入的数据量较大的时候(比如导入数据,
或者批量操作时[update tb set a=a+1;]),ROW要记录每行的变化,所以比较占用空间。
3. 且写入数据量很大时,ROW格式下,commit会比较耗时间,因为他还要写binlog( binlog在提交时才写入 )
假设更新一张几百万的表,产的 binlog 可能会有几百兆,当 commit 时,写入的数据量就是几百兆,所以会有 “ 阻塞 ” 等待的效果。
但其实是在写 binlog 到磁盘而已。
上面这些结论,大家可以通过实验去验证哦。
3、binlog_cache
binlog默认写入到 binlog_cache 中
"root@localhost:mysql.sock [xx]>show variables like "binlog_cache_size";
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| binlog_cache_size | 32768 | -- 默认为32K(内存中),线程级别的变,别设置的太大
+-------------------+-------+
1 row in set (0.00 sec)
"root@localhost:mysql.sock [xx]>show global status like "binlog%";
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Binlog_cache_disk_use | 0 |-- 记录了使用临时文件写二进制日志的次数(做监控需要关注这个)
| Binlog_cache_use | 6 |-- 记录了使用缓冲写二进制日志的次数
| Binlog_stmt_cache_disk_use | 0 |
| Binlog_stmt_cache_use | 3 |
+----------------------------+-------+
4 rows in set (0.00 sec)
写日志本来就挺慢的,现在cache写不下,再写入磁盘,然后再写binlog,就是两次写磁盘,就更慢了。
如果参数 Binlog_cache_disk_use 次数很多,
就要看一下 binlog_cache_size 设置是否太小 ,
或者事物本身是否太大 MySQL使用在OLTP的场景下,应该是很快速的小事物。
如果有大的事物,应该把大的事物拆成小事物去执行。
4、 binlog与redo的一致性(深入理解,后面会和复制有关)
使用内部分布式事物来保证一致性
在 commit 时( 无论用户自己入,或者系统自动添加 ),会有如下几个步骤:
(1)InnoDB 层 写 prepare log
写的还是redo file (或者就是redo log,只是内容不一样,这里不是记录页的变化了)
写入的是 xid ( 事物 id , show binlog events in “bin.000056”)
准确的说, xid 是写在 undo 页上的(后面会提到)
(2)MySQL 层 写 binlog
(3)InnoDB 层 写 commit log (这里同样也是redo log file)
(1)假设,如果没有第一步的 prepare log ,而是直接写第二步的 MySQL binlog ,以及接着写第三步的 InnoDB commit log :
此时假设出现 binlog写入成功 ,而 commit log(redo)写入失败 的情况( 比如宕机 ),
那随后机器重启时 恢复 时,就会对该事物 回滚 ;
万一此时的 binlog 已经传递到了 slave 机器上,且 slave上commit 了。
那此时 主从就不一致 了(Master 上回滚了 )
(2)现在有 prepare log 了以后, prepare log写入成功 ,假设还是 binlog写入成功 ,而 commit log(redo)写入失败 的情况下;
此时事物恢复的时候, 检查到prepare log写入成功,binlog写入成功 ,那就直接 commit 了( 可以理解成补了那次失败的 commit),
而不管commit log是否写入成功 了。
(3)如果 prepare log写入成功 , binlog写入失败 了,那恢复时,也会回滚
(4)如果 没开binlog ,就没有第一和第二步, 只写第三步的commit log ,恢复的时候没有commit log,就会回滚。
注意:
一个事物在prepare log中写入成功,在binlog中写入成功,那就必须要提交 (commit)
用户/系统 commit ===> redo file( prepare log) ===> binlog ===> redo file( commit log)
xid 即写入prepare log 中,也会写入到binlog 中,
当恢复时,会对比一下某个 xid 在两个文件中是否都存在,如果都存在,该xid对应的事物才会提交
5、分布式事务
终端1:
"root@localhost:mysql.sock [xx]> create table test_xa_1(a int primary key);
Query OK, 0 rows affected (0.05 sec)
"root@localhost:mysql.sock [xx]>xa start 'A'; -- 开始一个分布式事物A,不是传统的begin。而是 xa start
Query OK, 0 rows affected (0.00 sec)
"root@localhost:mysql.sock [xx]> insert into test_xa_1 values(10);
Query OK, 1 row affected (0.00 sec)
"root@localhost:mysql.sock [xx]>xa end 'A'; -- 结束一个分布式事物A,此时并未提交
Query OK, 0 rows affected (0.00 sec)
"root@localhost:mysql.sock [xx]>xa prepare 'A'; -- 两阶段事物- prepare
Query OK, 0 rows affected (0.01 sec)
"root@localhost:mysql.sock [xx]>xa recover; -- 查看分布式事物
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
| 1 | 1 | 0 | A |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)
终端2:
"root@localhost:mysql.sock [xx]> select * from test_xa_1; -- 虽然在会话1中已 end 了,但是其实在会话2中是看不到的,符合ACID
Empty set (0.00 sec)
"root@localhost:mysql.sock [xx]>
终端1:
"root@localhost:mysql.sock [xx]> xa commit 'A'; -- xa commit 才是提交分布式事物
Query OK, 0 rows affected (0.01 sec)
终端2:
"root@localhost:mysql.sock [xx]> select * from test_xa_1;
+----+
| a |
+----+
| 10 |
+----+
1 row in set (0.00 sec)
解释如下:
XA START xid # 开启一个分布式事物
XA END xid # 结束一个分布式事物
XA PREPARE xid # 将分布式事物变成prepare状态
XA COMMIT xid # 提交一个分布式事物
XA ROLLBACK xid # 回滚一个分布式事物
XA RECOVER # 查看分布式事物
备注:个人学习整理,仅用于学习,如有侵权,联系马上删除!
以上是关于MySQL事务-binlog与分布式事务的主要内容,如果未能解决你的问题,请参考以下文章