MySQL如何保證數據不丟

Binlog寫入機制

  事務執行過程中,先把日誌寫到binlog cache,事務提交的時候,再把binlog cache寫到binlog文件中。系統給binlog cache分配了一片內存,每個線程一個,參數 binlog_cache_size用於控制單個線程內binlog cache所佔內存的大小。如果超過了這個參數規定的大小,就要暫存到磁盤。
  Binlog的寫入有兩個階段:
  1. write,指的是指把日誌寫入到文件系統的page cache,並沒有把數據持久化到磁盤,所以速度比較快。
  2. fsync,是將數據持久化到磁盤的操作。一般情況下,fsync佔用磁盤的IOPS。
  write 和fsync的時機,是由參數sync_binlog控制的:
  1. sync_binlog=0的時候,表示每次提交事務都只write,不fsync;
  2. sync_binlog=1的時候,表示每次提交事務都會執行fsync;
  3. sync_binlog=N(N>1)的時候,表示每次提交事務都write,但累積N個事務後才fsync。
  在實際的業務中,一般將這個參數設置爲100-1000,注意這時如果主機異常重啓,會有丟失日誌的風險。

Redo log寫入機制

  與binlog類似,爲了控制redo log的寫入策略,InnoDB提供了innodb_flush_log_at_trx_commit參數,它有三種可能取值:
  1. 設置爲0的時候,表示每次事務提交時都只是把redo log留在redo log buffer中;
  2. 設置爲1的時候,表示每次事務提交時都將redo log直接持久化到磁盤;
  3. 設置爲2的時候,表示每次事務提交時都只是把redo log寫到page cache。
  InnoDB通過後臺線程的方式,每隔1秒,就把redo log buffer中的日誌,調用write寫到文件系統的page cache,然後調用fsync持久化到磁盤。

組提交技術

  爲了減少刷盤佔用的IOPS,MySQL提供了一種組提交技術,拖延write與fsync之間的時間,每次fsync的時候都將一組寫到磁盤上~(不僅僅是當前事務),兩階段提交的實質性圖如下所示:
在這裏插入圖片描述
  一般MySQL的備庫會設置成read-only,以避免發生數據不一致等情況,注意這個read-only對於超級用戶無效(binlog可以正常執行),事務日誌同步的過程如下
  1. 在備庫B上通過change master命令,設置主庫A的IP、端口、用戶名、密碼,以及要從哪個位置開始請求binlog,這個位置包含文件名和日誌偏移量。
  2. 在備庫B上執行start slave命令,這時候備庫會啓動兩個線程,分別爲io_thread和sql_thread。其中io_thread負責與主庫建立連接。
  3. 主庫A校驗完用戶名、密碼後,開始按照備庫B傳過來的位置,從本地讀取binlog,發給B。
  4. 備庫B拿到binlog後,寫到本地文件,稱爲中轉日誌(relay log)。
  5. sql_thread讀取中轉日誌,解析出日誌裏的命令,並執行。

Binlog的格式

  一共有三種格式
  Statement:
  這種格式直接記錄操作語句,如果使用limit時,可能會發生在主庫和從庫上選擇不同索引而造成的查詢結果不一致的問題
  Row:
  記錄具體操作的rowID,不會出現主從不一致的問題。對於插入會記錄具體插入內容和插入的行,對於刪除也會記錄全部刪除內容,所以可以用於恢復數據,但是佔用空間較大。
  Mixed:
  這種格式是上面兩種進行混合,由MySQL去判斷是不是會發生主從不一致,進而選擇合適的binlog格式
在生產中,大部分會使用雙master,這時要小心binlog的循環複製問題,可以通過日誌中記錄的server id來解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章