1. 程式人生 > >ceph(3)--Ceph 物理和邏輯結構

ceph(3)--Ceph 物理和邏輯結構

gre network 鏡像 操作記錄 share 速度 深度優先 cache 訪問

本系列文章會深入研究 Ceph 以及 Ceph 和 OpenStack 的集成:

(1)安裝和部署

(2)Ceph RBD 接口和工具

(3)Ceph 物理和邏輯結構

(4)Ceph 的基礎數據結構

(5)Ceph 與 OpenStack 集成的實現

(6)QEMU-KVM 和 Ceph RBD 的 緩存機制總結

(7)Ceph 的基本操作和常見故障排除方法

(8)關於Ceph PGs

1. Ceph 集群的物理結構

1.1 Ceph 內部集群

從前一篇文章 我們知道,從物理上來講,一個 Ceph 集群內部其實有幾個子集群存在:

(1)MON(Montior)集群:MON 集群有由少量的、數目為奇數個的 Monitor 守護進程(Daemon)組成,它們負責通過維護 Ceph Cluster map 的一個主拷貝(master copy of Cluster map)來維護整 Ceph 集群的全局狀態。理論上來講,一個 MON 就可以完成這個任務,之所以需要一個多個守護進程組成的集群的原因是保證高可靠性。每個 Ceph node 上最多只能有一個 Monitor Daemon。

root@ceph1:~# ps -ef | grep ceph-mon
root       964     1  0 Sep18 ?        00:36:33 /usr/bin/ceph-mon --cluster=ceph -i ceph1 -f

實際上,除了維護 Cluster map 以外,MON 還承擔一些別的任務,比如用戶校驗、日誌等。詳細的配置可以參考 MON 配置。

(2)OSD (Object Storage Device)集群:OSD 集群由一定數目的(從幾十個到幾萬個) OSD Daemon 組成,負責數據存儲和復制,向 Ceph client 提供存儲資源。每個 OSD 守護進程監視它自己的狀態,以及別的 OSD 的狀態,並且報告給 Monitor;而且,OSD 進程負責在數據盤上的文件讀寫操作;它還負責數據拷貝和恢復。在一個服務器上,一個數據盤有一個 OSD Daemon。

root@ceph1:~# ps -ef | grep ceph-osd
root      1204     1  0 Sep18 ?        00:24:39 /usr/bin/ceph-osd --cluster=ceph -i 3 -f
root      2254     1  0 Sep18 ?        00:20:52 /usr/bin/ceph-osd --cluster=ceph -i 6 -f

(3)若幹個數據盤:一個Ceph 存儲節點上可以有一個或者多個數據盤,每個數據盤上部署有特定的文件系統,比如 xfs,ext4 或者 btrfs,由一個 OSD Daemon 負責照顧其狀態以及向其讀寫數據。

Disk /dev/vda: 21.5 GB, 21474836480 bytes
/dev/vda1               1    41943039    20971519+  ee  GPT
Disk /dev/vdb: 32.2 GB, 32212254720 bytes
/dev/vdb1               1    62914559    31457279+  ee  GPT

技術分享圖片 技術分享圖片(MON 和 OSD 可以共同在一個節點上,也可以分開)

關於Ceph 支持的數據盤上的 xfs、ext4 和 btrfs 文件系統,它們都是日誌文件系統(其特點是文件系統將沒提交的數據變化保存到日誌文件,以便在系統崩潰或者掉電時恢復數據),三者各有優勢和劣勢:

  • btrfs (B-tree 文件系統) 是個很新的文件系統(Oracel 在2014年8月發布第一個穩定版),它將會支持許多非常高大上的功能,比如 透明壓縮( transparent compression)、可寫的COW 快照(writable copy-on-write snapshots)、去重(deduplication )和加密(encryption )。因此,Ceph 建議用戶在非關鍵應用上使用該文件系統。 更多的參考包括 (1)(2)(3)。
  • xfs 和 btrfs 相比較ext3/4而言,在高伸縮性數據存儲方面具有優勢。
  • Ceph 的這篇文章 明確推薦在生產環境中使用 XFS,在開發、測試、非關鍵應用上使用 btrfs。
  • 網上有很多的文章比較這幾種文件系統,包括:
    • ext3,ext4,xfs和btrfs文件系統性能對比
    • 固態硬盤上 Ext4 和 xfs 性能比較
    • 哇,讓你的DB再快一倍:ext4 vs xfs對比測試
    • XFS --if it‘s more robust, why are we using ext4 instead?

(4)要使用 CephFS,還需要 MDS 集群,用於保存 CephFS 的元數據

(5)要使用對象存儲接口,還需要 RADOS Gateway, 它對外提供REST接口,兼容S3和Swift的API。

1.2 Ceph 網絡結構

Ceph 使用以太網連接內部各存儲節點以及連接 client 和集群。Ceph 推薦使用兩個網絡:

  • 前端(北向)網絡( a public (front-side) network)連接客戶端和集群
  • 後端/東西向網絡 (a cluster (back-side) network)來連接 Ceph 各存儲節點

下圖(來源)顯示了這種網絡拓撲結構:

技術分享圖片

這麽做,主要是從性能(OSD 節點之間會有大量的數據拷貝操作)和安全性(兩網分離)考慮。你可以在 Ceph 配置文件的 [global] 部分配置兩個網絡:

public network = {public-network/netmask}
cluster network = {cluster-network/netmask}

具體可以參考:

  • Deploying Ceph with High Performance Networks, Architectures and benchmarks for Block Storage Solutions
  • Deploying Ceph with High Performance Networks
  • CHAPTER 2. NETWORKING RECOMMENDATIONS
  • Ceph with a cluster and public network on IPv6 談到了 IPV6 的支持。

1.3 RDB Cache (緩存)

1.3.1 常見的 Write Cache 種類

緩存種類 說明 優劣勢 適合場景
Write-through(直寫) 這種緩存方式在寫 I/O 時把數據放入緩存,同時直接寫入底層的持久存儲,然後再向主機確認寫入操作完成。 安全地保存數據,從緩存讀,減少了讀操作的延遲,但是寫操作 的延遲沒得到優化 適合於寫較少,但是頻繁度的應用
Write-back (回寫) 數據直接寫入緩存,然後向主機返回寫入完成。 對頻繁寫應用減少了寫的延遲,但是有數據丟失風險 對讀寫混合型應用有優勢,但是需要考慮數據保護

緩存的通常位置分類:

  • 服務器(主機)上:RAID 卡或者 HBA 卡上做緩存。
  • VMM 內:在 Hypervisor 上做緩存。
  • 客戶機操作系統內:以 Windows 2012 為例,它提供 write-back 緩存機制。

