innodb 日誌機制及優化

1、innodb 重作日誌

當更新數據時,innodb 內部的操做流程大體是:數據庫

  1. 將數據讀入 innodb buffer pool,並對相關記錄加獨佔鎖;
  2. 將 undo 信息寫入 undo 表空間的回滾段中;
  3. 更改緩存頁中的數據,並將更新記錄寫入 redo buffer中;
  4. 提交時,根據 innodb_flush_log_at_trx_commit 的設置,用不一樣的方式將 redo buffer 中的更新記錄刷新到 innodb redo log file 中,而後釋放獨佔鎖;
  5. 最後,後臺 IO 線程根據須要擇機將緩存中更新過的數據刷新到磁盤文件中。
---
LOG
---
Log sequence number 1708635750      // 上次數據頁的修改,尚未刷新到日誌文件的lsn號
Log flushed up to   1708635750      // 上次成功操做,已經刷新到日誌文件中的lsn號
Pages flushed up to 1708635750
Last checkpoint at  1708635741      // 上次檢查點成功完成時的lsn號,覺得着恢復的起點

其中 lsn(log sequence number) 稱爲日誌序列號,它實際上對應日誌文件的偏移量,其生成公式是:
新的 lsn = 舊的 lsn + 寫入的日誌大小 緩存

例如,日誌文件大小爲 600 MB,目前的 lsn 是 1GB,如今要將 512 字節的更新記錄寫入 redo log,則實際寫入過程以下:安全

  1. 求出偏移量:因爲 lsn 數值遠大於日誌文件大小,所以經過取餘方式,獲得偏移量爲 400MB
  2. 寫入日誌:找到偏移 400MB 的位置,寫入 512 字節日誌內容,下一個事務的 lsn 就是 1000000512。

除 innodb buffer pool,innodb log buffer 的大小,redo 日誌文件的大小以及 innodb_flush_log_at_trx_commit 參數的設置等,都會影響 innodb 的性能。函數

2、innodb_flush_log_at_trx_commit 的設置

innodb_flush_log_at_trx_commit 參數能夠控制將 redo buffer 中的更新記錄寫入到日誌文件以及將日誌文件數據刷新到磁盤的操做時機。經過調整這個參數,能夠在性能和數據安全之間作取捨。性能

  • 0:在事務提交時,innodb 不會當即觸發將緩存日誌寫到磁盤文件的操做,而是每秒觸發一次緩存日誌回寫磁盤操做,並調用系統函數 fsync 刷新 IO 緩存。這種方式效率最高,也最不安全。
  • 1:在每一個事務提交時,innodb 當即將緩存中的 redo 日誌回寫到日誌文件,並調用 fsync 刷新 IO 緩存。
  • 2:在每一個事務提交時,innodb 當即將緩存中的 redo 日誌回寫到日誌文件,但並不立刻調用 fsync 來刷新 IO 緩存,而是每秒只作一次磁盤IO 緩存刷新操做。只要操做系統不發生崩潰,數據就不會丟失,這種方式是對性能和數據安全的折中,其性能和數據安全性介於其餘兩種方式之間。

innodb_flush_log_at_trx_commit 參數的默認值是 1,即每一個事務提交時都會從 log buffer 寫更新記錄到日誌文件,並且會實際刷新磁盤緩存,顯然,這徹底能知足事務的持久化要求,是最安全的,但這樣會有較大的性能損失。 操作系統

在某些須要儘可能提升性能,而且能夠容忍在數據庫崩潰時丟失小部分數據,那麼經過將參數 innodb_flush_log_at_trx_commit 設置成 0 或 2 都能明顯減小日誌同步 IO,加快事務提交,從而改善性能。線程

3、設置 log file size ,控制檢查點

當一個日誌文件寫滿後,innodb 會自動切換到另外一個日誌文件,但切換時會觸發數據庫檢查點(checkpoint),這將致使 innodb 緩存髒頁的小批量刷新,會明顯下降 innodb 的性能。 日誌

能夠經過增大 log file size 避免一個日誌文件過快的被寫滿,但若是日誌文件設置的過大,恢復時將須要更長的時間,同時也不便於管理,通常來講,平均每半個小時寫滿一個日誌文件比較合適code

能夠經過下面的方式來計算 innodb 每小時產生的日誌量並估算合適的 innodb_log_file_size 的值:事務

// 1. 計算 innodb 每分鐘產生的日誌量  
MySQL [(none)]> pager grep -i "log sequence number"
PAGER set to 'grep -i "log sequence number"'

MySQL [(none)]> show engine innodb status\G select sleep(60);show engine innodb status\G
Log sequence number 1706853570
1 row in set (0.00 sec)

1 row in set (1 min 0.00 sec)

Log sequence number 1708635750
1 row in set (0.00 sec)

MySQL [(none)]> nopager
PAGER set to stdout

MySQL [(none)]> select round ((1708635750 - 1706853570) /1024/1024) as MB;
+------+
| MB   |
+------+
|    2 |
+------+
1 row in set (0.00 sec)

經過上述操做獲得 innodb 每分鐘產生的日誌量是 2 MB。而後計算沒半小時的日誌量:

半小時日誌量 = 30 * 2MB = 60MB

這樣,就能夠得出 innodb_log_file_size 的大小至少應該是 60MB。

4、調整 innodb_log_buffer_size

innodb_log_buffer_size 決定 innodb 重作日誌緩存池的大小,默認是 8MB。對於可能產生大量更新記錄的大事務,增長 innodb_log_buffer_size 的大小,能夠避免 innodb 在事務提交前就執行沒必要要的日誌寫入磁盤操做。所以,對於會在一個事務中更新,插入或刪除大量記錄的應用,能夠經過增大 innodb_log_buffer_size 來減小日誌寫磁盤操做,提升事務處理性能。

相關文章
相關標籤/搜索