Ceph QoS初探(下)

存儲QoS是個可以做很大也可以做很小的特性。SolidFire認為將QoS歸類為特性太兒戲,QoS應該是存儲系統(tǒng)設計之初就要仔細考慮的架構問題。的確,分析了一眾主流存儲大廠后還是覺得它在這方面做得最細致最全面。同時也有些廠商做得比較簡陋,只提供了帶寬或者IOPS的限速功能。這或許在某些場景中已經夠用,但我認為一個完整的QoS方案至少要包括對帶寬、IOPS的預留、上限和優(yōu)先級控制,如果再精細點還可以考慮IO的粒度、延遲、突發(fā)、空間局部性、系統(tǒng)內部IO、用戶IO、緩存、磁盤等要素。

分布式存儲都有很長的IO路徑,簡單的IOPS限速功能通常在路徑的最前端實現(xiàn)。例如OpenStack Cinder默認使用QEMU完成存儲塊的限速功能,QEMU對存儲來說已經屬于客戶端的角色了。

QoS的本質總結起來就四個字:消此長彼,它并不會提高系統(tǒng)整體處理能力,只是負責資源的合理分配。據(jù)此就可以提出一連串問題了:首先,如何知道什么時候該消誰什么時候該長誰?其次,該怎么消該怎么長?這兩個問題QoS算法可以幫忙解決,可以參考我的另外一篇文章《聊聊dmclock算法》。在這兩個問題之前還需要選擇一塊風水寶地,能夠控制希望可以控制的IO,否則即使知道何時控制以及如何控制也鞭長莫及無能為力。風水寶地的選擇可以參考我的另外一篇文章《拆開Ceph看線程和隊列》。

對Ceph來說,OSD的ShardedOpWq隊列是個不錯的選擇,因為幾乎所有重量級的IO都會經過該隊列。這些IO可以劃分為兩大類,一類是客戶端過來的IO,包括文件、對象和塊存儲;另一類是系統(tǒng)內部活動產生的IO,包括副本復制、Scrub、Recovery和SnapTrim等。第一類IO由于涉及到一些敏感內容暫不考慮,本文主要分析第二類IO,這也是本文叫做下篇的原因。

Recovery

| 配置項 | 默認值 | 說明 |
|:--|
| osd_recovery_threads | 1 | Recovery線程池中線程的個數(shù)
wipe_dmclock2分支已經禁用該線程池 |
| osd_max_backfills | 1 | 同時進行恢復的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對應的Object個數(shù) |
| osd_recovery_delay_start | 0 | 推遲Recovery開始時間 |
| osd_recovery_sleep | 0 | 出隊列后先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隊列時配置,待補充|
| osd_recovery_priority | 5 | 入ShardOpWq隊列時配置,待補充|

Recovery自己已經具備了一些優(yōu)先級控制的功能,上表給出了一些控制參數(shù),下面一一介紹下每個參數(shù)的作用。

Ceph主線分支中Recovery擁有獨立的工作隊列和線程池,線程池的線程數(shù)目由配置項osd_recovery_threads指定,默認為1。Ceph wip_dmclock2分支取消了Recovery的工作隊列和線程池,轉而將Recovery Op入ShardOpWq隊列。這樣Recovery Op和其它類型Op在相同的隊列,因此理論上會有更好的控制效果。

預留

OSDService
    |-- remote_reserver: AsyncReserver<spg_t>
    |-- local_reserver: AsyncReserver<spg_t>
        |-- queues: map<unsigned, list<pair<T, Context*> > >  // Key為pg恢復的優(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  // 調用queues中Context的隊列
        |-- max_allowed: unsigned  // osd_max_backfills配置項
        |-- min_priority: unsigned  // osd_min_recovery_priority配置項

1. WaitLocalRecoveryReserved::WaitLocalRecoveryReserved() --> AsyncReserver::request_reservation() --> AsyncReserver::do_queues()
2. QueuePeeringEvt::finish() --> PG::queue_peering_event(LocalRecoveryReserved)  // 由AsyncReserver的Finish線程調用

