Ceph寫入文件到分布至各個osd過程分析


一、簡介
本文主要講解ceph接收客戶端數據寫入,然后在系統內部數據是如何進行分布的,以及分布原理簡單介紹。所有介紹都基於如下圖進行講解。

 

ceph

上圖左側的幾個概念說明如下:
File :file就是用戶需要存儲或者訪問的實際文件。
Ojbect :object是ceph底層分布式存儲系統RADOS所看到的“對象”。File寫入到ceph是由object-size(4M)決定客戶端實際寫入的file被分片多少個rados識別的object對象。
PG:PG的用途是對object的存儲進行組織和位置映射。
OSD :即客戶寫入的文件file分成若干個object之后,分配到不同的pg中,然后pg被分配到不同的磁盤上(冗余決定)進行實際存儲,osd實際上是對物理磁盤進行管理的一個進程,也被稱之為物理磁盤。
二、原理介紹
大家可以思考下,將一個file寫入到實際的磁盤上一共分為幾步?
根據上面的圖進行分析,我認為是需要3步:file->object、object->pg、pg->osd。下面分別進行介紹。
2.1 File -> object映射
將用戶實際寫入的文件file,映射為RADOS能夠處理的object。本質上就是將文件file按照固定對象大小(默認是4M)進行切片,類似於條帶化。每一個切分后產生的object將獲得唯一的oid,即object id。結合上圖(oid=ino+ono)中實際分析,ino是文件file的元數據,可以簡單理解為該file的唯一id。ono則是由該file切分產生的某個object的序號。而oid就是將這個序號簡單加在該file id之后得到的。舉例,假設一個id為filename的file被切分成了三個object,則其object序號依次為0、1和2,而最終得到的oid就依次為filename0、filename1和filename2。
2.2 Object -> PG映射
在文件file在rados底層被分為為一個或多個object之后,就需要將每個object(oid唯一)獨立地映射到一個PG(作用是對object的存儲進行組織和位置映射,1個pg中包含多個對象)中去。其計算公式是:
hash(oid) & mask -> pgid
首先是使用Ceph系統指定的一個靜態hash函數計算oid的哈希值,將oid映射成為一個近似均勻分布的偽隨機值。然后,將這個偽隨機值和mask按位相與,得到最終的PG序號(pgid)。根據RADOS的設計,給定PG的總數為m(m應該為2的整數冪),則mask的值為m-1。因此,哈希值計算和按位與操作的整體結果事實上是從所有m個PG中近似均勻地隨機選擇一個。
2.3 PG -> OSD映射
將PG映射到數據的實際存儲磁盤OSD中。如上圖所示,RADOS采用一個名為CRUSH的算法,將pgid代入其中,然后得到一組共n個OSD。這n個OSD即共同負責存儲和維護一個PG中的所有object。這里的n之前也介紹過,由實際環境冗余決定,若副本數為2,則這里的n為2,也就是說pg被復制2份且分別存儲到由crush計算得出的2個osd中實現冗余。

三、實際介紹

3.1 ceph邏輯層
Ceph在rados上構建了一個邏輯層,那就是池(pool),用於保存對象。個人理解這個pool的作用是對底層所有存儲空間在邏輯上區分開來,不同的pool存儲不同類型的數據,或者說給不同類型的客戶使用。然后為方便對寫入到pool的對象進行管理,Pool再一次進行了細分,即將一個pool划分為若干的PG(歸置組 Placement Group)也就是說所有的PG構成了一個pool。這里 ceph不需要直接對存儲池pool中的object對象進行直接管理,而是管理數量更少的pg,然后由pg對object進行管理,這塊不做詳細介紹。
下面摘自網絡:https://www.cnblogs.com/mylovelulu/p/10508904.html

重要的是要理解
現在需要解決的問題是,對象怎么知道要保存到哪個PG上,假定這里我們的pool名叫rbd,共有256個PG,給每個PG編個號分別叫做0x0, 0x1, ...0xF, 0x10, 0x11... 0xFE, 0xFF。
要解決這個問題,我們先看看我們擁有什么,1,不同的對象名。2,不同的PG編號。這里就可以引入Ceph的計算方法了 : HASH。
對於對象名分別為bar和foo的兩個對象,對他們的對象名(實際上文件系統大家看到的更多的就是這樣10000000000.00000008的對象名)進行計算即:
HASH(‘bar’) = 0x3E0A4162
HASH(‘foo’) = 0x7FE391A0
HASH(‘bar’) = 0x3E0A4162
對對象名進行HASH后,得到了一串十六進制輸出值,也就是說通過HASH我們將一個對象名轉化成了一串數字,那么上面的第一行和第三行是一樣的有什么意義? 意義就是對於一個同樣的對象名,計算出來的結果永遠都是一樣的,但是HASH算法的確將對象名計算得出了一個隨機數。
有了這個輸出,我們使用小學就會的方法:求余數!用隨機數除以PG的總數256,得到的余數一定會落在[0x0, 0xFF]之間,也就是這256個PG中的某一個:
0x3E0A4162 % 0xFF ===> 0x62
0x7FE391A0 % 0xFF ===> 0xA0
於是乎,對象bar保存到編號為0x62的PG中,對象foo保存到編號為0xA0的PG中。對象bar永遠都會保存到PG 0x62中! 對象foo永遠都會保存到PG 0xA0中!
現在又來了一億個對象,他們也想知道自己會保存到哪個PG中,Ceph說:“自己算”。於是這一億個對象,各自對自己對象名進行HASH,得到輸出后除以PG總數得到的余數就是要保存的PG。求余的好處就是對象數量規模越大,每個PG分布的對象數量就越平均。所以每個對象自有名字開始,他們要保存到的PG就已經確定了。Ceph是不區分對象的真實大小內容以及任何形式的格式,只認對象名。畢竟當對象數達到百萬級時,對象的分布從宏觀上來看還是平均的。
這里給出更Ceph一點的說明,實際上在Ceph中,存在着多個pool,每個pool里面存在着若干的PG,如果兩個pool里面的PG編號相同,Ceph怎么區分呢? 於是乎,Ceph對每個pool進行了編號,比如剛剛的rbd池,給予編號0,再建一個pool就給予編號1,那么在Ceph里,PG的實際編號是由pool_id+.+PG_id組成的,也就是說,剛剛的bar對象會保存在0.62這個PG里,foo這個對象會保存在0.A0這個PG里。其他池里的PG名稱可能為1.12f, 2.aa1,10.aa1等。