更多資料,可以參考 Cache is vital for application deployment, but which one to choose。

1.3.2 Ceph RBD 緩存

默認情況下,Ceph RBD 是不使用緩存的,讀和寫直接到 Ceph 集群中的存儲,寫只有在所有 replica 上寫都完成後才給客戶端返回寫完成。Ceph 在較新的版本上陸續添加了 RBD 緩存支持:

  • 從 0.46 版本開始,Ceph 支持 write-back 緩存,你可以在 ceph.conf 文件的 [client] 部分添加 rbd cache = true 來使得 write-back 緩存生效。這時候,寫幾乎是立即返回,但是數據只有在被 flushed 後才寫入到實際存儲。
  • 從 0.47 版本開始,Ceph 支持 write-through 緩存機制。你只需要再添加配置項 rbd cache max dirty = 0 即可。
  • 從 0.60 版本開始,Ceph 支持 rbd cache writethrough until flush 配置項。設置它為 true 時,會使得 write-through 機制變得更加安全,因為老的客戶機操作系統(2.6.32 內核版本之前)可能不支持 flush 操作。因此,在設置了該配置項為 true 時,即使用戶設置了使用 write-through 機制,Ceph 也會自動使用 write-back 機制,直到它收到第一個 flush 指令後才真正使用 write-through。

可見 RBD 緩存是在客戶端做的,見如下圖示:

技術分享圖片

更多信息,可以參考我的另一篇文章:QEMU-KVM 和 Ceph RBD 的 緩存機制總結

1.3.3 Cache tiering (緩存分層)

Ceph 還支持在集群段做緩存分層。其原理是,在較快的磁盤比如 SSD 上建立一個 cache pool,在建立存儲池(storage pool)和它之間的 cache 關系,設置一定的緩存策略,實現類似於在客戶端緩存同樣的效果。

技術分享圖片

更多的信息及詳細配置,參見 CACHE TIERING 和 Intel 的文章。

1.3.4 RBD Cache 和 Cache Tiering 的區別

從上面的分析可以看出來,兩者的區別在於緩存的位置不同:

  • Cache tiering 是 RADOS 層在 OSD 端進行數據緩存,也就是說不論是塊存儲、對象存儲還是文件存儲都可以使用tier來提高讀寫速度
  • RBD Cache是 rbd 層在客戶端的緩存,也就是只支持塊存儲。

Rbd cache是 客戶端的緩存,當多個客戶端使用同個塊設備時,存在客戶端數據不一致的問題。舉個例子,用戶A向塊設備寫入數據後,數據停留在客戶自己的緩存中,沒有立即刷新到磁盤,所以其它用戶讀取不到A寫入的數據。但是tier不存在這個問題,因為所有用戶的數據都直接寫入到 ssd,用戶讀取數據也是在ssd中讀取的,所以不存在客戶端數據不一致問題。

一般地,Tier 使用 SSD 做緩存,而 Rbd cache 只能使用內存做緩存。SSD和內存有兩個方面的差別,一個是讀寫速度、另一個是掉電保護。掉電後內存中的數據就丟失了,而ssd中的數據不會丟失。

2. Ceph 集群的邏輯結構(以RBD為例)

Ceph 集群的邏輯結構由 Pool 和 PG (Placement Group)來定義。

2.1 Pool

一個 Pool 是 Ceph 中的一些對象的邏輯分組,它並不表示一個連續的分區,而只是一個邏輯概念,類似於將二進制數據打了tag一樣然後根據tag歸類一樣。它類似於 LVM 中的 Volume Group,類似於一個命名空間。RBD Image 類似於 LVM 中的 Logical Volume。RBD Image 必須且只能在一個 Pool 中。Pool 由若幹個PG組成。其屬性包括:

  • 所有性和訪問權限
  • 對象副本數目
  • PG 數目
  • CRUSH 規則集合

Ceph Pool 有兩種類型:

  1. Replicated pool:拷貝型 pool,通過生成對象的多份拷貝來確保在部分 OSD 丟失的情況下數據不丟失。這種類型的 pool 需要更多的裸存儲空間,但是它支持所有的 pool 操作。
  2. Erasure-coded pool:糾錯碼型 pool(類似於 Software RAID)。在這種 pool 中,每個數據對象都被存放在 K+M 個數據塊中:對象被分成 K 個數據塊和 M 個編碼塊;pool 的大小被定義成 K+M 塊,每個塊存儲在一個 OSD 中;塊的順序號作為 object 的屬性保存在對象中。可見,這種 pool 用更少的空間實現存儲,即節約空間;糾刪碼實現了高速的計算,但有2個缺點,一個是速度慢,一個是只支持對象的部分操作(比如:不支持局部寫)。這篇文章 詳細介紹了其原理和細節。

Pool 提供如下的能力:

  1. Resilience(彈力):即在確保數據不丟失的情況允許一定的 OSD 失敗,這個數目取決於對象的拷貝(copy/replica)份數。對拷貝型 pool 來說,Ceph 中默認的拷貝份數是2,這意味著除了對象自身外,它還有一個另外的備份。你可以自己決定一個 Pool 中的對象的拷貝份數。
  2. Placement Groups(放置組):Ceph 使用 PG 來組織對象,這是因為對象可能成千上萬,因此一個一個對象來組織的成本是非常高的。PG 的值會影響 Ceph 集群的行為和數據的持久性。你可以設置 pool 的 PG 數目。推薦的配置是,每個 OSD 大概 100 個 PG。
  3. CRUSH Rules (CRUSH 規則):數據映射的策略。系統默認提供 “replicated_ruleset"。用戶可以自定義策略來靈活地設置 object 存放的區域。比如可以指定 pool1中所有objecst放置在機架1上,所有objects的第1個副本放置在機架1上的服務器A上,第2個副本分布在機架1上的服務器B上。 pool2中所有的object分布在機架2、3、4上,所有Object的第1個副本分布在機架2的服務器上,第2個副本分布在機架3的服 器上,第3個副本分布在機架4的服務器上。詳細的信息可以參考這些文檔 (1)(2)(3)(4)。
  4. Snapshots(快照):你可以對 pool 做快照。
  5. Set Ownership:設置 pool 的 owner 的用戶 ID。
  6. Ceph 集群創建後,默認創建了 data,metadata 和 rbd 三個存儲池。

2.2 (Placement Group)PG

2.2.1 概念

