存儲QoS是個可以做很大也可以做很小的特性。SolidFire認(rèn)為將QoS歸類為特性太兒戲,,QoS應(yīng)該是存儲系統(tǒng)設(shè)計(jì)之初就要仔細(xì)考慮的架構(gòu)問題,。的確,,分析了一眾主流存儲大廠后還是覺得它在這方面做得最細(xì)致最全面。同時也有些廠商做得比較簡陋,,只提供了帶寬或者IOPS的限速功能,。這或許在某些場景中已經(jīng)夠用,但我認(rèn)為一個完整的QoS方案至少要包括對帶寬,、IOPS的預(yù)留,、上限和優(yōu)先級控制,如果再精細(xì)點(diǎn)還可以考慮IO的粒度,、延遲,、突發(fā)、空間局部性,、系統(tǒng)內(nèi)部IO,、用戶IO、緩存,、磁盤等要素,。
分布式存儲都有很長的IO路徑,簡單的IOPS限速功能通常在路徑的最前端實(shí)現(xiàn),。例如OpenStack Cinder默認(rèn)使用QEMU完成存儲塊的限速功能,,QEMU對存儲來說已經(jīng)屬于客戶端的角色了。
QoS的本質(zhì)總結(jié)起來就四個字:消此長彼,,它并不會提高系統(tǒng)整體處理能力,,只是負(fù)責(zé)資源的合理分配。據(jù)此就可以提出一連串問題了:首先,,如何知道什么時候該消誰什么時候該長誰,?其次,該怎么消該怎么長,?這兩個問題QoS算法可以幫忙解決,,可以參考我的另外一篇文章《聊聊dmclock算法》。在這兩個問題之前還需要選擇一塊風(fēng)水寶地,,能夠控制希望可以控制的IO,,否則即使知道何時控制以及如何控制也鞭長莫及無能為力。風(fēng)水寶地的選擇可以參考我的另外一篇文章《拆開Ceph看線程和隊(duì)列》,。
對Ceph來說,,OSD的ShardedOpWq隊(duì)列是個不錯的選擇,因?yàn)閹缀跛兄亓考壍腎O都會經(jīng)過該隊(duì)列,。這些IO可以劃分為兩大類,,一類是客戶端過來的IO,包括文件,、對象和塊存儲,;另一類是系統(tǒng)內(nèi)部活動產(chǎn)生的IO,包括副本復(fù)制,、Scrub,、Recovery和SnapTrim等。第一類IO由于涉及到一些敏感內(nèi)容暫不考慮,,本文主要分析第二類IO,,這也是本文叫做下篇的原因。
Recovery
配置項(xiàng) |
默認(rèn)值 |
說明 |
osd_recovery_threads |
1 |
Recovery線程池中線程的個數(shù) wipe_dmclock2分支已經(jīng)禁用該線程池
|
osd_max_backfills |
1 |
同時進(jìn)行恢復(fù)的PG數(shù)目的最大值 |
osd_min_recovery_priority |
0 |
優(yōu)先級最高為255, 基數(shù)為230,??赏ㄟ^命令行配置PG的優(yōu)先級 |
osd_recovery_max_active |
3 |
|
osd_recovery_max_single_start |
1 |
一個PGRecovery對應(yīng)的Object個數(shù) |
osd_recovery_delay_start |
0 |
推遲Recovery開始時間 |
osd_recovery_sleep |
0 |
出隊(duì)列后先Sleep一段時間,拉長兩個Recovery的時間間隔 |
osd_recovery_op_priority |
3 |
Recovery Op的優(yōu)先級 |
osd_max_push_cost |
8^20 |
MOSDPGPush消息的大小 |
osd_max_push_objects |
10 |
MOSDPGPush消息允許的Object數(shù)量 |
osd_recovery_cost |
20MB |
入ShardOpWq隊(duì)列時配置,,待補(bǔ)充
|
osd_recovery_priority |
5 |
入ShardOpWq隊(duì)列時配置,,待補(bǔ)充
|
Recovery自己已經(jīng)具備了一些優(yōu)先級控制的功能,上表給出了一些控制參數(shù),,下面一一介紹下每個參數(shù)的作用,。
Ceph主線分支中Recovery擁有獨(dú)立的工作隊(duì)列和線程池,線程池的線程數(shù)目由配置項(xiàng)osd_recovery_threads指定,,默認(rèn)為1,。Ceph wip_dmclock2分支取消了Recovery的工作隊(duì)列和線程池,轉(zhuǎn)而將Recovery Op入ShardOpWq隊(duì)列,。這樣Recovery Op和其它類型Op在相同的隊(duì)列,,因此理論上會有更好的控制效果。
預(yù)留
OSDService
|-- remote_reserver: AsyncReserver<spg_t>
|-- local_reserver: AsyncReserver<spg_t>
|-- queues: map<unsigned, list<pair<T, Context*> > > // Key為pg恢復(fù)的優(yōu)先級,,Value為List,,List元素為<pgid, QueuePeeringEvt>
|-- queue_pointers: map<T, pair<unsigned, typename list<pair<T, Context*> >::iterator > > // Key為pgid,Value為queues[prio]
|-- in_progress: set<T> // 正在處理的請求
|-- f: Finisher // 調(diào)用queues中Context的隊(duì)列
|-- max_allowed: unsigned // osd_max_backfills配置項(xiàng)
|-- min_priority: unsigned // osd_min_recovery_priority配置項(xiàng)
1. WaitLocalRecoveryReserved::WaitLocalRecoveryReserved() --> AsyncReserver::request_reservation() --> AsyncReserver::do_queues()
2. QueuePeeringEvt::finish() --> PG::queue_peering_event(LocalRecoveryReserved) // 由AsyncReserver的Finish線程調(diào)用
在開始恢復(fù)數(shù)據(jù)前Ceph會先進(jìn)行預(yù)留,,預(yù)留的其中一個目的是控制不同PG恢復(fù)的優(yōu)先級,。預(yù)留通過AsyncReserver類實(shí)現(xiàn),該類包含了一個優(yōu)先級隊(duì)列queues,,預(yù)留時先將PG入優(yōu)先級隊(duì)列,,再根據(jù)PG的優(yōu)先級從高到低的順序出隊(duì)列,優(yōu)先級越高的PG越先恢復(fù),。雖然AsyncReserver以PG為單位進(jìn)行優(yōu)先級控制,,但事實(shí)上用戶以Pool為單位設(shè)置PG的優(yōu)先級。Ceph的ceph osd pool set recovery_priority命令用于設(shè)置Pool的Recovery優(yōu)先級,,屬于同個Pool的PG具有相同的優(yōu)先級,。
預(yù)留的另一個目的是控制OSD中同時進(jìn)行恢復(fù)的PG數(shù)目。AsyncReserver::max_allowed限制PG出隊(duì)列,,若正在處理的PG數(shù)目超過max_allowed則后面的請求將留在隊(duì)列內(nèi)直到其它PG完成恢復(fù)后才出隊(duì)列,。預(yù)留會同時考慮Primary OSD和Replica OSD,,Primary OSD通過local_reserver來預(yù)留,Replica OSD通過remote_reserver來預(yù)留,,默認(rèn)每個AsyncReserver同一個時刻只允許一個PG進(jìn)行恢復(fù),。因?yàn)橐粋€OSD同時為某些PG的Primary為另一些PG的Replica,所以一個OSD同一時刻只允許兩個PG進(jìn)行恢復(fù),。
恢復(fù)
PGRecovery
|-- reserved_pushes: uint64_t
OSDService
|-- awaiting_throttle: list<pair<epoch_t, PGRef> >
|-- recovery_ops_reserved: uint64_t // 預(yù)留的ops,,進(jìn)ShardOp隊(duì)列的recovery請求數(shù)
|-- recovery_ops_active: uint64_t
|-- defer_recovery_until: utime_t // 允許Recovery啟動的時間
|-- recovery_paused: bool // 暫停Recovery,通過OSDMap來設(shè)置
// 狀態(tài)機(jī)進(jìn)入Recoverying狀態(tài),,將PGRecovery Op入ShardOpWq隊(duì)列
Recovering::Recovering() --> PG::queue_recovery(false) --> OSDService::_maybe_queue_recovery() --> OSDService::_queue_for_recovery() --> ShardedWQ::queue(PGRecovery)
RPGHandle(PGBackend::RecoveryHandle)
|-- pushes: map<pg_shard_t, vector<PushOp>> // pg_shard_t目標(biāo)OSD,,PushOp Object的詳細(xì)內(nèi)容
|-- pulls: map<pg_shard_t, vector<PullOp>> // pg_shard_t目標(biāo)OSD,PullOp Object的詳細(xì)內(nèi)容
MOSDPGPush
|-- pushes: vector<PushOp>
// 出ShardOpWq隊(duì)列
PGQueueable::RunVis::operator() --> OSD::do_recovery() --> ReplicatedPG::start_recovery_ops() --> ReplicatedPG::recover_replicas() -->
1. ReplicatedPG::prep_object_replica_pushes() --> ReplicatedBackend::recover_object() --> ReplicatedBackend::start_pushes() --> ReplicatedBackend::prep_push_to_replica() --> ReplicatedBackend::prep_push()
2. ReplicatedBackend::run_recovery_op() --> ReplicatedBackend::send_pushes()
回顧下前端IO控制,,在3副本情況下一個前端MOSDOp請求將衍生出兩個額外的MOSDRepOp請求,,而mClock隊(duì)列只控制MOSDOp請求的速度,通過MOSDOp來間接控制MOSDRepOp請求,。Recovery也采用類似的策略,,mClock隊(duì)列控制PGRecovery出隊(duì)列的速度,而每個PGRecovery可能對應(yīng)多個Object的恢復(fù),,通過PGRecovery間接控制Object的恢復(fù),。
除了在mClock隊(duì)列中控制PGRecovery速度外,Ceph還提供了多種手段來控制PGRecovery到Object的映射關(guān)系,。首先,,限制每個PGRecovery對應(yīng)的Object的數(shù)目,由osd_recovery_max_single_start配置決定,,默認(rèn)為1,。也就說,每個PGRecovery默認(rèn)只能恢復(fù)一個Object,。其次,,限制活動的Object恢復(fù)操作,由osd_recovery_max_active配置決定,。Ceph將恢復(fù)Op分為兩類:一類是Active恢復(fù)操作代表已經(jīng)正在恢復(fù)的操作,;另一類是預(yù)留的恢復(fù)操作,代表正在mClock隊(duì)列等候的PGRecovery對應(yīng)的恢復(fù)操作,。當(dāng)PGRecovery入mClock隊(duì)列時,,根據(jù)這兩類操作數(shù)以及osd_recovery_max_active來限制PGRecovery允許的Object個數(shù)。最后限制恢復(fù)請求中對象的個數(shù)和大小,,由osd_max_push_cost和osd_max_push_objects兩個配置決定,。
// Replica處理MOSDPGPush消息
1. OSD::dispatch_op_fast() --> OSD::handle_replica_op() --> OSD::enqueue_op() --> PG::queue_op() --> ShardedWQ::queue()
2. ReplicatedPG::do_request() --> ReplicatedBackend::handle_message() --> ReplicatedBackend::do_push() --> ReplicatedBackend::_do_push()
// Primary處理MOSDPGPushReply消息
3. ReplicatedPG::do_request() --> ReplicatedBackend::handle_message() --> ReplicatedBackend::do_push_reply() --> ReplicatedBackend::handle_push_reply() --> ReplicatedPG::on_global_recover() --> PG::finish_recovery_op() --> OSDService::finish_recovery_op() --> OSDService::_maybe_queue_recovery()
一個Recovery Object的所有Replica都恢復(fù)后,Primary重新向ShardOp隊(duì)列投遞PGRecovery請求,,ShardOp線程開始下個Object的恢復(fù),。所有Object都恢復(fù)后ShardOp線程使用AllReplicasRecovered事件將狀態(tài)機(jī)從Recovering狀態(tài)切換到Recovered狀態(tài),,同時釋放Replica的預(yù)留。最后,,如果所有節(jié)點(diǎn)都Active,,則從Recovered狀態(tài)切換到Clean狀態(tài)。
(Deep)Scrub
配置項(xiàng) |
默認(rèn)值 |
說明 |
osd_scrub_chunk_min |
5 |
PGScrub對應(yīng)的Object數(shù)目的最小值 |
osd_scrub_chunk_max |
25 |
PGScrub對應(yīng)的Object數(shù)目的最大值 |
osd_deep_scrub_interval |
1周 |
Deep scrub周期 |
osd_scrub_sleep |
0 |
兩個PGScrub Op間休息一段時間 |
osd_heartbeat_interval |
6 |
周期性執(zhí)行OSD::sched_scrub函數(shù) |
osd_scrub_begin_hour |
0 |
允許觸發(fā)Scrub的時間段的起始時間 |
osd_scrub_end_hour |
0 |
允許觸發(fā)Scrub的時間段的結(jié)束時間,,結(jié)束時間可以小于起始時間 |
osd_scrub_auto_repair |
false |
自動repair不一致Object,不支持副本池,,只支持EC池 |
osd_max_scrubs |
1 |
OSD允許同時運(yùn)行的Scrub任務(wù)的最大數(shù)目 |
osd_scrub_min_interval |
60*60*24 |
一天 |
osd_scrub_max_interval |
7*60*60*24 |
一周 |
osd_scrub_interval_randomize_ratio |
0.5 |
[min, min*(1+randomize_ratio)] |
osd_scrub_during_recovery |
true |
允許在OSD Recovery過程中執(zhí)行Scrub任務(wù) |
osd_scrub_load_threshold |
0.5 |
只有負(fù)載低于該值時才允許觸發(fā)Scrub |
同前端IO和Recovery一樣,,Ceph通過控制PGScrub來間接控制Scrub的所有IO優(yōu)先級。
啟動
OSDService
|-- sched_scrub_pg: set<ScrubJob> // 已注冊的Scrub任務(wù)
|-- sched_time: utime_t // 任務(wù)開始執(zhí)行的時間
|-- deadline: utime_t
// 注冊ScrubJob
PG::reg_next_scrub() --> OSD::reg_pg_scrub() --> OSD::sched_scrub_pg
// 調(diào)度ScrubJob
OSD::init() --> C_Tick_WithoutOSDLock::finish() --> OSD::tick_without_osd_lock() --> OSD::sched_scrub() --> PG::sched_scrub() --> PG::queue_scrub() --> PG::requeue_scrub() --> OSD::queue_for_scrub()
Ceph以PG為單位執(zhí)行Scrub操作,,若要執(zhí)行Scrub操作事先需要以ScrubJob的形式向OSD注冊,,OSD會定時檢查注冊的ScrubJob,若條件滿足則開始執(zhí)行Scrub操作,。這涉及到兩個問題:第一個問題是何時注冊ScrubJob,,第二個問題是何時執(zhí)行ScrubJob。執(zhí)行PGLog合并,、PG分裂,、Scrub相關(guān)命令時都會注冊ScrubJob,每個ScrubJob包含一個任務(wù)開始時間(sched_time)和一個最終時間(deadline),。默認(rèn)情況下,,ScrubJob::sched_time小于當(dāng)前時間+osd_scrub_min_interval,ScrubJob::deadline為當(dāng)前時間+osd_scrub_max_interval,,注冊任務(wù)后正常情況在一天內(nèi)執(zhí)行,,特殊情況一周內(nèi)執(zhí)行。
OSD進(jìn)程啟動時初始化C_Tick_WithoutOSDLock定時器,,定時器默認(rèn)每隔18秒檢查一次OSD中已注冊的ScrubJob,,對滿足條件的ScrubJob開始執(zhí)行預(yù)留操作。檢查的內(nèi)容包括以下幾項(xiàng):
- 檢查是否到達(dá)ScrubJob的開始時間(sched_time),,沒到達(dá)不執(zhí)行,;
- 在有Recovery Op的情況下,檢查 osd_scrub_during_recovery配置是否允許同時執(zhí)行Scrub任務(wù),;
- 檢查PG是否為Active狀態(tài),,非Active不允許執(zhí)行;
- 檢查ScrubJob是否超期(deadline),;
- 檢查當(dāng)前時間是否位于允許Scrub的時間段內(nèi)并且系統(tǒng)負(fù)載也在允許范圍內(nèi),。
特別注意在ScrubJob已經(jīng)超期的情況下將忽略最后一個限制條件強(qiáng)制執(zhí)行Scrub任務(wù)。另外值得一提的是Scrub時間段,,它由osd_scrub_begin_hour和osd_scrub_end_hour兩個配置項(xiàng)控制,。osd_scrub_begin_hour可以小于也可以大于osd_scrub_end_hour,,它們兩的取值范圍都是0到24。當(dāng)osd_scrub_begin_hour小于osd_scrub_end_hour時,,允許時間段為[osd_scrub_begin_hour, osd_scrub_end_hour],;當(dāng)osd_scrub_begin_hour大于osd_scrub_end_hour時,允許的時間段為[osd_scrub_begin_hour, 24]和[0, osd_scrub_end_hour]兩部分,。因?yàn)?和24是重疊的,,所以實(shí)際上這兩個時間段是連續(xù)的。
預(yù)留
PG
|-- scrubber: Scrubber
|-- reserved: bool // 是否已預(yù)留
|-- reserve_failed: bool // 預(yù)留失敗,,只要一個Peer預(yù)留失敗就代表預(yù)留失敗
|-- reserved_peers: set<pg_shard_t> // 預(yù)留成功的Peer OSD
OSD
|-- scrubs_pending: int // 排隊(duì)的Scrub任務(wù)數(shù)目
|-- scrubs_active: int // 運(yùn)行的Scrub任務(wù)數(shù)目
// Replica處理預(yù)留請求
ReplicatedPG::do_request() --> ReplicatedPG::do_sub_op() --> PG::sub_op_scrub_reserve() --> OSDService::inc_scrubs_pending()
// Primary處理預(yù)留回復(fù)
ReplicatedPG::do_request() --> ReplicatedPG::do_sub_op_reply() --> PG::sub_op_scrub_reserve_reply() --> PG::sched_scrub()
ScrubJob滿足調(diào)度條件后開始執(zhí)行Scrub前需要向PG的所有OSD節(jié)點(diǎn)申請預(yù)留,,只有預(yù)留成功后才允許開始Scrub操作。預(yù)留的目的是為了限制OSD進(jìn)程內(nèi)同時進(jìn)行Scrub任務(wù)的個數(shù),。Ceph將Scrub任務(wù)的狀態(tài)劃分為兩類:一類是已經(jīng)在運(yùn)行,,另一類是正在預(yù)留階段還沒開始執(zhí)行的。只有這兩類的Scrub任務(wù)總數(shù)低于osd_max_scrubs配置時才能夠預(yù)留成功,。osd_max_scrubs默認(rèn)值為1,,也就是說OSD進(jìn)程同一時刻最多只能運(yùn)行一個Scrub任務(wù)。 只有PG的所有OSD節(jié)點(diǎn)都預(yù)留成功后,,Ceph才開始向mClock隊(duì)列投遞PGScrub Op開始真正的Scrub操作,。
比較
PG
|-- scrubber: Scrubber
|-- store: std::unique_ptr<Scrub::Store>
|-- waiting_on: int // 未完成Scrub的Secondary OSD的數(shù)目
|-- waiting_on_whom: set<pg_shard_t> // 未完成Scrub的Secondary OSD
|-- received_maps: map<pg_shard_t, ScrubMap> // Secondary OSD的ScrubMap
|-- subset_last_update: eversion_t // 影響chunk中object的最近的版本號
|-- active_rep_scrub: OpRequestRef // (備OSD)等待subset_last_update版本完成
|-- queue_snap_trim: bool // Scrub結(jié)束后執(zhí)行SnapTrim,也就是說,,Scrub和SnapTrim不能同時執(zhí)行
PGQueueable::RunVis::operator(PGScrub) --> PG::scrub() --> PG::chunky_scrub()
執(zhí)行Scrub操作的主要邏輯:首先選出一組Object,,Object的個數(shù)由osd_scrub_chunk_min和osd_scrub_chunk_max兩個配置決定;然后向PG的其它OSD節(jié)點(diǎn)請求ScrubMap,;接收到所有Peer OSD節(jié)點(diǎn)的ScrubMap后進(jìn)行比較,。同Recovery一樣,此處要考慮一個PGScrub Op和Object的對應(yīng)關(guān)系,。
SnapTrim
配置項(xiàng) |
默認(rèn)值 |
說明 |
osd_snap_trim_cost |
1MB |
|
osd_snap_trim_priority |
5 |
|
osd_snap_trim_sleep |
0 |
兩次PGSnapTrim請求間休眠時間 |
osd_pg_max_concurrent_snap_trims |
2 |
每個PGSnapTrim對應(yīng)的Object數(shù)目 |
客戶端刪除快照
從客戶端來說,,快照整體上應(yīng)該同時包含RBD塊快照和CephFS快照兩種類型,本節(jié)只考慮RBD塊的快照,。RBD塊的快照數(shù)據(jù)包含兩部分內(nèi)容:一部分是存儲塊級別的快照元數(shù)據(jù),,保存在header對象的OMAP;另一部分是Object級別的快照信息,,這部分又由保存在Object屬性中的快照元數(shù)據(jù)和Clone Object兩部分內(nèi)容構(gòu)成,。Ceph刪除這兩部分內(nèi)容的方式不同。
// RBD客戶端向OSD發(fā)送刪除快照的消息
rbd::Shell::execute() --> rbd::action::snap::execute_remove() --> rbd::action::snap::do_remove_snap() --> librbd::Image::snap_remove2() --> librbd::snap_remove() --> librbd::Operations<librbd::ImageCtx>::snap_remove() --> Operations<I>::snap_remove() --> librbd::Operations<librbd::ImageCtx>::execute_snap_remove() --> librbd::operation::SnapshotRemoveRequest::send() --> cls_client::snapshot_remove() --> ... --> 發(fā)送op給rbd_header對象所在的Primary OSD
// OSD刪除快照信息
cls_rbd::snapshot_remove() --> cls_cxx_map_remove_key() --> ReplicatedPG::do_osd_ops(CEPH_OSD_OP_OMAPRMKEYS)
// RBD客戶端向Monitor發(fā)送刪除快照的消息
librbd::operation::SnapshotRemoveRequest::send() --> SnapshotRemoveRequest<I>::send_release_snap_id() --> Objecter::delete_selfmanaged_snap() -->
Objecter::pool_op_submit() --> Objecter::_pool_op_submit() --> MonClient::send_mon_message()
// Monitor刪除快照信息
OSDMonitor::prepare_pool_op() --> pg_pool_t::remove_unmanaged_snap() --> pg_pool_t::removed_snaps
對第一部分內(nèi)容,,RBD客戶端直接向header對象所在的Primary OSD發(fā)送CEPH_OSD_OP_OMAPRMKEYS消息,,立即刪除。對第二部分內(nèi)容,Ceph采用異步策略:先向Monitor節(jié)點(diǎn)發(fā)送刪除快照的請求,,Monitor回復(fù)后客戶端即可退出,,宣告快照已被刪除。同時,,Monitor修改OSDMap中和快照相關(guān)的數(shù)據(jù)構(gòu)建OSDMap增量,,并在適當(dāng)?shù)臅r候?qū)⑿掳鍻SDMap分發(fā)給相關(guān)OSD節(jié)點(diǎn),OSD節(jié)點(diǎn)接收到新OSDMap后獲得待刪除快照,,從而開始刪除Object級別的快照信息,。
ReplicatedPG(PG)
|-- snap_trimq: interval_set<snapid_t> // 待刪除的快照列表
|-- pool: PGPool
|-- cached_removed_snaps: interval_set<snapid_t> // 總的快照列表
|-- newly_removed_snaps: interval_set<snapid_t> // 一次更新中,新產(chǎn)生的待刪除快照列表
// OSD處理MOSDMap消息,,掃描PG向Peering隊(duì)列投遞NullEvt事件
OSD::handle_osd_map() --> C_OnMapCommit::finish() --> OSD::_committed_osd_maps() --> OSD::consume_map() --> PG::queue_null() --> PG::queue_peering_event()
// OSD Peer工作線程處理NullEvt事件
OSD::process_peering_events() --> OSD::advance_pg() --> PG::handle_advance_map() -->
1. PGPool::update() // 更新PGPool中待刪除的快照列表
2. RecoveryState::handle_event(AdvMap) --> RecoveryState::Active::react(AdvMap)--> ReplicatedPG::kick_snap_trim() --> SnapTrimmer::process_event(KickTrim) // 更新snap_trimq,,通知狀態(tài)機(jī)開始刪除快照對象
OSD分別在PG::snap_trimq和PGPool中保持了待刪除快照列表,真正開始刪除數(shù)據(jù)時從PG::snap_trimq中取快照,。為什么要在兩個地方保存待刪除快照?估計(jì)考慮到了PG Recovery的不同狀態(tài),,在PG切換到Active狀態(tài)時會將PGPool中的待刪除列表賦值給snap_trimq,。如果更新OSDMap時,PG恰好處于Active狀態(tài)那么將同時更新PGPool和snap_trimq,。上面給出了更新OSDMap時更新待刪除快照列表的流程,。
OSD刪除快照數(shù)據(jù)
ReplicatedPG(PG)
|-- snap_trimmer_machine: SnapTrimmer
| |-- NotTrimming // 狀態(tài)機(jī)初始狀態(tài)
| |-- AwaitAsyncWork // 工作狀態(tài)
| |-- WaitRWLock
| |-- WaitScrub // 等待Scrub結(jié)束
| |-- WaitRepops // 等待Replica完成快照對象刪除
|-- snap_trimq: interval_set<snapid_t> // 待刪除的快照列表
|-- snap_mapper: SnapMapper
// PGSnapTrim入ShardedOpWq隊(duì)列
AwaitAsyncWork::AwaitAsyncWork() --> OSDService::queue_for_snap_trim()
// PGSnapTrim出ShardedOpWq隊(duì)列
PGQueueable::RunVis::operator(PGSnapTrim) --> ReplicatedPG::snap_trimmer() --> AwaitAsyncWork::react(DoSnapWork) --> ReplicatedPG::simple_opc_submit() --> ReplicatedPG::issue_repop() --> ReplicatedBackend::submit_transaction() --> ReplicatedBackend::issue_op()
同Recovery、Scrub一樣,,SnapTrim也是通過控制PGSnapTrim來間接控制快照刪除的整體速度,。一個SnapTrim默認(rèn)對應(yīng)刪除兩個對象的快照,由osd_pg_max_concurrent_snap_trims配置決定,。
|