本篇內(nèi)容主要講解“BlueStore事物狀態(tài)機(jī)是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“BlueStore事物狀態(tài)機(jī)是什么”吧!
創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站建設(shè)、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的元謀網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
BlueStore可以理解為一個(gè)支持ACID的本地日志型文件系統(tǒng)。所有的讀寫(xiě)都是以Transaction
進(jìn)行,又因?yàn)橹С指采w寫(xiě),所以寫(xiě)流程設(shè)計(jì)的相對(duì)復(fù)雜一些,涉及到一系列的狀態(tài)轉(zhuǎn)換。我們著重分析一下?tīng)顟B(tài)機(jī)、延遲指標(biāo)以及如何保證IO的順序性和并發(fā)性。
queue_transactions
是ObjectStore層的統(tǒng)一入口,KVStore、MemStore、FileStore、BlueStore都相應(yīng)的實(shí)現(xiàn)了這個(gè)接口。state_t state
變量記錄了當(dāng)前時(shí)刻事物處于哪個(gè)狀態(tài)。在創(chuàng)建TransactionContext的時(shí)候會(huì)將state
初始化為STATE_PREPARE
,然后在_txc_add_transaction
中會(huì)根據(jù)操作碼類(lèi)型(opcode)進(jìn)行不同的處理。同時(shí)會(huì)獲取PG對(duì)應(yīng)的OpSequencer(每個(gè)PG有一個(gè)OpSequencer)用來(lái)保證PG上的IO串行執(zhí)行,對(duì)于deferred-write會(huì)將其數(shù)據(jù)寫(xiě)入RocksDB(WAL)。
以下階段就進(jìn)入BlueStore狀態(tài)機(jī)了,我們以寫(xiě)流程為導(dǎo)向分析狀態(tài)機(jī)的每個(gè)狀態(tài)。
從state_prepare開(kāi)始已經(jīng)進(jìn)入事物的狀態(tài)機(jī)了。這個(gè)階段會(huì)調(diào)用_txc_add_transaction
將OSD層面的事物轉(zhuǎn)換為BlueStore層面的事物;然后檢查是否還有未提交的IO,如果還有就將state設(shè)置為STATE_AIO_WAIT
并調(diào)用_txc_aio_submit
提交IO,然后退出狀態(tài)機(jī),之后aio完成的時(shí)候會(huì)調(diào)用回調(diào)函數(shù)txc_aio_finish
再次進(jìn)入狀態(tài)機(jī);否則就進(jìn)入STATE_AIO_WAIT
狀態(tài)。
_txc_aio_submit函數(shù)調(diào)用棧:
bdev->aio_submit –> KernelDevice::aio_submit –> io_submit
將aio提交到內(nèi)核Libaio隊(duì)列。
主要工作:準(zhǔn)備工作,生成大小寫(xiě)、初始化TransContext、deferred_txn、分配磁盤(pán)空間等。
延遲指標(biāo):l_bluestore_state_prepare_lat
,從進(jìn)入狀態(tài)機(jī)到prepare階段完成,平均延遲大概0.2ms左右。
該階段會(huì)調(diào)用_txc_finish_io
進(jìn)行SimpleWrite的IO保序等處理,然后將狀態(tài)設(shè)置為STATE_IO_DONE
再調(diào)用_txc_state_proc進(jìn)入下一個(gè)狀態(tài)的處理。
主要工作:對(duì)IO保序,等待AIO的完成。
延遲指標(biāo):l_bluestore_state_aio_wait_lat
,從prepare階段完成開(kāi)始到AIO完成,平均延遲受限于設(shè)備,SSD 0.03ms左右。
完成AIO,并進(jìn)入STATE_KV_QUEUED
階段。會(huì)根據(jù)bluestore_sync_submit_transaction
做不同處理。該值為布爾值,默認(rèn)為false。
如果為true,設(shè)置狀態(tài)為STATE_KV_SUBMITTED
并且同步提交kv到RocksDB但是沒(méi)有sync落盤(pán)(submit_transaction),然后applied_kv
。
如果為false,則不用做上面的操作,但是以下操作都會(huì)做。
最后將事物放在kv_queue
里,通過(guò)kv_cond
通知kv_sync_thread
去同步IO和元數(shù)據(jù)。
主要工作:將事物放入kv_queue
,然后通知kv_sync_thread
,osr的IO保序可能會(huì)block。
延遲指標(biāo):l_bluestore_state_io_done_lat
,平均延遲在0.004ms,通常很小主要耗在對(duì)SimpleWrite的IO保序處理上。
該階段主要在kv_sync_thread
線程中同步IO和元數(shù)據(jù),并且將狀態(tài)設(shè)置為STATE_KV_SUBMITTED
。具體會(huì)在異步線程章節(jié)分析kv_sync_thread
線程。
主要工作:從kv_sync_thread
隊(duì)列中取出事物。
延遲指標(biāo):l_bluestore_state_kv_queued_lat
,從事物進(jìn)入隊(duì)列到取出事物,平均延遲在0.08ms,因?yàn)槭菃尉€程順序處理的,所以依賴于kv_sync_thread
處理事物的速度。
等待kv_sync_thread
中kv元數(shù)據(jù)和IO數(shù)據(jù)的Sync完成,然后將狀態(tài)設(shè)置為STATE_KV_DONE
并且回調(diào)finisher線程。
主要工作:等待kv元數(shù)據(jù)和IO數(shù)據(jù)的Sync完成,回調(diào)finisher線程。
延遲指標(biāo):l_bluestore_state_kv_committing_lat
,從隊(duì)列取出事物到完成kv同步,平均延遲1.0ms,有極大的優(yōu)化空間。
如果是SimpleWrite,則直接將狀態(tài)設(shè)置為STATE_FINISHING
;如果是DeferredWrite,則將狀態(tài)設(shè)置為STATE_DEFERRED_QUEUED
并放入deferred_queue
。
主要工作:如上。
延遲指標(biāo):l_bluestore_state_kv_done_lat
,平均延遲0.0002ms,可以忽略不計(jì)。
主要工作:將延遲IO放入deferred_queue
等待提交。
延遲指標(biāo):l_bluestore_state_deferred_queued_lat
,通常不小,沒(méi)有數(shù)據(jù)暫不貼出。
主要工作:清理延遲IO在RocksDB上的WAL。
延遲指標(biāo):l_bluestore_state_deferred_cleanup_lat
,通常不小,沒(méi)有數(shù)據(jù)暫不貼出。
主要工作:設(shè)置狀態(tài)為STATE_DONE
,如果還有DeferredIO也會(huì)提交。
延遲指標(biāo):l_bluestore_state_finishing_lat
,平均延遲0.001ms。
主要工作:標(biāo)識(shí)整個(gè)IO完成。
延遲指標(biāo):l_bluestore_state_done_lat
。
BlueStore定義了狀態(tài)機(jī)的多個(gè)延遲指標(biāo),由PerfCounters采集,函數(shù)為BlueStore::_init_logger()
。
可以使用ceph daemon osd.0 perf dump
或者ceph daemonperf osd.0
來(lái)查看對(duì)應(yīng)的延遲情況。
除了每個(gè)狀態(tài)的延遲,我們通常也會(huì)關(guān)注以下兩個(gè)延遲指標(biāo):
b.add_time_avg(l_bluestore_kv_lat, "kv_lat", "Average kv_thread sync latency", "k_l", b.add_time_avg(l_bluestore_commit_lat, "commit_lat", "Average commit latency", "c_l",
BlueStore延遲主要花費(fèi)在l_bluestore_state_kv_committing_lat
也即c_l
,大概1ms左右。
BlueStore統(tǒng)計(jì)狀態(tài)機(jī)每個(gè)階段延遲的方法如下:
// 該階段延遲 = 上階段完成到該階段結(jié)束 void log_state_latency(PerfCounters *logger, int state) { utime_t lat, now = ceph_clock_now(); lat = now - last_stamp; logger->tinc(state, lat); last_stamp = now; }
在塊存儲(chǔ)的使用場(chǎng)景中,除了用戶并發(fā)IO外,通常用戶也會(huì)使用dd
等串行IO的命令,此時(shí)便受限于讀寫(xiě)的絕對(duì)延遲,擴(kuò)容加機(jī)器、增加線程數(shù)等橫向擴(kuò)展的優(yōu)化便是無(wú)效的,所以我們需要關(guān)注兩方面的延遲:并發(fā)IO延遲、串行IO延遲。
并發(fā)IO延遲優(yōu)化:kv_sync_thread、kv_finalize_thread多線程化;自定義WAL;async read。
串行IO延遲優(yōu)化:并行提交元數(shù)據(jù)、數(shù)據(jù);將sync操作與其他狀態(tài)并行處理。
保證IO的順序性以及并發(fā)性是分布式存儲(chǔ)必然面臨的一個(gè)問(wèn)題。因?yàn)锽lueStore使用異步IO,后提交的IO可能比早提交的IO完成的早,所以更要保證IO的順序,防止數(shù)據(jù)發(fā)生錯(cuò)亂。客戶端可能會(huì)對(duì)PG中的一個(gè)Object連續(xù)提交多次讀寫(xiě)請(qǐng)求,每次請(qǐng)求對(duì)應(yīng)一個(gè)Transaction,在OSD層面通過(guò)PGLock將并發(fā)的讀寫(xiě)請(qǐng)求在PG層面串行化,然后按序依次提交到ObjectStore層,ObjectStore層通過(guò)PG的OpSequencer保證順序處理讀寫(xiě)請(qǐng)求。
BlueStore寫(xiě)類(lèi)型有SimpleWrite、DeferredWrite兩種,所以我們分析一下SimpleWrite、DeferredWrite下的IO保序問(wèn)題。
因?yàn)?code>STATE_AIO_WAIT階段使用Libaio,所以需要保證PG對(duì)應(yīng)的OpSequencer中的txc按排隊(duì)的先后順序依次進(jìn)入kv_queue被kv_sync_thread
處理,也即txc在OpSequencer中的順序和在kv_queue中的順序是一致的。
void BlueStore::_txc_finish_io(TransContext *txc) { // 獲取txc所屬的OpSequencer,并且加鎖,保證互斥訪問(wèn)osr OpSequencer *osr = txc->osr.get(); std::lock_guard<std::mutex> l(osr->qlock); // 設(shè)置狀態(tài)機(jī)的state為STATE_IO_DONE txc->state = TransContext::STATE_IO_DONE; // 清除txc正在運(yùn)行的aio txc->ioc.running_aios.clear(); // 定位當(dāng)前txc在osr的位置 OpSequencer::q_list_t::iterator p = osr->q.iterator_to(*txc); while (p != osr->q.begin()) { --p; // 如果前面還有未完成IO的txc,那么需要停止當(dāng)前txc操作,等待前面txc完成IO。 // 目的是:確保之前txc的IO都完成。 if (p->state < TransContext::STATE_IO_DONE) { return; } // 前面的txc已經(jīng)進(jìn)入大于等于STATE_KV_QUEUED的狀態(tài)了,那么遞增p并退出循環(huán)。 // 目的是:找到狀態(tài)為STATE_IO_DONE的且在osr中排序最靠前的txc。 if (p->state > TransContext::STATE_IO_DONE) { ++p; break; } } // 依次處理狀態(tài)為STATE_IO_DONE的tx // 將txc放入kv_sync_thread的kv_queue、kv_queue_unsubmitted隊(duì)列 do { _txc_state_proc(&*p++); } while (p != osr->q.end() && p->state == TransContext::STATE_IO_DONE); ...... }
DeferredWrite在IO的時(shí)候也是通過(guò)Libaio提交到內(nèi)核Libaio隊(duì)列進(jìn)行寫(xiě)數(shù)據(jù),也需要保證IO的順序性。
相應(yīng)的數(shù)據(jù)結(jié)構(gòu)如下:
class BlueStore { typedef boost::intrusive::list< OpSequencer, boost::intrusive::member_hook< OpSequencer, boost::intrusive::list_member_hook<>, &OpSequencer::deferred_osr_queue_item>> deferred_osr_queue_t; // osr's with deferred io pending deferred_osr_queue_t deferred_queue; } class OpSequencer { DeferredBatch *deferred_running = nullptr; DeferredBatch *deferred_pending = nullptr; } struct DeferredBatch { OpSequencer *osr; // txcs in this batch deferred_queue_t txcs; }
BlueStore內(nèi)部包含一個(gè)成員變量deferred_queue;deferred_queue隊(duì)列包含需要執(zhí)行DeferredIO的OpSequencer;每個(gè)OpSequencer包含deferred_running和deferred_pending兩個(gè)DeferredBatch類(lèi)型的變量;DeferredBatch包含一個(gè)txc數(shù)組。
如果PG有寫(xiě)請(qǐng)求,會(huì)在PG對(duì)應(yīng)的OpSequencer中的deferred_pending中排隊(duì)加入txc,待時(shí)機(jī)成熟的時(shí)候,一次性提交所有txc給Libaio,執(zhí)行完成后才會(huì)進(jìn)行下一次提交,這樣不會(huì)導(dǎo)致DeferredIO亂序。
void BlueStore::_deferred_queue(TransContext *txc) { deferred_lock.lock(); // 排隊(duì)osr if (!txc->osr->deferred_pending && !txc->osr->deferred_running) { deferred_queue.push_back(*txc->osr); } // 追加txc到deferred_pending中 txc->osr->deferred_pending->txcs.push_back(*txc); _deferred_submit_unlock(txc->osr.get()); ...... } void BlueStore::_deferred_submit_unlock(OpSequencer *osr) { ...... // 切換指針,保證每次操作完成后才會(huì)進(jìn)行下一次提交 osr->deferred_running = osr->deferred_pending; osr->deferred_pending = nullptr; ...... while (true) { ...... // 準(zhǔn)備所有txc的寫(xiě)buffer int r = bdev->aio_write(start, bl, &b->ioc, false); } ...... // 一次性提交所有txc bdev->aio_submit(&b->ioc); }
線程+隊(duì)列是實(shí)現(xiàn)異步操作的基礎(chǔ)。BlueStore的一次IO經(jīng)過(guò)狀態(tài)機(jī)要進(jìn)入多個(gè)隊(duì)列并被不同的線程處理然后回調(diào),線程+隊(duì)列是BlueStore事物狀態(tài)機(jī)的重要組成部分。BlueStore中的線程大致有7種。
mempool_thread
:無(wú)隊(duì)列,后臺(tái)監(jiān)控內(nèi)存的使用情況,超過(guò)內(nèi)存使用的限制便會(huì)做trim。
aio_thread
:隊(duì)列為L(zhǎng)ibaio內(nèi)核queue,收割完成的aio事件。
discard_thread
:隊(duì)列為discard_queued,對(duì)SSD磁盤(pán)上的extent做Trim。
kv_sync_thread
:隊(duì)列為kv_queue、deferred_done_queue、deferred_stable_queue,sync元數(shù)據(jù)和數(shù)據(jù)。
kv_finalize_thread
:隊(duì)列為kv_committing_to_finalize、deferred_stable_to_finalize,執(zhí)行清理功能。
deferred_finisher
:調(diào)用回調(diào)函數(shù)提交DeferredIO的請(qǐng)求。
finishers
:多個(gè)回調(diào)線程Finisher,通知用戶請(qǐng)求完成。
我們主要分析aio_thread
、kv_sync_thread
、kv_finalize_thread
。
aio_thread比較簡(jiǎn)單,屬于KernelDevice模塊的,主要作用是收割完成的aio事件,并觸發(fā)回調(diào)函數(shù)。
void KernelDevice::_aio_thread() { while (!aio_stop) { ...... // 獲取完成的aio int r = aio_queue.get_next_completed(cct->_conf->bdev_aio_poll_ms, aio, max); // 設(shè)置flush標(biāo)志為true。 io_since_flush.store(true); // 獲取aio的返回值 long r = aio[i]->get_return_value(); ...... // 調(diào)用aio完成的回調(diào)函數(shù) if (ioc->priv) { if (--ioc->num_running == 0) { aio_callback(aio_callback_priv, ioc->priv); } } } }
涉及延遲指標(biāo):state_aio_wait_lat
、state_io_done_lat
。
當(dāng)IO完成后,要么將txc放入隊(duì)列,要么將dbh放入隊(duì)列,雖然對(duì)應(yīng)不同隊(duì)列,但都是由kv_sync_thread
執(zhí)行后續(xù)操作。
對(duì)于SimpleWrite,都是寫(xiě)新的磁盤(pán)block(如果是cow,也是寫(xiě)新的block,只是事務(wù)中k/v操作增加對(duì)舊的block的回收操作),所以先由aio_thread寫(xiě)block,再由kv_sync_thread同步元信息,無(wú)論什么時(shí)候掛掉,數(shù)據(jù)都不會(huì)損壞。
對(duì)于DeferredWrite,在事物的prepare階段將需要DeferredWrite的數(shù)據(jù)作為k/v對(duì)(也稱為WAL)寫(xiě)入基于RocksDB封裝的db_transaction中,此時(shí)還在內(nèi)存,kv_sync_thread第一次的commit操作中,將wal持久化在了k/v系統(tǒng)中,然后進(jìn)行后續(xù)的操作,異常的情況,可以通過(guò)回放wal,數(shù)據(jù)也不會(huì)損壞。
kv_sync_thread主要執(zhí)行的操作為:在Libaio寫(xiě)完數(shù)據(jù)后,需要通過(guò)kv_sync_thread更新元數(shù)據(jù)k/v,主要包含object的Onode、擴(kuò)展屬性、FreelistManager的磁盤(pán)空間信息等等,這些必須按順序操作。
涉及的隊(duì)列如下:
kv_queue
:需要執(zhí)行commit的txc隊(duì)列。將kv_queue中的txc存入kv_committing中,并提交給RocksDB,即執(zhí)行操作db->submit_transaction,設(shè)置狀態(tài)為STATE_KV_SUBMITTED,并將kv_committing中的txc放入kv_committing_to_finalize,等待線程kv_finalize_thread執(zhí)行。
deferred_done_queue
:已經(jīng)完成DeferredIO操作的dbh隊(duì)列,還沒(méi)有sync磁盤(pán)。這個(gè)隊(duì)列的dbh會(huì)有兩種結(jié)果: 1) 如果沒(méi)有做flush操作,會(huì)將其放入deferred_stable_queue待下次循環(huán)繼續(xù)處理 2) 如果做了flush操作,說(shuō)明數(shù)據(jù)已經(jīng)落盤(pán),即已經(jīng)是stable的了,直接將其插入deferred_stable_queue隊(duì)列。這里stable的意思就是數(shù)據(jù)已經(jīng)sync到磁盤(pán)了,前面RocksDB中記錄的wal沒(méi)用可以刪除了。
deferred_stable_queue
:DeferredIO已經(jīng)落盤(pán),等待清理RocksDB中的WAL。依次操作dbh中的txc,將RocksDB中的wal刪除,然后dbh入隊(duì)列deferred_stable_to_finalize,等待線程kv_finalize_thread執(zhí)行。
void BlueStore::_kv_sync_thread() { while (true) { // 交換指針 kv_committing.swap(kv_queue); kv_submitting.swap(kv_queue_unsubmitted); deferred_done.swap(deferred_done_queue); deferred_stable.swap(deferred_stable_queue) // 處理 deferred_done_queue if (force_flush) { // flush/barrier on block device bdev->flush(); // if we flush then deferred done are now deferred stable deferred_stable.insert(deferred_stable.end(), deferred_done.begin(), deferred_done.end()); deferred_done.clear(); } // 處理 kv_queue for (auto txc : kv_committing) { int r = cct->_conf->bluestore_debug_omit_kv_commit ? 0 : db->submit_transaction(txc->t); _txc_applied_kv(txc); } // 處理 deferred_stable_queue for (auto b : deferred_stable) { for (auto &txc : b->txcs) { get_deferred_key(wt.seq, &key); synct->rm_single_key(PREFIX_DEFERRED, key); } } // submit synct synchronously (block and wait for it to commit) // 同步kv,有設(shè)置bluefs_extents、刪除wal兩種操作 int r = cct->_conf->bluestore_debug_omit_kv_commit ? 0 : db->submit_transaction_sync(synct); // 放入finalize線程隊(duì)列,并通知其處理。 std::unique_lock<std::mutex> m(kv_finalize_lock); kv_committing_to_finalize.swap(kv_committing); deferred_stable_to_finalize.swap(deferred_stable); kv_finalize_cond.notify_one(); } }
涉及延遲指標(biāo):state_kv_queued_lat
、state_kv_committing_lat
、kv_lat
清理線程,包含兩個(gè)隊(duì)列:
kv_committing_to_finalize
:再次調(diào)用_txc_state_proc進(jìn)入狀態(tài)機(jī),設(shè)置狀態(tài)為STATE_KV_DONE,并執(zhí)行回調(diào)函數(shù)通知用戶io操作完成。
deferred_stable_to_finalize
:遍歷deferred_stable中的dbh,調(diào)用_txc_state_proc進(jìn)入狀態(tài)機(jī),設(shè)置狀態(tài)為STATE_FINISHING,繼續(xù)調(diào)用_txc_finish,設(shè)置狀態(tài)為STATE_DONE,狀態(tài)機(jī)結(jié)束,事物完成。
void BlueStore::_kv_finalize_thread() { while (true) { // 交換指針 kv_committed.swap(kv_committing_to_finalize); deferred_stable.swap(deferred_stable_to_finalize); // 處理kv_committing_to_finalize隊(duì)列 while (!kv_committed.empty()) { TransContext *txc = kv_committed.front(); _txc_state_proc(txc); kv_committed.pop_front(); } // 處理deferred_stable_to_finalize for (auto b : deferred_stable) { auto p = b->txcs.begin(); while (p != b->txcs.end()) { TransContext *txc = &*p; p = b->txcs.erase(p); // unlink here because _txc_state_proc(txc); // this may destroy txc } delete b; } deferred_stable.clear(); } }
涉及延遲指標(biāo):state_deferred_cleanup_lat
、state_finishing_lat
主要分為SimpleWrite、DeferredWrite、SimpleWrite+DeferredWrite。
到此,相信大家對(duì)“BlueStore事物狀態(tài)機(jī)是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
新聞名稱:BlueStore事物狀態(tài)機(jī)是什么
文章位置:http://aaarwkj.com/article24/psosce.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、微信小程序、Google、服務(wù)器托管、搜索引擎優(yōu)化、全網(wǎng)營(yíng)銷(xiāo)推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)