在開始恢復數(shù)據(jù)前Ceph會先進行預留,預留的其中一個目的是控制不同PG恢復的優(yōu)先級。預留通過AsyncReserver類實現(xiàn),該類包含了一個優(yōu)先級隊列queues,預留時先將PG入優(yōu)先級隊列,再根據(jù)PG的優(yōu)先級從高到低的順序出隊列,優(yōu)先級越高的PG越先恢復。雖然AsyncReserver以PG為單位進行優(yōu)先級控制,但事實上用戶以Pool為單位設置PG的優(yōu)先級。Ceph的ceph osd pool set recovery_priority命令用于設置Pool的Recovery優(yōu)先級,屬于同個Pool的PG具有相同的優(yōu)先級。

預留的另一個目的是控制OSD中同時進行恢復的PG數(shù)目。AsyncReserver::max_allowed限制PG出隊列,若正在處理的PG數(shù)目超過max_allowed則后面的請求將留在隊列內直到其它PG完成恢復后才出隊列。預留會同時考慮Primary OSD和Replica OSD,Primary OSD通過local_reserver來預留,Replica OSD通過remote_reserver來預留,默認每個AsyncReserver同一個時刻只允許一個PG進行恢復。因為一個OSD同時為某些PG的Primary為另一些PG的Replica,所以一個OSD同一時刻只允許兩個PG進行恢復。

恢復

PGRecovery
    |-- reserved_pushes: uint64_t

OSDService
    |-- awaiting_throttle: list<pair<epoch_t, PGRef> >
    |-- recovery_ops_reserved: uint64_t  // 預留的ops,進ShardOp隊列的recovery請求數(shù)
    |-- recovery_ops_active: uint64_t
    |-- defer_recovery_until: utime_t  //  允許Recovery啟動的時間
    |-- recovery_paused: bool  // 暫停Recovery,通過OSDMap來設置

// 狀態(tài)機進入Recoverying狀態(tài),將PGRecovery Op入ShardOpWq隊列
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目標OSD,PushOp Object的詳細內容
    |-- pulls: map<pg_shard_t, vector<PullOp>>  // pg_shard_t目標OSD,PullOp Object的詳細內容

MOSDPGPush
    |-- pushes: vector<PushOp>

// 出ShardOpWq隊列
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隊列只控制MOSDOp請求的速度,通過MOSDOp來間接控制MOSDRepOp請求。Recovery也采用類似的策略,mClock隊列控制PGRecovery出隊列的速度,而每個PGRecovery可能對應多個Object的恢復,通過PGRecovery間接控制Object的恢復。

除了在mClock隊列中控制PGRecovery速度外,Ceph還提供了多種手段來控制PGRecovery到Object的映射關系。首先,限制每個PGRecovery對應的Object的數(shù)目,由osd_recovery_max_single_start配置決定,默認為1。也就說,每個PGRecovery默認只能恢復一個Object。其次,限制活動的Object恢復操作,由osd_recovery_max_active配置決定。Ceph將恢復Op分為兩類:一類是Active恢復操作代表已經正在恢復的操作;另一類是預留的恢復操作,代表正在mClock隊列等候的PGRecovery對應的恢復操作。當PGRecovery入mClock隊列時,根據(jù)這兩類操作數(shù)以及osd_recovery_max_active來限制PGRecovery允許的Object個數(shù)。最后限制恢復請求中對象的個數(shù)和大小,由osd_max_push_costosd_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都恢復后,Primary重新向ShardOp隊列投遞PGRecovery請求,ShardOp線程開始下個Object的恢復。所有Object都恢復后ShardOp線程使用AllReplicasRecovered事件將狀態(tài)機從Recovering狀態(tài)切換到Recovered狀態(tài),同時釋放Replica的預留。最后,如果所有節(jié)點都Active,則從Recovered狀態(tài)切換到Clean狀態(tài)。

(Deep)Scrub

