天天看點

初學MySQL—MySQL是如何保證資料不丢失的?binlog的寫入機制redo log的寫入機制

MySQL是如何保證資料不丢失的?

  • binlog的寫入機制
  • redo log的寫入機制

隻要redo log和binlog能夠持久化到磁盤中,就能確定MySQL在異常重新開機後,資料可以恢複。下面一起來了解下MySQL中binlog和redo log的寫入流程。

binlog的寫入機制

事務執行過程中,先把日志寫到binlog cache,事務送出的時候,再把binlog cache寫到binlog檔案中。

系統給binlog cache配置設定了一片記憶體,每個線程一個,參數binlog_cache_size用于控制單個線程内binlog cache所占記憶體的大小,如果超過這個參數規定的大小,就要暫存到磁盤中。

事務送出的時候,執行器把binlog cache的完整事務寫入到binlog中,并且清空binlog cache中。

初學MySQL—MySQL是如何保證資料不丢失的?binlog的寫入機制redo log的寫入機制

每個線程都有自己的binlog cache,共用同一份binlog檔案;上圖中的write就是把日志寫入到檔案系統的page cache,并沒有把資料持久化到磁盤中,是以速度很快;

圖中的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個事務後才fsnc;

sync_binlgo設定為N的風險是:如果主機發生異常重新開機,會丢失最近N個事務的binlog日志;

redo log的寫入機制

redo log存在三種狀态

初學MySQL—MySQL是如何保證資料不丢失的?binlog的寫入機制redo log的寫入機制
  1. 存在redo log buffer中,實體上是在MySQL程序記憶體中,就是圖中的紅色部分;
  2. 寫到磁盤(write),但是沒有持久化(fsync),實體上是在檔案系統的page cache裡面,也就是圖中的黃色部分;
  3. 持久化到磁盤,對應的是hard disk。也就是圖中的綠色部分;

為了控制 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有一個背景線程,每隔一秒,就會把redo log buffer中的日志,調用write寫到檔案系統的pagecache中,然後調用fsync持久化到磁盤中;

實際上,除了背景線程每秒一次的輪詢操作外,還有兩種場景會讓一個沒有送出的事務的redo log 寫入到磁盤:

  1. redo log buffer 占用的空間即将達到 innodb_log_buffer_size 一半的時

    候,背景線程會主動寫盤;

  2. 并行的事務送出的時候,順帶将這個事務的 redo log buffer 持久化到磁

    盤;

在兩階段送出的時候說過,時序上redo log先prepare,再寫binlog,最後再把redo log commit;

初學MySQL—MySQL是如何保證資料不丢失的?binlog的寫入機制redo log的寫入機制

上面的"寫binlog"是分成兩步的:

  1. 先把binlog從binlog cache中寫到磁盤上的binlog檔案;
  2. 調用fsync持久化;
初學MySQL—MySQL是如何保證資料不丢失的?binlog的寫入機制redo log的寫入機制

如果你的 MySQL 現在出現了性能瓶頸,而且瓶頸在 IO 上,可以通過哪些方法來提升性能呢?

  1. 設定 binlog_group_commit_sync_delay 和binlog_group_commit_sync_no_delay_count 參數,減少 binlog 的寫盤次數;基于“額外的故意等待”,雖然增加了語句的響應時間,但沒有丢失資料的風險;
  2. 将sync_binlog設定為大于1的值,常見範圍是100~1000,風險是主機停電時會丢失binlog日志;
  3. 将 innodb_flush_log_at_trx_commit 設定為 2。這樣做的風險是,主機掉電的時候會

    丢資料;

繼續閱讀