BDI writeback髒頁回寫

2021-10-05 09:41:14 字數 3302 閱讀 7187

注:本文分析基於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效能調優 髒頁重新整理

原理 當記憶體資料頁跟磁碟資料頁內容不一致的時候,我們稱這個記憶體頁為 髒頁 記憶體資料寫入到磁碟後,記憶體和磁碟上的資料頁的內容就一致了,稱為 乾淨頁 當要讀入的資料頁沒有在記憶體的時候,就必須到緩衝池中申請乙個資料頁。這時候只能把最久不使用的資料頁從記憶體中淘汰掉 如果要淘汰的是乙個乾淨頁,就直...