| 配置項 | 默認值 | 說明 |
|:--|
| osd_scrub_chunk_min | 5 | PGScrub對應的Object數(shù)目的最小值 |
| osd_scrub_chunk_max | 25 | PGScrub對應的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的時間段的結束時間,結束時間可以小于起始時間|
| osd_scrub_auto_repair | false | 自動repair不一致Object,不支持副本池,只支持EC池|
| osd_max_scrubs | 1 | OSD允許同時運行的Scrub任務的最大數(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任務 |
| osd_scrub_load_threshold | 0.5 | 只有負載低于該值時才允許觸發(fā)Scrub |

同前端IO和Recovery一樣,Ceph通過控制PGScrub來間接控制Scrub的所有IO優(yōu)先級。

啟動

OSDService
    |-- sched_scrub_pg: set<ScrubJob>  // 已注冊的Scrub任務
        |-- sched_time: utime_t  // 任務開始執(zhí)行的時間
        |-- deadline: utime_t

// 注冊ScrubJob
PG::reg_next_scrub()  --> OSD::reg_pg_scrub() --> OSD::sched_scrub_pg

// 調度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相關命令時都會注冊ScrubJob,每個ScrubJob包含一個任務開始時間(sched_time)和一個最終時間(deadline)。默認情況下,ScrubJob::sched_time小于當前時間+osd_scrub_min_interval,ScrubJob::deadline為當前時間+osd_scrub_max_interval,注冊任務后正常情況在一天內執(zhí)行,特殊情況一周內執(zhí)行。

OSD進程啟動時初始化C_Tick_WithoutOSDLock定時器,定時器默認每隔18秒檢查一次OSD中已注冊的ScrubJob,對滿足條件的ScrubJob開始執(zhí)行預留操作。檢查的內容包括以下幾項:

  • 檢查是否到達ScrubJob的開始時間(sched_time),沒到達不執(zhí)行;
  • 在有Recovery Op的情況下,檢查 osd_scrub_during_recovery配置是否允許同時執(zhí)行Scrub任務;
  • 檢查PG是否為Active狀態(tài),非Active不允許執(zhí)行;
  • 檢查ScrubJob是否超期(deadline);
  • 檢查當前時間是否位于允許Scrub的時間段內并且系統(tǒng)負載也在允許范圍內。

特別注意在ScrubJob已經超期的情況下將忽略最后一個限制條件強制執(zhí)行Scrub任務。另外值得一提的是Scrub時間段,它由osd_scrub_begin_hour和osd_scrub_end_hour兩個配置項控制。osd_scrub_begin_hour可以小于也可以大于osd_scrub_end_hour,它們兩的取值范圍都是0到24。當osd_scrub_begin_hour小于osd_scrub_end_hour時,允許時間段為[osd_scrub_begin_hour, osd_scrub_end_hour];當osd_scrub_begin_hour大于osd_scrub_end_hour時,允許的時間段為[osd_scrub_begin_hour, 24]和[0, osd_scrub_end_hour]兩部分。因為0和24是重疊的,所以實際上這兩個時間段是連續(xù)的。

預留

PG
    |-- scrubber: Scrubber
        |-- reserved: bool  // 是否已預留
        |-- reserve_failed: bool // 預留失敗,只要一個Peer預留失敗就代表預留失敗
        |-- reserved_peers: set<pg_shard_t>  // 預留成功的Peer OSD

OSD
    |-- scrubs_pending: int  // 排隊的Scrub任務數(shù)目
    |-- scrubs_active: int  // 運行的Scrub任務數(shù)目

// Replica處理預留請求
ReplicatedPG::do_request() --> ReplicatedPG::do_sub_op() --> PG::sub_op_scrub_reserve() --> OSDService::inc_scrubs_pending()

// Primary處理預留回復
ReplicatedPG::do_request() --> ReplicatedPG::do_sub_op_reply() --> PG::sub_op_scrub_reserve_reply() --> PG::sched_scrub()

ScrubJob滿足調度條件后開始執(zhí)行Scrub前需要向PG的所有OSD節(jié)點申請預留,只有預留成功后才允許開始Scrub操作。預留的目的是為了限制OSD進程內同時進行Scrub任務的個數(shù)。Ceph將Scrub任務的狀態(tài)劃分為兩類:一類是已經在運行,另一類是正在預留階段還沒開始執(zhí)行的。只有這兩類的Scrub任務總數(shù)低于osd_max_scrubs配置時才能夠預留成功。osd_max_scrubs默認值為1,也就是說OSD進程同一時刻最多只能運行一個Scrub任務。 只有PG的所有OSD節(jié)點都預留成功后,Ceph才開始向mClock隊列投遞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結束后執(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é)點請求ScrubMap;接收到所有Peer OSD節(jié)點的ScrubMap后進行比較。同Recovery一樣,此處要考慮一個PGScrub Op和Object的對應關系。

SnapTrim

| 配置項 | 默認值 | 說明 |
|:--|
| osd_snap_trim_cost | 1MB | |
| osd_snap_trim_priority | 5 | |
| osd_snap_trim_sleep | 0 | 兩次PGSnapTrim請求間休眠時間 |
| osd_pg_max_concurrent_snap_trims | 2 | 每個PGSnapTrim對應的Object數(shù)目 |

客戶端刪除快照

從客戶端來說,快照整體上應該同時包含RBD塊快照和CephFS快照兩種類型,本節(jié)只考慮RBD塊的快照。RBD塊的快照數(shù)據(jù)包含兩部分內容:一部分是存儲塊級別的快照元數(shù)據(jù),保存在header對象的OMAP;另一部分是Object級別的快照信息,這部分又由保存在Object屬性中的快照元數(shù)據(jù)和Clone Object兩部分內容構成。Ceph刪除這兩部分內容的方式不同。

// 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

對第一部分內容,RBD客戶端直接向header對象所在的Primary OSD發(fā)送CEPH_OSD_OP_OMAPRMKEYS消息,立即刪除。對第二部分內容,Ceph采用異步策略:先向Monitor節(jié)點發(fā)送刪除快照的請求,Monitor回復后客戶端即可退出,宣告快照已被刪除。同時,Monitor修改OSDMap中和快照相關的數(shù)據(jù)構建OSDMap增量,并在適當?shù)臅r候將新版OSDMap分發(fā)給相關OSD節(jié)點,OSD節(jié)點接收到新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>  // 一次更新中,新產生的待刪除快照列表

