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模式:正常行級鎖。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM