MySQL -- flush
- 髒頁:記憶體資料頁與磁碟資料頁內容 不一致
- 乾淨頁:記憶體資料頁與磁碟資料頁內容 一致
- flush: 將記憶體中的髒頁寫入磁碟
- flush – 刷髒頁;purge – 清undolog;merge – 應用change buffer
flush過程
觸發flush
redolog寫滿
- 當InnoDB的redolog寫滿,系統會 停止所有的更新操作 ,推進
checkpoint
- 把
checkpoint
從CP推進到CP’,需要將兩點之間的日誌(綠色),所 對應的所有髒頁 都flush到磁碟上 - 然後
write pos
到CP’之間(紅色+綠色)可以再寫入redolog
效能影響
InnoDB應該 儘量避免 ,此時所有更新都會被 堵住 ,更新數( 寫效能 )跌為0
記憶體不足
- 當需要新的記憶體頁,而記憶體不夠用時,就需要 淘汰 一些記憶體資料頁( LRU )
- 如果淘汰的是 髒頁 ,就需要 先將髒頁flush到磁碟
- 該過程不會動redolog,因為redolog在重放的時候
- 如果一個數據頁已經flush過,會識別出來並跳過
效能影響
- 這種情況是 常態 ,InnoDB使用
buffer pool
管理記憶體 -
buffer pool
中記憶體頁有3種狀態- 沒有被使用
- 已被使用且為 乾淨頁
- 已被使用且為 髒頁
- InnoDB的策略是 儘量使用記憶體 ,對於一個 長期執行 的庫來說,未被使用的記憶體頁很少
- 當要讀入的資料頁沒有在記憶體中,必須到
buffer pool
中申請一個記憶體頁,採用 LRU 策略淘汰記憶體頁- 如果淘汰的是 乾淨頁 , 直接釋放並複用
- 如果淘汰的是 髒頁 ,必須先將髒頁 flush 到磁碟上,變成乾淨頁後才能複用
- 如果一個查詢 要淘汰的髒頁太多 ,會導致查詢的 響應時間明顯變長
其他情況
- 系統空閒
- 正常關閉
髒頁控制策略
主機IO能力
- 需要配置主機的 IO能力 ,InnoDB才知道 全力刷髒頁 時,可以刷多快
- 控制引數
innodb_io_capacity
,建議設定為磁碟的IOPS
(可以通過fio
測試) - 如果該值設定 過小 ,InnoDB會認為主機的IO能力很差,從而 控制刷髒頁的速度 ,甚至低於髒頁的生成速度
- 造成 髒頁累積 , 影響查詢和更新效能
mysql> SHOW VARIABLES LIKE '%innodb_io_capacity%'; +------------------------+-------+ | Variable_name| Value | +------------------------+-------+ | innodb_io_capacity| 2000| | innodb_io_capacity_max | 4000| +------------------------+-------+
$ fio -filename=fio.txt -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=2048M -numjobs=10 -runtime=10 -group_reporting -name=mytest ... Jobs: 10 (f=10): [m(10)][90.9%][r=155MiB/s,w=155MiB/s][r=9907,w=9896 IOPS][eta 00m:01s] mytest: (groupid=0, jobs=10): err= 0: pid=4867: Thu Jan 31 11:26:20 2019 read: IOPS=11.2k, BW=175MiB/s (184MB/s)(1754MiB/10002msec) ... bw (KiB/s): min=14285, max=24256, per=10.01%, avg=17978.35, stdev=2020.97, samples=190 iops: min=892, max= 1516, avg=1123.32, stdev=126.33, samples=190 write: IOPS=11.2k, BW=176MiB/s (184MB/s)(1756MiB/10002msec) ... bw (KiB/s): min=14211, max=24480, per=10.01%, avg=17990.18, stdev=2278.29, samples=190 iops: min=888, max= 1530, avg=1124.08, stdev=142.44, samples=190 Run status group 0 (all jobs): READ: bw=175MiB/s (184MB/s), 175MiB/s-175MiB/s (184MB/s-184MB/s), io=1754MiB (1839MB), run=10002-10002msec WRITE: bw=176MiB/s (184MB/s), 176MiB/s-176MiB/s (184MB/s-184MB/s), io=1756MiB (1841MB), run=10002-10002msec
flush speed
- 刷髒頁速度 慢 的後果
- 記憶體髒頁太多
- redolog寫滿
- 因素: 髒頁比例 + redolog寫盤速度
- 控制引數
innodb_max_dirty_pages_pct
:髒頁比例上限 -
F1(M)
:InnoDB會根據 當前的髒頁比例M ,計算出一個[0,100]
的值,虛擬碼如下所示 -
F2(N)
: N越大,F2越大- InnoDB每次寫入的日誌都有一個序號
- N:
write pos
對應的序號與checkpoint
對應的序號之間的 差值
- 演算法
-
R = max(F1(M) , F2(N))
-
flush speed = innodb_io_capacity * R%
-
mysql> SHOW VARIABLES LIKE '%innodb_max_dirty_pages_pct%'; +--------------------------------+-------+ | Variable_name| Value | +--------------------------------+-------+ | innodb_max_dirty_pages_pct| 75| | innodb_max_dirty_pages_pct_lwm | 0| +--------------------------------+-------+
F1(M){ if M>=innodb_max_dirty_pages_pct then return 100; return M/innodb_max_dirty_pages_pct * 100; }
髒頁比例
- 平時要多關注 髒頁比例 :
Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total
- 不要經常接近
innodb_max_dirty_pages_pct
mysql> SHOW GLOBAL STATUS LIKE '%Innodb_buffer_pool_pages_%'; +----------------------------------+------------+ | Variable_name| Value| +----------------------------------+------------+ | Innodb_buffer_pool_pages_data| 633395| | Innodb_buffer_pool_pages_dirty| 99| | Innodb_buffer_pool_pages_flushed | 1286891803 | | Innodb_buffer_pool_pages_free| 8191| | Innodb_buffer_pool_pages_misc| 13774| | Innodb_buffer_pool_pages_total| 655360| +----------------------------------+------------+ # 1. Innodb_buffer_pool_pages_data #The number of pages in the InnoDB buffer pool containing data. The number includes both dirty and clean pages. # 2. Innodb_buffer_pool_pages_dirty #The current number of dirty pages in the InnoDB buffer pool. # 3. Innodb_buffer_pool_pages_flushed #The number of requests to flush pages from the InnoDB buffer pool. # 4. Innodb_buffer_pool_pages_free #The number of free pages in the InnoDB buffer pool. # 5. Innodb_buffer_pool_pages_misc #The number of pages in the InnoDB buffer pool that are busy because they have been allocated for administrative overhead, such as row locks or the adaptive hash index. #Innodb_buffer_pool_pages_misc = Innodb_buffer_pool_pages_total − Innodb_buffer_pool_pages_free − Innodb_buffer_pool_pages_data. #13774 = 655360 - 8191 - 633395 # 6. Innodb_buffer_pool_pages_total #The total size of the InnoDB buffer pool. # Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total = 0.015%
flush neighbor
mysql> SHOW VARIABLES LIKE '%innodb_flush_neighbors%'; +------------------------+-------+ | Variable_name| Value | +------------------------+-------+ | innodb_flush_neighbors | 0| +------------------------+-------+
- 在準備刷一個髒頁的時候,如果這個資料頁的 鄰居 恰好也是髒頁,也會一起flush,可能會 蔓延
- 在 HDD ( IOPS為幾百 )時代,能 減少很多隨機IO
- 對於 SDD ,IOPS不再是瓶頸,可以將
innodb_flush_neighbors
設定為0,只重新整理自己,MySQL 8.0預設
參考資料
《MySQL實戰45講》
轉載請註明出處:http://zhongmingmao.me/2019/01/31/mysql-flush/
訪問原文「MySQL -- flush」獲取最佳閱讀體驗並參與討論