PG 概念非常復雜,主要有如下幾點:

  • PG 也是對象的邏輯集合。同一個PG 中的所有對象在相同的 OSD 上被復制。
  • PG 聚合一部分對象成為一個組(group),這個組被放在某些OSD上(place),合起來就是 Placemeng Group (放置組)了。
  • Epoch:PG map 的版本號,它是一個單調遞增的序列。
  • Peering:見下文的狀態(8)描述。詳細過程請參閱 Ceph:pg peering過程分析。
  • Acting set:支持一個 PG 的所有 OSD 的有序列表,其中第一個 OSD 是主OSD,其余為次。acting set 是 CRUSH 算法分配的,但是不一定已經生效了。
  • Up set:某一個 PG map 歷史版本的 acting set。在大多數情況下,acting set 和 up set 是一致的,除非出現了 pg_temp。
  • Current Interval or Past Interval:若幹個連續的版本號,這些版本中 acting 和 up set 保持不變。
  • PG temp:在Ceph 正在往主 OSD 回填數據時,這個主OSD是不能提供數據服務的,這時候,它會向 MON 申請一個臨時的 acting set,這就是 PG temp。舉個例子,現在 acting set 是[0,1,2],出現了一點事情後,它變為 [3,1,2],此時 osd.3 還是空的因此它無法提供數據服務因此它還需要等待backfilling過程結束,因此,它會向 MON 申請一個臨時的 set 比如 [1,2,3],此時將由 osd.1 提供數據服務。回填過程結束後,該臨時 set 會被丟棄,重新由 osd.3 提供服務。
  • 主 (primary) OSD:在 acting set 中的首個 OSD,負責接收客戶端寫入數據;默認情況下,提供數據讀服務,但是該行為可以被修改。它還負責 peering 過程,以及在需要的時候申請 PG temp。
  • 次 (replica)OSD:在 acting set 中的除了第一個以外的其余 OSD。
  • 流浪 (stray) OSD:已經不是 acting set 中了,但是還沒有被告知去刪除數據 的 OSD。
  • PG 的 acting set 是由 CRUSH 算法根據 CRUSH Rules 動態地計算得出的。

技術分享圖片 技術分享圖片

2.2.2 特點

其主要特點如下:

  • 基本特點
    • PG 確定了 pool 中的對象和 OSD 之間的映射關系。一個 object 只會存在於一個 PG 中,但是多個 object 可以在同一個 PG 內。
    • Pool 的 PG 數目是創建 pool 時候指定的,Ceph 官方有推薦的計算方法。其值與 OSD 的總數的關系密切。當Ceph 集群擴展 OSD 增多時,根據需要,可以增加 pool 的 PG 數目。
    • 對象的副本數目,也就是被拷貝的次數,是在創建 Pool 時指定的。該分數決定了每個 PG 會在幾個 OSD 上保存對象。如果一個拷貝型 Pool 的size(拷貝份數)為 2,它會包含指定數目的 PG,每個 PG 使用兩個 OSD,其中,第一個為主 OSD (primary),其它的為從 OSD (secondary)。不同的 PG 可能會共享一個 OSD。
    • Ceph 引入 PG 的目的主要是為了減少直接將對象映射到 OSD 的復雜度。
    • PG 也是Ceph 集群做清理(scrubbing)的基本單位,也就是說數據清理是一個一個PG來做的。
    • PG 和 OSD 之間的映射關系由 CRUSH 決定,而它做決定的依據是 CRUSH 規則(rules)。CRUSH 將所有的存儲設備(OSD)組織成一個分層結構,該結構能區分故障域(failure domain),該結構中每個節點都是一個 CRUSH bucket。詳細情況請閱讀 CRUSH 相關的文檔。
  • PG 和 OSD 的關系是動態的:
    • 一開始在 PG 被創建的時候,MON 根據 CRUSH 算法計算出 PG 所在的 OSD。這是它們之間的初始關系。
    • Ceph 集群中 OSD 的狀態是不斷變化的,它會在如下狀態之間做切換:
      • up:守護進程運行中,能夠提供IO服務;
      • down:守護進程不在運行,無法提供IO服務;
      • in:包含數據;
      • out:不包含數據
    • 部分 PG 和 OSD 的關系會隨著 OSD 狀態的變化而發生變化。
      • 當新的 OSD 被加入集群後,已有OSD上部分PG將可能被挪到新OSD上;此時PG 和 OSD 的關系會發生改變。
      • 當已有的某 OSD down 了並變為 out 後,其上的 PG 會被挪到其它已有的 OSD 上。
      • 但是大部分的 PG 和 OSD 的關系將會保持不變,在狀態變化時,Ceph 盡可能只挪動最少的數據。
    • 客戶端根據 Cluster map 以及 CRUSH Ruleset 使用 CRUSH 算法查找出某個 PG 所在的 OSD 列表(其實是 up set)。
    • PG-Object-OSD 的關系如下圖所示:

      技術分享圖片

  • PG 的創建過程(詳細過程請參考 PG 的創建過程):
    1. MON 節點上有PGMonitotor,它發現有 pool 被創建後,判斷該 pool 是否有 PG。如果有PG,則一一判斷這些 PG 是否已經存在,如果不存在,則開始下面的創建 PG 的過程。
    2. 創建過程的開始,設置PG 狀態為 Creating,並將它加入待創建PG隊列 creating_pgs,等待被處理。
    3. 開始處理後,使用 CRUSH 算法根據當前的 OSD map 找出來 up/acting set,加入 PG map 中以這個 set 中 OSD 為索引的隊列 creating_pgs_by_osd。(看起來只會加入到主OSD的隊列中)。
    4. 隊列處理函數將該 OSD 上需要創建的 PG 合並,生成消息MOSDPGCreate,通過消息通道發給 OSD。
    5. OSD 收到消息字為 MSG_OSD_PG_CREATE 的消息,得到消息中待創建的 PG 信息,判斷類型,並獲取該PG的其它OSD,加入隊列 creating_pgs (似乎是由主 OSD 負責發起創建次 OSD 上的PG),再創建具體的 PG。
    6. PG 被創建出來以後,開始 Peering 過程。
  • PG 值的確定:創建 pool 時需要確定其 PG 的數目,在 pool 被創建後也可以調整該數字,該數目會影響到:
    • 數據的持久性:考慮pool 的 size 為 3,表明每個 PG 會將數據存放在 3 個 OSD 上。當一個 OSD down 了後,一定間隔後將開始 recovery 過程,recovery結束前,有部分 PG 的數據將只有兩個副本。這時候和需要被恢復的數據的數量有關系,如果該 OSD 上的 PG 過多,則花的時間將越長,風險將越大。如果此時再有一個 OSD down 了,那麽將有一部分 PG 的數據只有一個副本,recovery 過程繼續。如果再出現第三個 OSD down 了,那麽可能會出現部分數據丟失。可見,每個 OSD 上的PG數目不宜過大,否則,會降低數據的持久性。這也就要求在添加 OSD 後,PG 的數目在需要的時候也需要相應增加。
    • 數據的均勻分布性:CRUSH 算法會偽隨機地保證 PG 被選中來存放客戶端的數據,它還會盡可能地保證所有的 PG 均勻分布在所有的 OSD 上。比方說,有10個OSD,但是只有一個 size 為 3 的 pool,它只有一個 PG,那麽10個 OSD 中將只有三個 OSD 被用到。但是 CURSH 算法在計算的時候不會考慮到OSD上已有數據的大小。比方說,100萬個4K對象共4G均勻地分布在10個OSD上的1000個PG內,那麽每個 OSD 上大概有400M 數據。再加進來一個400M的對象(假設它不會被分割),那麽有三塊 OSD 上將有 400M + 400M = 800 M 的數據,而其它七塊 OSD 上只有 400M 數據。

    • 資源消耗:PG 作為一個邏輯實體,它需要消耗一定的資源,包括內存,CPU 和帶寬。太多 PG 的話,則占用資源會過多。
    • 清理時間:Ceph 的清理工作是以 PG 為單位進行的。如果一個 PG 內的數據太多,則其清理時間會很長。

    那如何確定一個 Pool 中有多少 PG?Ceph 不會自己計算,而是給出了一些參考原則,讓 Ceph 用戶自己計算:

    • 少於 5 個 OSD, 建議設為 128
    • 5 到 10 個 OSD,建議設為 512
    • 10 到 50 個 OSD,建議設為 4096
    • 50 個 OSD 以上,就需要有更多的權衡來確定 PG 數目
    • 你可以使用 pgcalc 工具
  • PG 的狀態也是不斷變化的,其主要狀態包括:
    • Creating 創建中:PG 正在被創建。
    • Peering 對等互聯:表示一個過程,該過程中一個 PG 的所有 OSD 都需要互相通信來就PG 的對象及其元數據的狀態達成一致。處於該狀態的PG不能響應IO請求。Peering的過程其實就是pg狀態從初始狀態然後到active+clean的變化過程。一個 OSD 啟動之後,上面的pg開始工作,狀態為initial,這時進行比對所有osd上的pglog和pg_info,對pg的所有信息進行同步,選舉primary osd和replica osd,peering過程結束,然後把peering的結果交給recovering,由recovering過程進行數據的恢復工作。
    • Active 活動的:Peering 過程完成後,PG 的狀態就是 active 的。此狀態下,在主次OSD 上的PG 數據都是可用的。
    • Clean 潔凈的:此狀態下,主次 OSD 都已經被 peered 了,每個副本都就緒了。
    • Down:PG 掉線了,因為存放其某些關鍵數據(比如 pglog 和 pginfo,它們也是保存在OSD上)的副本 down 了。
    • Degraded 降級的:某個 OSD 被發現停止服務 (down)了後,Ceph MON 將該 OSD 上的所有 PG 的狀態設置為 degraded,此時該 OSD 的 peer OSD 會繼續提供數據服務。這時會有兩種結果:一是它會重新起來(比如重啟機器時),需要再經過 peering 過程再到clean 狀態,而且 Ceph 會發起 recovery (恢復)過程,使該 OSD 上過期的數據被恢復到最新狀態;二是 OSD 的 down 狀態持續 300 秒後其狀態被設置為 out,Ceph 會選擇其它的 OSD 加入 acting set,並啟動回填(backfilling)數據到新 OSD 的過程,使 PG 副本數恢復到規定的數目。詳情可以參考 PG 的數據恢復過程。
    • Recovering 恢復中:一個 OSD down 後,其上面的 PG 的內容的版本會比其它OSD上的 PG 副本的版本落後。在它重啟之後(比如重啟機器時),Ceph 會啟動 recovery 過程來使其數據得到更新。
    • Backfilling 回填中:一個新 OSD 加入集群後,Ceph 會嘗試級將部分其它 OSD 上的 PG 挪到該新 OSD 上,此過程被稱為回填。與 recovery 相比,回填(backfill)是在零數據的情況下做全量拷貝,而恢復(recovery)是在已有數據的基礎上做增量恢復。
    • Remapped 重映射:每當 PG 的 acting set 改變後,就會發生從舊 acting set 到新 acting set 的數據遷移。此過程結束前,舊 acting set 中的主 OSD 將繼續提供服務。一旦該過程結束,Ceph 將使用新 acting set 中的主 OSD 來提供服務。
    • Stale 過期的:OSD 每隔 0.5 秒向 MON 報告其狀態。如果因為任何原因,主 OSD 報告狀態失敗了,或者其它OSD已經報告其主 OSD down 了,Ceph MON 將會將它們的 PG 標記為 stale 狀態。
    • PG 的所有的狀態是一個類似樹形的結構,每個狀態可能存在子狀態,子狀態還可能存在子狀態,如下圖所示:

技術分享圖片(來源)

更多的狀態請參考 http://docs.ceph.com/docs/master/rados/operations/pg-states/。實際上 PG 的狀態可以是以上這些狀態的組合,比如:

技術分享圖片
[root@ceph-mon ~]# ceph -s
cluster c5476875-2a04-41b7-a4e8-421133c69ac8
health HEALTH_WARN
28 pgs backfill #回填,有新的 OSD 被加入了?
79 pgs degraded #降級,有 OSD down 了?
10 pgs recovering #恢復中
42 pgs recovery_wait #等待恢復
80 pgs stuck unclean #有 80個 PG 一直處於 unclean 狀態
27 pgs undersized #GP 的副本數小於pool size
recovery 4814/27835 objects degraded (17.295%)
recovery 2047/27835 objects misplaced (7.354%)
技術分享圖片

註意,只有當所有的 PG 都是 active + clean 狀態時,集群的狀態才是 HEALTH_OK 的。

  • 清理 scrubbing:Ceph 以 PG 為單位進行數據清理,以保證數據的完整性,它的作用類似於文件系統的 fsck 工具。
    • 有兩種比較方式:(1)light scrubbing:比較對象的size和屬性,一般每天進行 (2)deep scrubbing:讀取對象的數據,比較檢驗碼,一般每周進行。
    • Ceph 的 OSD 定期啟動 scrub 線程來掃描部分對象,通過與其他副本比對來發現是否一致,如果存在不一致,拋出異常提示用戶手動解決。管理員也可以手工發起。
    • Scrub 以 PG 為單位,對於每一個PG,Ceph 分析該 PG 下所有的對象, 產生一個類似於元數據信息摘要的數據結構,如對象大小,屬性等,叫scrubmap, 比較主與副scrubmap,來保證是不是有object 丟失或者不匹配。
    • Scrub 方式分成兩種, classic vs. chunky。Scrub 流程需要提取對象的校驗信息然後跟其他副本的校驗信息對比,這期間被校驗對象的數據是不能被修改的,所以 write 請求會被 block. 由於 PG 可能包含成千上萬 objects, chunk 每一次的比較只取其中一部分 objects 來比較,這樣只 block一小部分object的write請求。這是在ceph的Bobtail(v0.56 Jan 1 2013)引入的feature,稱為chunky scrub。Classic scrub 沒有引入chunk, 會block所有的write請求。

    • 該機制對保證數據的完整性非常重要,但是也會消耗大量的集群資源,block 住一部分對象的寫入操作,降低集群的性能,特別是當一個OSD服務器上多個OSD同時進行深度清理的時候。這篇文章 Ceph Deep-Scrubbing Impact Study 說當有三個深度清理線程發生時,性能有明顯的下降。

2.2.3 PG 設計帶來的一些運維問題

引用自原文 Ceph運維告訴你分布式存儲的那些“坑”

(1)擴容粒度

Ceph在實踐中,擴容受“容錯域”制約,一次只能擴一個“容錯域”。容錯域就是:副本隔離級別,即同一個replica的數據,放在不同的磁盤/機器/Rack/機房。默認是機器,通常設為機架。

Ceph擴容需要對PGs進行調整。正因為這個調整,導致Ceph受“容錯域”制約。

例如:有一個PG,是3副本,Ceph集群有一個配置是PG要向外提供正常服務,至少有2個完整的副本。而當這個數據pool的容錯域是host時,同時擴容2臺機器,一些PG就有可能把3副本中的2個都映射到2臺新機器上去。而這2個副本都是新副本,都沒有完整的最新數據。剩下的一個副本,無法滿足老機器至少有完整的2副本的要求,也就不能提供正常讀寫服務了。這就會導致這個PG裏的所有對象,停止對外服務。

那在擴容時,一次只擴容一臺機器時,是不是就安全了呢?這樣就能保證所有PG都至少在老機器有2個完整的副本了。可是,即使是擴容一臺機器,也還要面臨擴容時老機器中有硬盤壞掉,導致PG的完整副本又下降為1的極端情況發生。

辦法是,在開始規劃Ceph集群時,設定好更大層次的“容錯域”,比如Rack。 可以是真實的Rack,即使沒有也可以是邏輯的Rack。這樣擴容時,可以擴一個邏輯“容錯域”,就可以打破擴一臺機器的限制,擴一整個Rack,至少有好幾臺機器。

(2)擴容是 crushmap 變化帶領的系統抖動

Ceph是根據crushmap去放置PG的物理位置的,倘若在擴容進行了一半時,又有硬盤壞掉了,那Ceph的crushmap就會改變,Ceph又會重新進行PG的re-hash,很多PG的位置又會重新計算。如果運氣比較差,很可能一臺機器的擴容進度被迫進行了很久才回到穩定的狀態。

這個crushmap改變導致的Ceph重平衡,不單單在擴容時,幾乎在任何時候,對一個大的存儲集群都有些頭疼。在建立一個新集群時,硬盤都比較新,因此故障率並不高。但是在運行了2-3年的大存儲集群,壞盤真的是一個稀松平常的事情,1000臺規模的集群一天壞個2-3塊盤很正常。crushmap經常變動,對Ceph內部不穩定,影響真的很大。隨之而來,可能是整體IO的下降(磁盤IO被反復的rebalance占滿),甚至是某些數據暫時不可用。

(3)OSD 增加時候的PG數量調整

假設我們現在有10臺機器,每臺一塊硬盤一共10塊盤,有1024個PG,PG都是單副本,那麽每個盤會存100個PG。此時這個設置非常健康,但當我們集群擴容到1000臺機器,每臺硬盤就只放一個PG了,這會導致偽隨機造成的不平衡現象放大。因此,admin就要面臨調整PG數量,這就帶來了問題。調PG,基本也就意味著整個集群會進入一種嚴重不正常的狀態。幾乎50%的對象,涉及到調整後的PG都需要重新放置物理位置,這會引起服務質量的嚴重下降。

(4)盤滿造成的系統不可訪問

在集群整體使用率不高時,都沒有問題。而在使用率達到70%後,就需要管理員介入了。因為方差大的盤,很有可能會觸及95%這條紅線。admin開始調低容量過高磁盤的reweight,但如果在這一批磁盤被調整reweight沒有結束時,又有一些磁盤被寫滿了,那管理員就必須被迫在Ceph沒有達到穩定狀態前,又一次reweight過高的磁盤。 這就導致了crushmap的再一次變更,從而導致Ceph離穩定狀態越來越遠。而此時擴容又不及時的話,更是雪上加霜。而且之前的crushmap的中間狀態,也會導致一些PG遷移了一半,這些“不完整的”PG並不會被馬上刪除,這給本來就緊張的磁盤空間又加重了負擔。關於reweight 導致的 rebalance,可參考 https://ceph.com/geen-categorie/ceph-osd-reweight/。

一塊磁盤滿了,Ceph為什麽就不可用了。Ceph還真的就是這樣設計的,因為Ceph沒法保證新的對象是否落在空盤而不落在滿盤,所以Ceph選擇在有盤滿了時,就拒絕服務。基本上大家的Ceph集群都是在達到50%使用率時,就要開始準備擴容了。

2.3 Ceph 結構和狀態地圖 Cluster map

Ceph 要求 ceph 客戶端和 OSD 守護進程需要知曉整個集群的拓撲結構,它們可以通過 Monitor 獲取 cluster map 來達到這一點。Cluster map 包括:

(1)Monitor Map:MON 集群的狀態(包括 the cluster fsid, the position, name address and port of each monitor, 創建時間,最後的更新時間等)。

技術分享圖片
root@ceph1:/osd/data# ceph mon dump
dumped monmap epoch 1
epoch 1
fsid 4387471a-ae2b-47c4-b67e-9004860d0fd0
last_changed 0.000000
created 0.000000
0: 9.115.251.194:6789/0 mon.ceph1
1: 9.115.251.195:6789/0 mon.ceph2
2: 9.115.251.218:6789/0 mon.ceph3
技術分享圖片

