bluestore 流程解析

1.整體流程


圖片發自簡書App


圖中展示了流程中的關鍵路徑及涉及到的線程與隊列。下面詳細闡述工作流程。

重點關注:狀態切換;kv存儲數據的GC時機

1.1 queue_transactions

queue_transactions是store統一的入口,各個存儲引擎如filestore、kvstore、bluestore都得實現這個入口。在queue_transactions里先初始化transaction(初始化狀態為STATE_PREPARE),然后在_txc_add_transaction根據操作碼的類型進行不同處理,將其放到transaction里,前一篇文章里的I/O映射邏輯就是根據操作碼OP_WRITE在BlueStore::_write里進行處理。BlueStore::_write –> BlueStore::_do_write –> (_do_write_small/_do_write_big) –> _do_alloc_write 分配空間,如果采用aio就會調用bdev->aio_write準備aio的結構,放在pending_aios里,如果不是aio就直接pwrite(如果是非direct的還需要sync)。

1.2 STATE_PREPARE

_txc_state_proc里就是狀態機的處理邏輯,根據所處的狀態進行不同階段的處理。起始狀態是STATE_PREPARE,在這個狀態下回檢查是否還有未完成的aio,如果有就將狀態置為STATE_AIO_WAIT,并調用_txc_aio_submit進行處理,否則就直接進入到下一個狀態STATE_AIO_WAIT的處理。

在_txc_aio_submit里就是就是調用bdev->aio_submit –> KernelDevice::aio_submit –> io_submit將aio提交到內核進行處理(注:目前支持KernelDevice和NVMEDevice,這里以KernelDevice為例)。

使用linux Aio時,將I/O提交后,當內核處理完成后會通知到用戶態,一種方式是使用eventfd,將其注冊到epoll里,當內核處理I/O完成后會觸發eventfd的事件從而進行處理;另外一種方式是用一個單獨的線程,輪詢調用io_getevents去獲取完成的事件。在bluestore里采用的是第二種方式,對應的線程是KernelDevice::_aio_thread,當I/O處理完后會調用回調函數aio_cb進行處理(這個回調函數是在bluestore啟動時創建KernelDevice設置的),在aio_cb中調用_txc_aio_finish –> _txc_state_proc,從而進入到下一個狀態STATE_AIO_WAIT的處理。

1.3 STATE_AIO_WAIT

在這個狀態里是調用_txc_finish_io進行處理,會將狀態設置成STATE_IO_DONE。因為aio的完成可能是亂序的,有可能后提交的I/O先完成,但是需要保證kv事務的順序性。bluestore里通過OpSequencer來保證kv事務的順序性(在_txc_create里會將新的txc放到osr->q里,即q.push_back。在_osr_reap_done里從osr->q里挨個剔除完成的。),在_txc_finish_io里就是實現通過OpSequencer來保證每個事務在處于某個狀態時,這個事務之前的事務也必須在這個狀態,即使某個事務的I/O先完成,也得等到它之前的事務的I/O也完成后才能進入到下個狀態的處理。

做了這個保證后,再對按序對STATE_IO_DONE狀態的事務調用_txc_state_proc進入下一個狀態的處理。

1.4 STATE_IO_DONE

進入這個狀態后,會設置下個狀態為STATE_KV_QUEUED,然后會根據bluestore_sync_transaction和bluestore_sync_submit_transaction這兩個配置參數的組合作不同的處理:

1)bluestore_sync_transaction為true:表示同步提交kv到rocksdb并持久化,對應調用_txc_finalize_kv后再調用db->submit_transaction,即rocksdb::Write并設置rocksdb::WriteOptions.sync=true;

2)bluestore_sync_transaction為false,bluestore_sync_submit_transaction為true:表示將kv提交到rocksdb,但是不sync,也就是沒有落盤,對應調用_txc_finalize_kv后再調用db->submit_transaction_sync,即rocksdb::Write,但rocksdb::WriteOptions.sync=false;

不管采用何種處理方式,最后都會將事務放到kv_queue里,然后通過kv_cond通知_kv_sync_thread。

1.5 _kv_sync_thread處理kv_queue

_kv_sync_thread線程里就是處理kv_queue和wal_cleanup_queue里的事務。按照流程,這一步走到從kv_queue里取事務進行處理的過程。處理的時候是將kv_queue替換給kv_committing,然后后續對kv_committing進行處理。

當bluestore_sync_transaction和bluestore_sync_submit_transaction都為false時(也就是在前一個狀態里沒做事務相關處理,直接放到kv_queue里了),會遍歷kv_committing里的事務,調用_txc_finalize_kv將空間分配釋放相關的元數據在kv事務進行處理(如設置key、刪除key等),然后db->submit_transaction將kv提交到rocksdb,但是沒有落盤。

然后都會調用db->submit_transaction_sync來進行提交并刷盤的動作,這樣即使在1.4那一步已經提交sync了,這里也會多做一次,以確保不管前面是沒提交、只提交了沒sync、提交并sync了的,到了這一步操作后事務都落盤了。

