前言
本文介紹 MySQL 的 binlog 和 redo log 寫入機制和刷盤策略,以及如何提升 MySQL 的 IO 性能,
binlog 的寫入機制
binlog 的寫入流程是:
先將日志寫入到 binlog cache 中,然后再 write page cache 到磁盤(檔案系統向內核申請的一塊記憶體空間,當 MySQL 行程重啟時,不影響這塊空間),最后 fsync 到磁盤,
每個事務對應的 binlog 是不能拆開的,所以必須一次性保存,每個執行緒有自己的 binlog cache,通過 binlog_cache_size 引數設定,但是多個執行緒共享同一個 binlog 檔案,如果 binlog cache 存不下,就會存到磁盤中,
binlog 的刷盤策略,即 write 和 fsync 的時機,是由引數 sync_binlog 控制的:
-
sync_binlog=0的時候,表示每次提交事務都只write,不fsync;
-
sync_binlog=1的時候,表示每次提交事務都會執行fsync;
-
sync_binlog=N(N>1)的時候,表示每次提交事務都write,但累積N個事務后才fsync,
一般不會將 sync_binlog 設定為 0,那樣可能會丟失大量的日志,為了提高 IO 性能,可能會將 sync_binlog 設定為 100 ~ 1000 的值,這樣只會丟失最近的 N 條日志,
redo log 的寫入機制
redo log 的寫入流程:
先將日志記錄在 redo log buffer 中,然后再 write page cache,最后 fsync 到磁盤,并且,有一個后臺執行緒,每隔一段時間就會將 redo log buffer 同步到磁盤,(可能事務未提交,但也同步到磁盤的情況)
redo log 的刷盤策略,由 InnoDB 提供了 innodb_flush_log_at_trx_commit 引數控制,它有三種可能取值:
-
設定為0的時候,表示每次事務提交時都只是把redo log留在redo log buffer中;
-
設定為1的時候,表示每次事務提交時都將redo log直接持久化到磁盤;
-
設定為2的時候,表示每次事務提交時都只是把redo log寫到page cache,
注意,如果把 innodb_flush_log_at_trx_commit 設定為 1,那么 redo log 在兩階段提交的第一個 prepare 階段就會刷盤,第二個 commit 階段只會 write page cache,
雙“1”配置
MySQL 的雙“1”配置指的就是 innodb_flush_log_at_trx_commit=1 和 sync_binlog=1 ,即一次事務提交,需要等待兩次 fsync,
組提交(group commit)
這時候,你可能有一個疑問,這意味著我從MySQL看到的TPS是每秒兩萬的話,每秒就會寫四萬次磁盤,但是,我用工具測驗出來,磁盤能力也就兩萬左右,怎么能實作兩萬的TPS?
解釋這個問題,就要用到組提交 group commit 機制了,
這里,我需要先和你介紹日志邏輯序列號 LSN(log sequence number)的概念,LSN是單調遞增的,用來對應redo log的一個個寫入點,每次寫入長度為length的redo log, LSN的值就會加上length,
組提交舉例:
對于多個并發事務,他們都寫完了 redo log buffer,準備持久化到磁盤,那么會從這些事務中選擇一個 leader,然后取他們中最大的 LSN,讓這個 leader 帶著最大的 LSN 取寫盤,這樣小于 LSN 的日志就都寫到了磁盤,也就完成了一個組提交,其他事務直接回傳即可,
所以,一次組提交中事務越多,可以節省的 IOPS 也就越多,
MySQL 在進行兩階段提交時,redo log 和 binlog 都是可以使用組提交的,此外,為了提高 binlog 使用組提交的效果,可以設定 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 來實作:
-
binlog_group_commit_sync_delay引數,表示延遲多少微秒后才呼叫fsync;
-
binlog_group_commit_sync_no_delay_count引數,表示累積多少次以后才呼叫fsync,
注意,如果 sync_binlog 設定為 0,那么 binlog_group_commit_sync_delay 會進行延遲,但不會 fsync,
MySQL的IO性能優化
綜合所述,可以通過以下方法進行優化:
-
將 sync_binlog 設定為大于 1 的(一般為 100 ~ 1000),這樣可能會丟失最近的 N 條日志
-
將 innodb_flush_log_at_trx_commit 設定為 2,主機斷電會導致丟失資料
-
設定 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count引數,提升組優化效果,減少寫盤次數,但是會增加事務回應時間,也可能有丟失日志的風險
參考
- [1] MySQL是怎么保證資料不丟的
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/308610.html
標籤:其他
下一篇:MongoDB進階之查詢(一)