(2)OSD Map:當前所有 Pool 的狀態和所有 OSD 的狀態 (包括 the cluster fsid, map 創建和最後修改時間, pool 列表, replica sizes, PG numbers, a list of OSDs and their status (e.g., up, in) 等)。通過運行 ceph osd dump 獲取。

技術分享圖片
root@ceph1:~# ceph osd dump
epoch 76
fsid 4387471a-ae2b-47c4-b67e-9004860d0fd0
created 2015-09-18 02:16:19.504735
modified 2015-09-21 07:58:55.305221
flags
pool 0 data replicated size 3 min_size 2 crush_ruleset 0 object_hash rjenkins pg_num 64 pgp_num 64 last_change 1 flags hashpspool crash_replay_interval 45 stripe_width 0
osd.3 up   in  weight 1 up_from 26 up_thru 64 down_at 25 last_clean_interval [7,23) 9.115.251.194:6801/1204 9.115.251.194:6802/1204 9.115.251.194:6803/1204 9.115.251.194:6804/1204 exists,up d55567da-4e2a-40ca-b7c9-5a30240c895a
......
技術分享圖片

(3)PG Map:包含PG 版本(version)、時間戳、最新的 OSD map epoch, full ratios, and 每個 PG 的詳細信息比如 PG ID, Up Set, Acting Set, 狀態 (e.g., active + clean), pool 的空間使用統計。可以使用命令 ceph pg dump 來獲取 PG Map。

這裏 有段代碼可以以表格形式顯示這些映射關系:

技術分享圖片
ceph pg dump | awk ‘
 /^pg_stat/ { col=1; while($col!="up") {col++}; col++ }
 /^[0-9a-f]+\.[0-9a-f]+/ { match($0,/^[0-9a-f]+/); pool=substr($0, RSTART, RLENGTH); poollist[pool]=0;
 up=$col; i=0; RSTART=0; RLENGTH=0; delete osds; while(match(up,/[0-9]+/)>0) { osds[++i]=substr(up,RSTART,RLENGTH); up = substr(up, RSTART+RLENGTH) }
 for(i in osds) {array[osds[i],pool]++; osdlist[osds[i]];}
}
END {
 printf("\n");
 printf("pool :\t"); for (i in poollist) printf("%s\t",i); printf("| SUM \n");
 for (i in poollist) printf("--------"); printf("----------------\n");
 for (i in osdlist) { printf("osd.%i\t", i); sum=0;
 for (j in poollist) { printf("%i\t", array[i,j]); sum+=array[i,j]; poollist[j]+=array[i,j] }; printf("| %i\n",sum) }
 for (i in poollist) printf("--------"); printf("----------------\n");
 printf("SUM :\t"); for (i in poollist) printf("%s\t",poollist[i]); printf("|\n");
}‘
技術分享圖片

(4)CRUSH (Controlled Replication under Scalable Hashing)Map:包含當前磁盤、服務器、機架等層級結構 (Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data)。 要查看該 map 的話,先運行 ceph osd getcrushmap -o {filename} 命令,然後運行 crushtool -d {comp-crushmap-filename} -o {decomp-crushmap-filename} 命令,在vi 或者 cat {decomp-crushmap-filename} 即可。

CRUSH map 使用分層結構來組織集群中的所有存儲設備:

技術分享圖片

CRUSH rules 主要有三個作用:

  • 指定從CRUSH Map 中的哪個節點開始查找
  • 指定使用那個節點作為故障隔離域
  • 指定定位副本的搜索模式(廣度優先 or 深度優先)

例子:

技術分享圖片
rule replicated_ruleset                            #規則集的命名,創建pool時可以指定rule集
{
    ruleset 0                                      #rules集的編號,順序編即可
    type replicated                                #定義pool類型為replicated(還有esurecode模式)
    min_size 1                                     #pool中最小指定的副本數量不能小1
    max_size 10                                    #pool中最大指定的副本數量不能大於10    
    step take default                              #定義PG查找副本的入口點
    step chooseleaf  firstn  0  type  host         #選葉子節點、深度優先、隔離host
    step emit                                      #結束
}
技術分享圖片

PG 選擇 OSD 的過程(詳情可閱讀 PG選擇osd的過程(crush 算法)):

  1. 首先要知道在 rules 中指明從 CRUSH map 中哪個節點開始查找,入口點默認為 default 也就是 root 節點
  2. 然後隔離域為 host 節點(也就是同一個host下面不能選擇兩個子節點)。由 default 到3個host的選擇過程,這裏由default根據節點的bucket類型選擇下一個子節點,由子節點再根據本身的類型繼續選擇,知道選擇到host,然後在host下選擇一個osd。

因此,Ceph Admin 可以通過配置 CRUSH map 和 rules 來決定數據的存放方式。詳細信息,可以參考 The RADOS object store and Ceph filesystem: Part 2。

(5)MDS Map:包含當前所有 MDS 的狀態 (the current MDS map epoch, when the map was created, and the last time it changed. It also contains the pool for storing metadata, a list of metadata servers, and which metadata servers are up and in)。通過執行 ceph mds dump 獲取。

技術分享圖片
root@ceph1:~# ceph mds dump
dumped mdsmap epoch 13
epoch   13
flags   0
created 2015-09-18 02:16:19.504427
modified        2015-09-18 08:05:55.438558
4171:   9.115.251.194:6800/962 ceph1 mds.0.2 up:active seq 7
5673:   9.115.251.195:6800/959 ceph2 mds.-1.0 up:standby seq 1
技術分享圖片

MDS 只用於Ceph 文件系統該,與 RDB 和對象存儲無關。

3. CRUSH 算法(以RBD為例)

3.1 Ceph client 是如何將數據塊放到 OSD 的

Ceph 架構中,Ceph 客戶端是直接讀或者寫存放在 OSD上的 RADOS 對象存儲中的對象(data object)的,因此,Ceph 需要走完 (Pool, Object) → (Pool, PG) → OSD set → OSD/Disk 完整的鏈路,才能讓 ceph client 知道目標數據 object的具體位置在哪裏:

(1)創建 Pool 和它的 PG。根據上述的計算過程,PG 在 Pool 被創建後就會被 MON 在根據 CRUSH 算法計算出來的 PG 應該所在若幹的 OSD 上被創建出來了。也就是說,在客戶端寫入對象的時候,PG 已經被創建好了,PG 和 OSD 的映射關系已經是確定了的。

