1. 程式人生 > 其它 >MySQL45講之IO效能提升

MySQL45講之IO效能提升

本文介紹 MySQL 的 binlog 和 redo log 寫入機制和刷盤策略,以及如何提升 MySQL 的 IO 效能。

前言

本文介紹 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 控制的:

  1. sync_binlog=0的時候,表示每次提交事務都只write,不fsync;

  2. sync_binlog=1的時候,表示每次提交事務都會執行fsync;

  3. 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 引數控制,它有三種可能取值:

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

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

  3. 設定為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_delaybinlog_group_commit_sync_no_delay_count 來實現:

  1. binlog_group_commit_sync_delay引數,表示延遲多少微秒後才呼叫fsync;

  2. binlog_group_commit_sync_no_delay_count引數,表示累積多少次以後才呼叫fsync。

注意,如果 sync_binlog 設定為 0,那麼 binlog_group_commit_sync_delay 會進行延遲,但不會 fsync。

MySQL的IO效能優化

綜合所述,可以通過以下方法進行優化:

  1. 將 sync_binlog 設定為大於 1 的(一般為 100 ~ 1000),這樣可能會丟失最近的 N 條日誌

  2. 將 innodb_flush_log_at_trx_commit 設定為 2,主機斷電會導致丟失資料

  3. 設定 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count引數,提升組優化效果,減少寫盤次數,但是會增加事務響應時間,也可能有丟失日誌的風險

參考