mysql对binlog的处理

--mysql对binlog的处理

------------------------2014/05/28

Binlog是mysql以二进制形式打印的日志,它默认不加密,不压缩。每个正常的binlog文件头部,有4个字节的标记,值为0xfe 0x62 0x69 0x6e。LOG_EVENT是binlog里的单位,即正常情况下binlog按照逐LOG_EVENT的形式增长。除去头部的标记,binlog就是一个LOG_EVENT的序列。每个LOG_EVENT都独立单元,没有互相引用的关系,它也有自己的二进制头部,主要是记录了时间戳、类型标记等描述信息。

Mysql把磁盘操作的实现封装在IO_CACHE结构里,这也方便了我们对binlog的研究和描述,后文如果没有特别说明,读写binlog与读写IO_CACHE的含义相同。

对于MYISAM表:只要语法和语义没有错误,MYSQL不等执行语句执行完,就会写binlog。如果binlog_format=statement对于复制而言就很危险,因为主库可能会将它执行到一半的时候cancel,然后这条语句却会在从库上完整的执行,造成主从不一致。

这是生产库上因为主库sql被abort后,从库停止复制,报出的错误信息:

 

Last_Error: Query partially completed on the master (error on master: 1317) and was aborted. There is a chance that your master is inconsistent at this point.
If you are sure that your master is ok, run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; .
Query: 'delete from log_fight_data where d_create< '2014-03-00 00:00:00''

 

对于INNODB表:commit后才会写binlog,如果语句被cancel,作为事务性引擎,会回滚,不会出现更新一半,也不会记binlog。

--可见使用innodb表相比myisam无事务的表来说,从很多方面来看都安全很多。

 

Q:  主库发送binlog,是使用内存里的copy吗?

A:  无法确定,很有可能是先从磁盘上读一份,然后发送。

 

Q: 既然mysql是先做数据操作、再写binlog,如果写binlog的时候失败,mysql又crash,数据怎么办?
A: 是由存储引擎决定数据。
  可以把mysql和它的存储引擎分开看,因为mysql只是一个框架,而不是一个实现。
  binlog是mysql自己的日志,而事务是由存储引擎本身保证的。
  以update为例,mysql做的事情简单分为:
  1. 修改数据update
  2. 写binlog
  注意此处的update和commit/rollback都由存储引擎实现,mysql只是站在逻辑的高度上理解这些操作。

对于innodb而言,会在提交后才开始写binlog,没提交的事务不会写binlog。然而即使是这样,innodb仍然无法保证

binlog和数据的一致性,因为innodb在写commit成功后crash,不能保证binlog被写入了磁盘。

把--innodb-support-xa设置为1,同时保证sync_binlog=1,才能保证innodb的binlog和数据一致。

实验

1. 证明对于innodb存储引擎,只有commit成功后才写日志。

mysql> show master logs;
+----------------+-----------+
| Log_name       | File_size |
+----------------+-----------+
| pri_bin.000010 |       165 |
| pri_bin.000011 |  16894474 |
| pri_bin.000012 |       698 |
| pri_bin.000013 |       307 |
+----------------+-----------+
4 rows in set (0.00 sec)

mysql> insert into t values(111);
Query OK, 1 row affected (0.00 sec)

mysql> show master logs;
+----------------+-----------+
| Log_name       | File_size |
+----------------+-----------+
| pri_bin.000010 |       165 |
| pri_bin.000011 |  16894474 |
| pri_bin.000012 |       698 |
| pri_bin.000013 |       307 |
+----------------+-----------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql> show master logs;
+----------------+-----------+
| Log_name       | File_size |
+----------------+-----------+
| pri_bin.000010 |       165 |
| pri_bin.000011 |  16894474 |
| pri_bin.000012 |       698 |
| pri_bin.000013 |       307 |
+----------------+-----------+
4 rows in set (0.00 sec)

 

2. 由于innodb的这种特性,是的在binlog_format在row和statement下有不同的锁表现。

STATEMENT模式:带有范围性的修改,锁全表。例如update t set id=XXX where statement; 例如insert ... select操作会锁定源表。

ROW模式:正常行级锁。

 

 

 

posted @ 2014-05-28 22:10  胡.杰  阅读(3116)  评论(0编辑  收藏  举报