對于每個處理完的事務,都會調用_txc_state_proc進入到下一個狀態STATE_KV_QUEUED的處理。

1.6 STATE_KV_QUEUED

設置狀態為STATE_KV_DONE,然后調用_txc_finish_kv處理onreadable、oncommit回調,就是將回調放到finisher queue里,觸發finisher thread去進行回調的處理(即如果各個副本都處理完成,就會發送對應的響應給客戶端)。然后直接進入到STATE_KV_DONE狀態的處理。

1.7 STATE_KV_DONE

如果沒有wal事務要處理,就直接設置狀態為STATE_FINISHING,然后跳出此處處理,在下一次處理到該事務時判斷到狀態為STATE_FINISHING,從而進行完成的一些處理。

下面主要介紹有wal的情況,之前一篇文章講過當有覆蓋寫的時候就會進行wal,設置狀態為STATE_WAL_QUEUED,然后根據配置參數bluestore_sync_wal_apply有兩種處理方式:

1)當bluestore_sync_wal_apply為false,就把事務放到wal_wq中(會觸發WALWQ threads去處理),結束此次處理;

2)當bluestore_sync_wal_apply為true時,直接調用_wal_apply進行處理;

在_wal_apply中會設置狀態為STATE_WAL_APPLYING,然后遍歷wal事務中的op,調用_do_wal_op進行處理,在_do_wal_op里調用bdev->aio_write準備aio的結構,放在pending_aios里,如果不是aio就直接pwrite(如果是非direct的還需要sync)。

當wal事務中的op都處理完后,就會調用_txc_state_proc進入到下一個狀態的處理。

1.8 WALWQ threads

上面說到在bluestore_sync_wal_apply為false時,wal事務直接放到wal_wq中,交由WALWQ的線程池來處理。在這個線程池里也是調用_wal_apply進行處理,具體在上面已經說過了。處理完調用_txc_state_proc進入到下一個狀態STATE_WAL_APPLYING的處理。

1.9 STATE_WAL_APPLYING

在這個狀態下回檢查是否還有未完成的aio,如果有就將狀態置為STATE_WAL_AIO_WAIT,然后調用_txc_aio_submit提交I/O到磁盤,并結束此次處理。否則就判斷是否滿足后續狀態,如果是就進行處理,如果不是就結束。

在KernelDevice::_aio_thread,當I/O處理完后會調用回調函數aio_cb進行處理,在aio_cb中調用_txc_aio_finish –> _txc_state_proc,從而進入到下一個狀態STATE_WAL_AIO_WAIT的處理。

1.10 STATE_WAL_AIO_WAIT

在這個狀態下,調用_wal_finish,設置狀態為STATE_WAL_CLEANUP,然后放到wal_cleanup_queue中,通知_kv_sync_thread去處理。

1.11 _kv_sync_thread處理wal_cleanup_queue

處理的時候是將wal_cleanup_queue替換給wal_cleaning,然后后續對wal_cleaning進行處理。在1.5節里已經介紹過kv_sync_thread對kv_queue的處理,其實_kv_sync_thread在每次處理時都是同時處理kv_queue和wal_cleanup_queue里的事務,只不過本文是按照邏輯處理流程才分開描述的。

對于wal_cleanup_queue里的事務,也是調用_txc_finalize_kv將空間分配釋放相關的元數據在kv事務進行處理(如設置key、刪除key等),然后在接下去的db->submit_transaction_sync中統一提交kv到rocksdb并sync落盤。這次submit_transaction_sync的調用對于kv_queue和wal_cleanup_queue中事務都是一起生效的。

在處理完成后,對于wal_cleanning中的事務都會調用_txc_state_proc進行下一個狀態的處理。

1.12 STATE_WAL_CLEANUP

在這個狀態里就是設置狀態為STATE_FINISHING,然后直接進入STATE_FINISHING狀態的處理。

1.13 STATE_FINISHING

調用_txc_finish進行一些結束狀態的處理。

2.總結

從上面的流程分析可以知曉,一個I/O在bluestore里經歷了多個線程和隊列才最終完成,對于非WAL的寫,比如對齊寫、寫到新的blob里等,I/O先寫到塊設備上,然后元數據提交到rocksdb并sync了,才返回客戶端寫完成(在STATE_KV_QUEUED狀態的處理);對于WAL(即覆蓋寫),沒有先把數據寫塊設備,而是將數據和元數據作為wal一起提交到rocksdb并sync后,這樣就可以返回客戶端寫成功了,然后在后面的動作就是將wal里的數據再寫到塊設備的過程,對這個object的讀請求要等到把數據寫到塊設備完成整個wal寫I/O的流程后才行,代碼里對應的是_do_read里先o->flush()的操作,所以bluestore里的wal就類似filestore里的journal的作用。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容