(2)Ceph 客戶端通過哈希算法計算出存放 object 的 PG 的 ID:

  1. 客戶端輸入 pool ID 和 object ID (比如 pool = “liverpool” and object-id = “john”)
  2. ceph 對 object ID 做哈希
  3. ceph 對該 hash 值取 PG 總數的模,得到 PG 編號 (比如 58)(第2和第3步基本保證了一個 pool 的所有 PG 將會被均勻地使用)
  4. ceph 對 pool ID 取 hash (比如 “liverpool” = 4
  5. ceph 將 pool ID 和 PG ID 組合在一起(比如 4.58)得到 PG 的完整ID。

也就是:PG-id = hash(pool-id). hash(objet-id) % PG-number

技術分享圖片

(3)客戶端通過 CRUSH 算法計算出(或者說查找出) object 應該會被保存到 PG 中哪個 OSD 上。(註意:這裏是說”應該“,而不是”將會“,這是因為 PG 和 OSD 之間的關系是已經確定了的,那客戶端需要做的就是需要知道它所選中的這個 PG 到底將會在哪些 OSD 上創建對象。)。這步驟也叫做 CRUSH 查找。

對 Ceph 客戶端來說,只要它獲得了 Cluster map,就可以使用 CRUSH 算法計算出某個 object 將要所在的 OSD 的 ID,然後直接與它通信。

  1. Ceph client 從 MON 獲取最新的 cluster map。
  2. Ceph client 根據上面的第(2)步計算出該 object 將要在的 PG 的 ID。
  3. Ceph client 再根據 CRUSH 算法計算出 PG 中目標主和次 OSD 的 ID。

也就是:OSD-ids = CURSH(PG-id, cluster-map, cursh-rules)。

技術分享圖片

(4)客戶端寫入數據

在客戶端使用 rbd 時一般有兩種方法:

  • 第一種 是 Kernel rbd。就是創建了rbd設備後,把rbd設備map到內核中,形成一個虛擬的塊設備,這時這個塊設備同其他通用塊設備一樣,一般的設備文件為/dev/rbd0,後續直接使用這個塊設備文件就可以了,可以把 /dev/rbd0 格式化後 mount 到某個目錄,也可以直接作為裸設備使用。這時對rbd設備的操作都通過kernel rbd操作方法進行的。
  • 第二種是 librbd 方式。就是創建了rbd設備後,這時可以使用librbd、librados庫進行訪問管理塊設備。這種方式不會map到內核,直接調用librbd提供的接口,可以實現對rbd設備的訪問和管理,但是不會在客戶端產生塊設備文件。

應用寫入rbd塊設備的過程(詳細步驟請參考 rbd client 端的數據請求處理):

  1. 應用調用 librbd 接口或者對linux 內核虛擬塊設備寫入二進制塊。下面以 librbd 為例。
  2. librbd 對二進制塊進行分塊,默認塊大小為 4M,每一塊都有名字,成為一個對象
  3. librbd 調用 librados 將對象寫入 Ceph 集群
  4. librados 向主 OSD 寫入分好塊的二進制數據塊 (先建立TCP/IP連接,然後發送消息給 OSD,OSD 接收後寫入其磁盤)
  5. 主 OSD 負責同時向一個或者多個次 OSD 寫入副本。註意這裏是寫到日誌(Journal)就返回,因此,使用SSD作為Journal的話,可以提高響應速度,做到服務器端對客戶端的快速同步返回寫結果(ack)。
  6. 當主次OSD都寫入完成後,主 OSD 向客戶端返回寫入成功。
  7. 當一段時間(也許得幾秒鐘)後Journal 中的數據向磁盤寫入成功後,Ceph通過事件通知客戶端數據寫入磁盤成功(commit),此時,客戶端可以將寫緩存中的數據徹底清除掉了。
  8. 默認地,Ceph 客戶端會緩存寫入的數據直到收到集群的commit通知。如果此階段內(在寫方法返回到收到commit通知之間)OSD 出故障導致數據寫入文件系統失敗,Ceph 將會允許客戶端重做尚未提交的操作(replay)。因此,PG 有個狀態叫 replay:“The placement group is waiting for clients to replay operations after an OSD crashed.”。

技術分享圖片

也就是,文件系統負責文件處理,librdb 負責塊處理,librados 負責對象處理,OSD 負責將數據寫入在Journal和磁盤中。

關於 RDB 鏡像在存儲池中是如何被存放的,請閱讀 理解 OpenStack + Ceph (4):Ceph 的基礎數據結構 [Pool, Image, Snapshot, Clone]。

(5)以存放一個文件為例,下圖(來源)說明了完整的計算過程:

技術分享圖片

(6)一些說明

幾個比例關系:

  • 文件 :對象 = 1 : n (由客戶端實時計算)
  • object :PG = n : 1 (有客戶端使用哈希算法計算)
  • PG :OSD = m : n (由 MON 根據 CRUSH 算法計算)

CRUSH 算法是相當復雜,快速看看的話可以參考 官方文章,或者直接讀代碼和作者的論文。幾個簡單的結論或原則:

  • 一個 RBD image(比如虛機的一個鏡像文件)會分成幾個 data objects 保存在 Ceph 對象存儲中。
  • 一個 Ceph 集群含有多個 pool (使用 ceph osd pool create 命令創建pool)
  • 一個 Pool 包含若幹個 PG (在創建 pool 時必須指定 pg_num,在需要的時候對已有的pool的 pg_num 也可以進行修改)
  • 一個 PG 可以包含多個對象
  • 一個 object 只在一個 PG 中
  • 一個 PG 映射到一組 OSD,其中第一個 OSD 是主(primary),其余的是從(secondary)
  • 許多 PG 可以映射到某個 OSD,通常一個OSD上會有50到100個PG。

使用 這裏 的腳本,可以看出在我的測試環境(pool的副本數為1)中,一共有 6 個pool,7 個 OSD,每個 pool 中有 192 個PG,每個 OSD 大概在164個 (192 * 6*1/7)PG 中:

技術分享圖片
pool :  4       5       0       1       2       3       | SUM
----------------------------------------------------------------
osd.4   20      19      21      23      21      24      | 128
osd.5   38      28      30      28      34      44      | 202
osd.6   30      33      33      32      34      36      | 198
osd.7   23      19      22      21      22      21      | 128
osd.8   26      36      34      36      30      20      | 182
osd.9   21      26      21      20      21      19      | 128
osd.3   34      31      31      32      30      28      | 186
----------------------------------------------------------------
SUM :   192     192     192     192     192     192     |  
技術分享圖片

這張圖(來源)也有助於理清其中的關系:

技術分享圖片

總之,Ceph 采用的是通過計算找到對象應該被保存的 OSD 位置,這比通過常見的查詢算法獲取位置快得多。CRUSH 算法是的 ceph 客戶端自己計算對象要被保存在哪裏(哪個 OSD),也使得客戶端可以從主 OSD 上保存或者讀取數據。

3.2 RBD image 保存過程和形式

如下圖所示,Ceph 系統中不同層次的組件/用戶所看到的數據的形式是不一樣的:

技術分享圖片

  • Ceph 客戶端所見的是一個完整的連續的二進制數據塊,其大小為創建 RBD image 是設置的大小或者 resize 的大小,客戶端可以從頭或者從某個位置開始寫入二進制數據。
  • librados 負責在 RADOS 中創建對象(object),其大小為 pool 的 order 決定,默認情況下 order = 22 此時 object 大小為 4MB;以及負責將客戶端傳入的二進制塊條帶化為若幹個條帶(stripe)。
  • librados 控制哪個條帶由哪個 OSD 寫入(條帶 ---寫入哪個----> object ----位於哪個 ----> OSD)
  • OSD 負責創建在文件系統中創建文件,並將 librados 傳入的數據寫入數據。

Ceph client 向一個 RBD image 寫入二進制數據(假設 pool 的拷貝份數為 3):

(1)Ceph client 調用 librados 創建一個 RBD image,這時候不會做存儲空間分配,而是創建若幹元數據對象來保存元數據信息。

(2)Ceph client 調用 librados 開始寫數據。librados 計算條帶、object 等,然後開始寫第一個 stripe 到特定的目標 object。

(3)librados 根據 CRUSH 算法,計算出 object 所對應的主 OSD ID,並將二進制數據發給它。

(4)主 OSD 負責調用文件系統接口將二進制數據寫入磁盤上的文件(每個 object 對應一個 file,file 的內容是一個或者多個 stripe)。

(5)主 ODS 完成數據寫入後,它使用 CRUSH 算啊計算出第二個OSD(secondary OSD)和第三個OSD(tertiary OSD)的位置,然後向這兩個 OSD 拷貝對象。都完成後,它向 ceph client 反饋該 object 保存完畢。

技術分享圖片

(6)然後寫第二個條帶,直到全部寫入完成。全部完成後,librados 還應該會做元數據更新,比如寫入新的 size 等。

完整的過程(來源):

技術分享圖片

該過程具有強一致性的特點:

  • Ceph 的讀寫操作采用 Primary-Replica 模型,Client 只向 Object 所對應 OSD set 的 Primary 發起讀寫請求,這保證了數據的強一致性。
  • 由於每個 Object 都只有一個 Primary OSD,因此對 Object 的更新都是順序的,不存在同步問題。
  • 當 Primary 收到 Object 的寫請求時,它負責把數據發送給其他 Replicas,只要這個數據被保存在所有的OSD上時,Primary 才應答Object的寫請求,這保證了副本的一致性。這也帶來一些副作用。相比那些只實現了最終一致性的存儲系統比如 Swift,Ceph 只有三份拷貝都寫入完成後才算寫入完成,這在出現磁盤損壞時會出現寫延遲增加。
  • 在 OSD 上,在收到數據存放指令後,它會產生2~3個磁盤seek操作:
    • 把寫操作記錄到 OSD 的 Journal 文件上(Journal是為了保證寫操作的原子性)。
    • 把寫操作更新到 Object 對應的文件上。
    • 把寫操作記錄到 PG Log 文件上。

3.3 條帶化(striping)

在 RADOS 層,Ceph 本身沒有條帶的概念,因為一個object 是作為一個 文件整體性保存的。但是,RBD 可以控制向一個 object 的寫入方式,默認是將一個 object 寫滿再去寫下一個object;還可以通過指定 stripe_unit 和 stripe_count,來將 object 分成若幹個條帶即 strip。

一個 RDB image 會被分為多個 object 來保存,從而使得對一個 image 的多個讀寫可以分在多個 object 進行,從而可以防止某個 image 非常大或者非常忙時單個節點稱為性能瓶頸。還可以將 object 進一步條帶化為多個條帶(stripe unit)。條帶(stripe)是 librados 通過 ODS 寫入數據的基本單位。這麽做的好處是在保持對象數目的同時,進一步減少可以同步讀寫的粒度(從 object 粒度減少到 stripe 粒度),從而提高讀寫效率。 Ceph 的條帶化行為(如果劃分條帶和如何寫入條帶)受三個參數控制:
  • order:RADOS Object 的大小為 2^[order] bytes。默認的 oder 為 22,這時候對象大小為4MB。最小 4k,最大 32M,默認 4M.
  • stripe_unit:條帶(stripe unit)的大小。每個 [stripe_unit] 的連續字節會被連續地保存到同一個對象中,client 寫滿 stripe unit 大小的數據後,接著去下一個 object 中寫下一個 stripe unit 大小的數據。默認為 1,此時一個 stripe 就是一個 object。
  • stripe_count:在分別寫入了 [stripe_unit] 個字節到 [stripe_count] 個對象後,ceph 又重新從一個新的對象開始寫下一個條帶,直到該對象達到了它的最大大小。這時候,ceph 轉移到下 [stripe_unit] 字節。默認為 object site。
以下圖為例: (1)RBD image 會被保存在總共 8 個 RADOS object (計算方式為 client data size 除以 2^[order])中。 (2)stripe_unit 為 object size 的四分之一,也就是說每個 object 包含 4 個 stripe。 (3)stripe_count 為 4,即每個 object set 包含四個 object。這樣,client 以 4 為一個循環,向一個 object set 中的每個 object 依次寫入 stripe,寫到第 16 個 stripe 後,按照同樣的方式寫第二個 object set。 技術分享圖片 默認的情況下,[stripe_unit] 等於 object size;stripe_count 為1。意味著 ceph client 在將第一個 object 寫滿後再去寫下一個 object。要設置其他的 [stripe_unit] 值,需要Ceph v0.53 版本及以後版本對 STRIPINGV2 的支持以及使用 format 2 image 格式。

參考鏈接:

http://www.wzxue.com/ceph-librbd-block-library/

http://docs.ceph.com/docs/master/architecture/

https://www.ustack.com/blog/ceph_infra/

https://hustcat.github.io/rbd-image-internal-in-ceph/

http://www.wzxue.com/category/ceph-2/

ceph(3)--Ceph 物理和邏輯結構