CRUSH演算法介紹

2021-09-05 09:50:43 字數 4405 閱讀 3497

crush資料分布演算法的全稱是:controlled, scalable, decentralized placement of replicated data. 

開源的分布式儲存ceph採用crush資料分布演算法以達到以下幾個要求:

1. 資料分布均衡

2. 負載均衡

3. 靈活應對集群擴容和縮容:無論是新增或刪除裝置,都能最小化資料遷移

4. 支援大規模集群,消除因幾種儲存元資料而可能的單點失敗

crush演算法除了要達到以上幾個要求,它的主要目的是為了定位所儲存資料的位置。

那麼,crush演算法如何定位儲存資料的位置,並且滿足以上四大要求呢? 

sage在2023年關於crush的原**寫得非常言簡意賅,並且主要是介紹抽象的crush演算法,而沒有結合ceph來談,比如就完全沒有提及pg和osd的概念。因此,估計是要看看sage的其他幾篇**和ceph的原始碼才能清楚一點。現根據前人的幾篇文獻總結如下。

crush演算法主要用於在ceph中定位儲存資料的位置,分為2個步驟:

1. 根據資料物件(object)的物件名,計算得到pg_id:

pg_id = pool_id + hash() % pg_num
2. 根據pg_id,計算得到一組osd

首先,為何是一組osd?

因為在ceph中,pool分為2種。第一種是replicated pool,比如每個object都有n個副本,就是屬於這種;第二種是ec pool,運用的是糾刪碼技術,每個object只有乙個副本,但有一些用於校驗和還原的資料塊。因此無論對於哪種pool,乙個object都需要多個osd來儲存其副本或者是儲存其糾刪碼,因此輸出是一組osd. 

那麼,如何根據pg_id,計算得到一組osd呢?

首先,使用者在建立pool的時候,要設定儲存規則(placement rule)。當然,如果不設定,那麼就採用預設的規則。規則看起來是這樣的:

action                  resulting 

take(root) root

select(1, row) row-2

select(3, cabinet) cab-21, cab-23, cab-24

select(1, disk) disk-210, disk-233, disk-245

emit

效果如下圖所示: 

這三步(take、select(n,t), emit),是真正的原crush**中crush演算法的架構內容。而在涉及到select的時候,也需要介紹下是如何select的 -- 即bucket選擇演算法。詳情如下。

第一步take(root), 代表的是選中了這個root.

注意,在乙個ceph集群中,是有可能有多個root的,因為層次結構是使用者可自己設定的。比如,使用者把所有ssd的裝置設定成屬於乙個root,而把所有hdd的裝置設定成屬於另乙個root. 

第二步,select(n, t). 這一步是關鍵,意思是,選擇n個型別為t的bucket. 

那麼,是如何選擇的呢?

首先,select有2種操作方式:

choose firstn: 深度優先選擇出n個型別為t的子bucket,只到bucket為止

chooseleaf: 先選擇出n個型別為t的bucket,再在每個bucket下選擇乙個osd裝置

其次,就是如何去選擇bucket了,即bucket隨機選擇演算法。

一共有4種型別的bucket,對於每種型別的bucket,如何「選出」的方法是不一樣的。而在設定placement rule時,可以指定採用哪種bucket隨機選擇演算法,即屬於哪種bucket. 

這裡首先介紹乙個重要的hash函式,因為該函式在多個bucket選擇演算法中都用到了,但作用各不相同:

hash(pg_id, r, bucket_id)
這個hash函式的輸入有3個:pg_id,r為 [1-n] 中的乙個值(n為副本數),bucket_id

這個hash函式的輸出是乙個 [0-1] 之間的數值

1. uniform bucket

每個bucket的權重都相同(這裡應該指的是同層級的節點的weight都相同),並且基本沒有硬體裝置新增和刪除的情況

這種bucket因為所有item權重都相同,因此選擇速度很快,為o(1),但是一旦需要新增或刪除裝置,就退化成普通hash,即幾乎所有資料都需要遷移。在實際中,一般不會使用這種bucket. 

2. list bucket

其子item在記憶體中使用資料結構中的鍊錶來儲存,其所包含的item可以具有任意權重。(注:此處item和bucket是乙個意思)      具體查詢bucket的方法是:

1> 從表頭item開始查詢,先得到表頭item的權重wh,剩餘鍊錶中所有item權重之和為ws. 