3.2 ceph物理層
理解了剛剛的邏輯層,我們再看一下Ceph里的物理層,rados在下一層,也就是實際屋里服務器上的各個磁盤,通常,Ceph將一個磁盤看作一個OSD(實際上,OSD是管理一個磁盤的程序),於是物理層由若干的OSD組成,我們的最終目標是將對象保存到磁盤上,在邏輯層里,對象是保存到PG里面的,那么現在的任務就是打通PG和OSD之間的隧道。PG相當於一堆余數相同的對象的組合,PG把這一部分對象打了個包,現在我們需要把很多的包平均的安放在各個OSD上,這就是CRUSH算法所要做的事情:CRUSH計算PG->OSD的映射關系CRUSH(PG_ID) ===> OSD

首先來看我們要做什么:
把已有的PG_ID映射到OSD上,有了映射關系就可以把一個PG保存到一個磁盤上。
如果我們想保存三個副本,可以把一個PG映射到三個不同的OSD上,這三個OSD上保存着一模一樣的PG內容。
再來看我們有了什么:
互不相同的PG_ID。
互不相同的OSD_ID。
每個OSD最大的不同的就是它們的容量,我們將每個OSD的容量又稱為OSD的權重(weight),規定4T權重為4,800G為0.8,也就是以T為單位的值。
現在問題轉化為:如何將PG_ID映射到有各自權重的OSD上?這里我直接使用CRUSH里面采取的Straw算法,翻譯過來就是抽簽,說白了就是挑個最長的簽,這里的簽指的是OSD的權重。下面既大概選擇過程:

給出一個PG_ID,作為CRUSH_HASH的輸入。
CRUSH_HASH(PG_ID, OSD_ID, r) 得出一個隨機數draw (重點是隨機數,不是HASH)。
對於所有的OSD用他們的權重乘以每個OSD_ID對應的隨機數(上述步驟中替換osd_id號),得到乘積。
選出乘積最大的OSD。
這個PG就會保存到這個OSD上。

第一行,我們姑且把r當做一個常數,第一行實際上將PG_ID, OSD_ID和r一起當做CRUSH_HASH的輸入,求出一個十六進制隨機數輸出,這和HASH(oid)完全類似,只是多了兩個輸入。所以需要強調的是,對於相同的三個輸入,計算得出的draw的值是一定相同的。

這個draw到底有啥用?其實,CRUSH希望得到一個隨機數,也就是這里的draw,然后拿這個隨機數去乘以OSD的權重,這樣把隨機數和OSD的權重結合在一起,就得到了每個OSD的實際簽長(乘積數),而且每個簽都不一樣長(極大概率),就很容易從中挑一個最長的。

說白了,CRUSH希望隨機挑一個OSD出來,但是還要滿足權重越大的OSD被挑中的概率越大,為了達到隨機的目的,它在挑之前讓每個OSD都拿着自己的權重乘以一個隨機數,再取乘積最大的那個。若是挑選1億次,從宏觀來看,同樣是乘以一個隨機數,在樣本容量足夠大之后,這個隨機數對挑中的結果不再有影響,起決定性影響的是OSD的權重,也就是說,OSD的權重越大,宏觀來看被挑中的概率越大。
這里再說明下CRUSH造出來的隨機數draw,前文可知,對於常量輸入,一定會得到一樣的輸出,所以這並不是真正的隨機,所以說,CRUSH是一個偽隨機算法。那crush是如何解決一個PG映射到多個OSD的問題,還記得那個常量r嗎?我們把r+1,再求一遍隨機數,再去乘以每個OSD的權重,再去選出乘積最大的OSD,如果和之前的OSD編號不一樣,那么就選中它,如果和之前的OSD編號一樣的話,那么再把r+2,再次選一次,直到選出我們需要的三個不一樣編號的OSD(3個副本)為止!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM