注:本文分析基於3.10.0-693.el7核心版本,即centos 7.4
bdi(backing device info),備用儲存裝置,最常見的就是硬碟儲存裝置。這類裝置相對於記憶體來說,其讀寫速度非常慢,差別在兩個數量級,因此為了提高系統整體效能,linux系統引入了cache作為緩衝,最近用到的資料臨時儲存在記憶體裡,減少對慢速bdi裝置的操作。但這就需要在一定的時機把這些資料同步回bdi裝置,一來記憶體畢竟小,無法存放太多資料,二來記憶體裡的資料容易丟失,比如機器異常宕機或重啟。進行週期性回寫工作的機制就是writeback,在3.10核心上由workqueue來進行實際的回寫工作。原先由乙個pdflush程序統管所有磁碟的髒頁回寫,在磁碟數量多時很容易出現io瓶頸,採用workquene來回寫,相當於公升級為多執行緒,提高了io吞吐量。
核心為了管理好bdi裝置,專門為此建立了對應的結構體,
struct backing_dev_info
;
其中,work_list任務鍊錶存放的就是所有需要writeback的work,所有需要回寫的髒頁都會封裝成wb_writeback_work,並提交到該鍊錶。
/*
* passed into wb_writeback(), essentially a subset of writeback_control
*/struct wb_writeback_work
;
封裝writeback work時還會標記回寫的緣由,是週期回寫或是後台回寫亦或是手動刷快取。其中的list就是用於掛接到backing_dev_info中work_list鍊錶。
而wb_writeback_work中實際工作佇列和操作的inode則由存放在struct bdi_writeback上,
struct bdi_writeback
;
對於各個結構體的關係,可以移步《bdi各個結構體關係》,通過圖表更容易理解它們之間的關係,以及扮演的角色。
在核心初始化時,會建立乙個bdi_wq工作佇列,用於管理所有bdi裝置的writeback工作,同時建立乙個預設的default bdi結構,
static
int __init default_bdi_init
(void
)int
bdi_init
(struct backing_dev_info *bdi)
static
void
bdi_wb_init
(struct bdi_writeback *wb,
struct backing_dev_info *bdi)
可見最終執行髒頁回寫的就是在bdi_writeback_workfn函式中。
bdi子系統使用workqueue機制進行資料回寫,其通過bdi_queue_work提交具體的writeback任務,也就是回寫請求(wb_writeback_work)掛到bdi_wq佇列上。
static
void
bdi_queue_work
(struct backing_dev_info *bdi,
struct wb_writeback_work *work)
//將回寫任務wb_writeback_work掛到任務佇列work_list中
list_add_tail
(&work->list,
&bdi->work_list)
;//啟動工作佇列開始處理回寫任務
mod_delayed_work
(bdi_wq,
&bdi->wb.dwork,0)
;out_unlock:
spin_unlock_bh
(&bdi->wb_lock)
;}
該情況下不提交任務,只啟動writeback工作佇列,主要發生在寫操作路徑。
static
void
bdi_wakeup_thread
(struct backing_dev_info *bdi)
觸發writeback的地方主要有以下幾處,
sync->
syscall_define0
(sync)
->
sync_inodes_one_sb->
sync_inodes_sb->
bdi_queue_work
這個和手動執行sync類似,只不過sync是針對所有superblock,而syncfs是針對某個superblock,因此呼叫路徑類似。
syscall_define1
(syncfs,
int, fd)
->
sync_filesystem->
__sync_filesystem->
sync_inodes_sb->
bdi_queue_work
free_more_memory->
wakeup_flusher_threads->
__bdi_start_writeback->
bdi_queue_work
__alloc_pages_nodemask->
__alloc_pages_slowpath->
__alloc_pages_direct_reclaim->
__perform_reclaim->
try_to_free_pages->
do_try_to_free_pages->
wakeup_flusher_threads->
__bdi_start_writeback->
bdi_queue_work
該路徑不提交writeback任務,只啟動writeback工作佇列
ext4_file_write->
ext4_file_dio_write->
__generic_file_aio_write->
generic_file_buffered_write->
generic_perform_write->
balance_dirty_pages_ratelimited->
balance_dirty_pages->
bdi_start_background_writeback->
bdi_wakeup_thread
mysql 檢視 髒頁 MySQL 刷髒頁
1.髒頁,乾淨頁 當記憶體資料頁和磁碟資料頁上的內容不一致時,我們稱這個記憶體頁為髒頁 記憶體資料寫入磁碟後,記憶體頁上的資料和磁碟頁上的資料就一致了,我們稱這個記憶體頁為乾淨頁。2.刷髒頁的時機 2.1 redo log redo log 是迴圈寫的,當redo log 寫滿了,即 write p...
mysql 髒頁重新整理 InnoDB髒頁重新整理機制
我們知道innodb採用write ahead log策略來防止宕機資料丟失,即事務提交時,先寫重做日誌,再修改記憶體資料頁,這樣就產生了髒頁。既然有重做日誌保證資料永續性,查詢時也可以直接從緩衝池頁中取資料,那為什麼還要重新整理髒頁 到磁碟呢?如果重做日誌可以無限增大,同時緩衝池足夠大,能夠快取所...
mysql髒頁 MySQL效能調優 髒頁重新整理
原理 當記憶體資料頁跟磁碟資料頁內容不一致的時候,我們稱這個記憶體頁為 髒頁 記憶體資料寫入到磁碟後,記憶體和磁碟上的資料頁的內容就一致了,稱為 乾淨頁 當要讀入的資料頁沒有在記憶體的時候,就必須到緩衝池中申請乙個資料頁。這時候只能把最久不使用的資料頁從記憶體中淘汰掉 如果要淘汰的是乙個乾淨頁,就直...