2> 根據 hash(pg_id, r, bucket_id) 計算得到乙個 [0-1] 之間的值v,若v在 [0-wh/ws) 的範圍,則選擇表頭item,並返回表頭item的id;

3> 否則,繼續遍歷剩餘的鍊錶,繼續上述的遞迴查詢。

由以上分析可知,list bucket的查詢複雜度為 o(n)

這種bucket在實際中一般也不太會用,因為其刪除硬體時,效率也較差。

3. tree bucket

此種型別的bucket的子item組織成樹的結構。每個osd是葉子節點;根節點和中間節點是虛擬節點,其權重等於左右子樹的權重之和。具體查詢bucket的方法如下:

1> 從根節點開始遍歷

2> 設左子樹權重為w1,而當前節點權重為wn,然後根據 hash(pg_id, r, bucket_id) 計算得到乙個 [0-1] 之間的值v;

a> 若v在 [0-w1/wn) 之間,那麼在左子樹中繼續選擇item;

b> 否則在右子樹中選擇item

c> 一直遍歷,直至葉子節點 

由以上分析可知,tree bucket的查詢複雜度為 o(log n)

這種bucket在實際中可以考慮使用。其選擇速度是很快的,而在新增和刪除硬體裝置時,速度也還可以。

4. straw bucket 

此種型別的bucket選擇演算法是ceph的預設選擇演算法。具體如下:

1> 函式 f(wi) 是和item的權重wi相關的函式,決定了每個item被選中的概率;權重(weight)越高的item則被選中的概率越大。

注意,這裡的weight並不是相當於磁碟可用空間,而是相當於總空間,因此是固定不變的。

2> 給每個item計算乙個長度

length = f(wi) * hash(pg_id, r, bucket_id)
然後選擇length最大的item. 

因為straw在增刪裝置時的表現最佳,而在選擇速度上也還可以,因此,它被選作預設的bucket選擇演算法。

以上各個bucket選擇演算法的對比情況見下表:    

bucket選擇演算法

選擇的速度

item新增的容易程度

item刪除的容易程度

uniform

o(1)

poor

poor

list

o(n)

optimal

poor

tree

o(log n)

good

good

straw

o(n)

better

better

straw2

o(n)

optimal

optimal

當選出乙個osd後,可能出現衝突(重複選擇)、失效(磁碟損壞)、過載的情況,那麼此時就重新選擇一次。對於replicated pool和ec pool,重新選擇的演算法是略有不同的。replicated pool是直接再選乙個即可(r' = r + f,f為總失敗的次數),而ec pool則需令r值增加n的倍數後(r' = fr*n, fr為在這個副本上失敗的次數),再運用hash(pg_id, r', bucket_id)來進行重新選擇。

下圖顯示了兩種pool在失敗的情況下是如何決定r'的值:

最後一步,第三步,emit,即輸出結果。所謂結果,即一組osd. 

1. 《ceph原始碼分析》第四章 crush資料分布演算法

2. crush: controlled, scalable, decentralized placement of replicated data

3. 大話ceph - crush那點事兒

4.  ceph剖析:資料分布之crush演算法與一致性hash

Ceph學習筆記(2) CRUSH資料分布演算法

分布式儲存系統需要讓資料均勻的分布在集群中的物理裝置上,同時在新裝置加入,舊裝置退出之後讓資料重新達到平衡狀態尤為重要。新裝置加入後,資料要從不同的老裝置中遷移過來。老裝置退出後,資料遷移分攤到其他裝置。將檔案 塊裝置等資料分片,經過雜湊,然後寫入不同的裝置,從而盡可能提高i o併發與聚合頻寬。在實...

A 演算法介紹

不得不嘆服,強大演算法背後,都是簡單得不能再簡單的邏輯。普林斯頓的演算法課程作業裡,要讓用a 演算法。什麼都沒接觸到過,看到後有種想哭的感覺!於是網上查閱資料,漸漸的明白了怎麼回事。通過對a 演算法的學習的個人感悟 計算乙個代價函式,評估每一步的代價,並找到代價最小的方向。最終得到的解可能不是最優,...

A 演算法介紹

參考 在最短路徑演算法中 dijkstra演算法 每次貪心選擇當前更新的點中距離最近的進行更新。貪心演算法 每次選擇離終點評估最近的點進行更新 a 演算法 綜合了dijkstra和貪心,相當於即考慮了起點到此點的距離,又評估了此點到終點的距離。a 演算法通過下面這個函式來計算每個節點的優先順序。其中...