// OSD處理MOSDMap消息,掃描PG向Peering隊列投遞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)機開始刪除快照對象

OSD分別在PG::snap_trimq和PGPool中保持了待刪除快照列表,真正開始刪除數(shù)據(jù)時從PG::snap_trimq中取快照。為什么要在兩個地方保存待刪除快照?估計考慮到了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)機初始狀態(tài)
    |    |-- AwaitAsyncWork  // 工作狀態(tài)
    |    |-- WaitRWLock
    |    |-- WaitScrub  // 等待Scrub結束
    |    |-- WaitRepops  // 等待Replica完成快照對象刪除
    |-- snap_trimq: interval_set<snapid_t>  // 待刪除的快照列表
    |-- snap_mapper: SnapMapper

// PGSnapTrim入ShardedOpWq隊列
AwaitAsyncWork::AwaitAsyncWork() --> OSDService::queue_for_snap_trim()

// PGSnapTrim出ShardedOpWq隊列
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默認對應刪除兩個對象的快照,由osd_pg_max_concurrent_snap_trims配置決定。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • ceph簡介 Ceph是一個分布式存儲系統(tǒng),誕生于2004年,是最早致力于開發(fā)下一代高性能分布式文件系統(tǒng)的項目。隨...
    愛吃土豆的程序猿閱讀 6,171評論 0 21
  • 1. 簡介 在傳統(tǒng)分布式存儲架構中,存儲節(jié)點往往僅作為被動查詢對象來使用,隨著存儲規(guī)模的增加,數(shù)據(jù)一致性的管理會出...
    chnmagnus閱讀 10,297評論 4 5
  • 朱 榮澤| 2013.09.09 https://www.ustack.com/blog/ceph_infra/ ...
    守望者_1065閱讀 2,623評論 0 1
  • 原因:2017年4月14日 星期五 學習記錄。說明:整理ceph資料。我的博客 : http://minichao...
    nicocoi閱讀 8,384評論 1 9
  • 集群管理 每次用命令啟動、重啟、停止Ceph守護進程(或整個集群)時,必須指定至少一個選項和一個命令,還可能要指定...
    Arteezy_Xie閱讀 19,908評論 0 19

友情鏈接更多精彩內容