MySQL 怎麼保證資料不丟?

2021-09-21 18:36:57 字數 2582 閱讀 7393

mysql怎麼保證資料不丟?

redo log 的寫入流程是怎麼樣的,如何保證 redo log 真實地寫入了磁碟 ?

binlog的寫入邏輯:事務執行過程中,先把日誌寫到 binlog cache,事務提交的時候,再把 binlog cache 寫到 binlog 檔案中。

乙個事務的binlog是不能被拆開的,因此不論這個事務多大,也要確保一次性寫入。

系統給 binlog cache 分配了一片記憶體,每個執行緒乙個,引數binlog_cache_size 用於控制單個執行緒內 binlog cache 所佔記憶體的大小。 如果超過了這個引數規定的大小, 就要暫存到磁碟。 

事務提交的時候,執行器把 binlog cache 裡的完整事務寫入到 binlog 中,並清空 binlog cache。

每個執行緒有自己 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 個事務後才 fsync。

一般不建議將這個引數設成 0,比較常見的是將其設定為 100~1000 中的某個數值。對應的風險是:如果主機發生異常重啟,會丟失最近 n 個事務的 binlog 日誌。

redo log 三種狀態:

1.存在 redo log buffer 中,物理上是在 mysql 程序記憶體中,就是圖中的紅色部分;

2.寫到磁碟 (write),但是沒有持久化(fsync),物理上是在檔案系統的 page cache 裡面,也就是圖中的黃色部分;

3.持久化到磁碟,對應的是 hard disk,也就是圖中的綠色部分。

innodb 提供了 innodb_flush_log_at_trx_commit 引數,控制 redo log 的寫入策略,有三種可能取值:

1.設定為 0 的時候,表示每次事務提交時都只是把 redo log 留在 redo log buffer 中 ;

2.設定為 1 的時候,表示每次事務提交時都將 redo log 直接持久化到磁碟;

3.設定為 2 的時候,表示每次事務提交時都只是把 redo log 寫到 page cache。

事務執行中間過程的 redo log 也是直接寫在 redo log buffer 中的,這些 redo log 也會被後台執行緒一起持久化到磁碟。也就是說,乙個沒有提交的事務的 redo log,也是可能已經持久化到磁碟的。

還有兩種場景會讓乙個沒有提交的事務的 redo log 寫入到磁碟中:

一種是,redo log buffer 占用的空間即將達到 innodb_log_buffer_size 一半的時候,後台執行緒會主動寫盤。

另一種是,並行的事務提交的時候,順帶將這個事務的 redo log buffer 持久化到磁碟。假設乙個事務 a 執行到一半,已經寫了一些 redo log 到 buffer 中,這時候有另外乙個執行緒的事務 b 提交,如果 innodb_flush_log_at_trx_commit 設定的是 1,那麼按照這個引數的邏輯,事務 b 要把 redo log buffer 裡的日誌全部持久化到磁碟。這時候,就會帶上事務 a 在 redo log buffer 裡的日誌一起持久化到磁碟。

組提交(group commit)機制:

wal 機制主要得益於兩個方面:

redo log 和 binlog 都是順序寫,磁碟的順序寫比隨機寫速度要快;

組提交機制,可以大幅度降低磁碟的 iops 消耗。

如果你的 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。這樣做的風險是,主機掉電的時候會丟資料。

不建議把 innodb_flush_log_at_trx_commit 設定成 0。因為把這個引數設定成 0,表示 redo log 只儲存在記憶體中,這樣的話 mysql 本身異常重啟也會丟資料,風險太大。而 redo log 寫到檔案系統的 page cache 的速度也是很快的,所以將這個引數設定成 2 跟設定成 0 其實效能差不多,但這樣做 mysql 異常重啟時就不會丟資料了,相比之下風險會更小。

23 MySQL是怎麼保證資料不丟的?

只要保證redo log和binlog持久化到磁碟,就能確保mysql異常重啟後資料可以恢復。binlog的寫入邏輯比較簡單 事務執行過程中,先把日誌寫到binlog cache,事務提交的時候,再把binlog cache寫到binlog檔案中。系統給binlog cache分配了一片記憶體,每個...

23 MySQL是怎麼保證資料不丟的?

其實,binlog 的寫入邏輯比較簡單 事務執行過程中,先把日誌寫到 binlog cache,事務提交的時候,再把 binlog cache 寫到 binlog 檔案中。乙個事務的 binlog 是不能被拆開的,因此不論這個事務多大,也要確保一次性寫入。這就涉及到了 binlog cache 的儲...

Kafka如何保證不丟訊息

生產者 producer 呼叫send方法傳送訊息之後,訊息可能因為網路問題並沒有傳送過去。訊息到partition的時候,會分配乙個offset,消費者拉取某個分割槽的訊息後,會自動提交offset,如果這部分訊息還沒有消費,突然掛掉了,這個時候這部分訊息就丟失了 kafka中partition分...