基礎
CephFS致力于提供POSIX兼容的文件系統(tǒng)接口,為了實現(xiàn)這一目標弊攘,CephFS選擇了以目錄樹的形式在內存管理和使用元數(shù)據(jù)信息锌钮。和S3的“偽目錄”做對比,這種目錄樹的方式能更高效楞捂、直接地實現(xiàn)POSIX語義。
CephFS作為分布式文件系統(tǒng)趋厉,面臨所有分布式系統(tǒng)都要著力解決的兩個問題:海量數(shù)據(jù)寨闹,單點。面對海量元數(shù)據(jù)君账,單機內存容量顯然無法滿足要求繁堡,對此CephFS提供了多個Active MDS機制,將目錄樹劃分成不同區(qū)域乡数,分別在不同MDS上管理椭蹄,MDS在檢測到對端MDS故障后,能對故障MDS進行接管净赴,解決單點問題绳矩,實現(xiàn)高可用。
由于目錄樹的結構特點玖翅,導致對目錄樹的并發(fā)操作需要一種互斥機制來保證一致性埋酬。舉例來說,同時在同一個目錄下新建文件烧栋,對于這個目錄來說必須是順序進行的写妥,而在不同目錄下創(chuàng)建文件時,對目標目錄的修改是可以并行的审姓,但同時也要確保目標目錄以上直至根節(jié)點珍特,在這個期間不會被其他線程修改,比如對一個目錄節(jié)點進行修改時魔吐,這個目錄及其全部父節(jié)點所在路徑無法做快照扎筒,這是顯而易見的。為此MDS中實現(xiàn)了自己的一套鎖機制酬姆。
為了提高可靠性嗜桌,MDS中每次針對目錄樹的修改都是先寫日志,再修改內存目錄樹結構辞色,最后將修改后的結果落盤骨宠。如果中途有MDS故障,再次啟動或者被其他MDS接管時,重放日志即可恢復到故障前的目錄樹狀態(tài)层亿。
實現(xiàn)
目錄樹結構
目錄樹中三個關鍵數(shù)據(jù)結構是inode
桦卒,dentry
和dir
,三者通過互相連接匿又,共同組成了一個樹形目錄結構方灾。
Inode中存儲的是具體文件/目錄的元信息,例如mode碌更,size等裕偿。inode號用來在metapool或datapool中查找對應的對象,在metapool中痛单,每個對象是一個dir(分片)嘿棘,在datapool中,每個對象(頭對象)是一個文件桦他。
Dentry中存儲的是文件/目錄的名字,被用來連接inode和dir谆棱。
Dir通過一個items map記錄自己管理的目錄項(dentry)快压,且擁有一個和自身連接的inode,通過inode可以繼續(xù)向上回溯目錄樹垃瞧。items map通過omap方式存儲在metapool中蔫劣。
目錄樹細節(jié)
inode
inode除記錄元信息外,作為目錄節(jié)點時還通過dirfrags
管理本節(jié)點的分片(fragement)个从,通過分片可以將一個大目錄(應用層面)或者熱點目錄(應用層面)拆分成多個較小目錄(實現(xiàn)層面)脉幢,從而管理更大容量的目錄或者在多個mds間實現(xiàn)負載平衡。
dentry
dentry在內存中有三種存在方式:primary
嗦锐,remote
嫌松,null
。
- primary dn表示一個正常的目錄項:已連接到一個inode奕污。
- remote dn對應文件系統(tǒng)中的硬鏈接(hard link)萎羔,文件系統(tǒng)中不允許dir有hard link,所以只有普通文件在mds內存中可能有對應的remote dn出現(xiàn)碳默。一個inode只能有一個parent贾陷,但能有多個remote parent,parent指向的是primary dentry嘱根,remote parent指向的是remote dentry髓废。
- null dn是一個中間狀態(tài),表示dn還未和inode關聯(lián)该抒。和前兩種dentry不一樣慌洪,null dn不會存儲在meta pool中。
dir
每個dir節(jié)點都是以<inodenum>.<fragment>的命名方式存在于meta pool中,通過CDir::fetch()
讀取metapool中的數(shù)據(jù)蒋譬,填充自己的CDir::items
割岛,從而在內存初中創(chuàng)建相應的dentry和inode結構。
auth
單個Active MDS時犯助,三種元數(shù)據(jù)結構都只有一份內存副本癣漆,位于Active MDS中,且都標記為auth
剂买,但當存在多個Active MDS時惠爽,每種元數(shù)據(jù)結構(inode、dentry瞬哼、dir)都可能出現(xiàn)!auth
的情況婚肆,!auth
情況的出現(xiàn)是由于目錄分裂(split)、備份(replicate)坐慰、遷移(export)引起较性。對于來自client的修改類請求,只有auth
能處理结胀,!auth
節(jié)點只能處理非修改類請求赞咙。
master / slave request
master和slave用于標識一個mds間請求中的請求方和接收方。發(fā)起方為mater(mdr->is_master()
)糟港,接受方為slave(mdr->is_slave()
)
鎖
實現(xiàn)數(shù)據(jù)一致性最簡單的辦法是每次操作對整個目錄樹加鎖攀操,這種方式實現(xiàn)簡單,但在性能上顯然無法接受秸抚。為了實現(xiàn)對目錄樹中數(shù)據(jù)結構更高效的互斥操作速和,mds中設計了12個鎖,每個鎖管理一部分元數(shù)據(jù)信息剥汤,每個鎖有自己的狀態(tài)颠放,分屬于不同類型的狀態(tài)機,狀態(tài)機定義了每個鎖存在的狀態(tài)吭敢,以及每個狀態(tài)下client能獲得的鎖權限和能進行的操作慈迈。
鎖的類型及所屬狀態(tài)機如下:
struct LockType {
int type;
const sm_t *sm;
explicit LockType(int t) : type(t) {
switch (type) {
case CEPH_LOCK_DN: // 管理dentry
case CEPH_LOCK_IAUTH: // 管理mod,uid,gid等信息
case CEPH_LOCK_ILINK: // 管理link屬性
case CEPH_LOCK_IXATTR: // 管理擴展屬性
case CEPH_LOCK_ISNAP: // 管理快照信息
case CEPH_LOCK_IFLOCK: // 文件鎖相關
case CEPH_LOCK_IPOLICY: // 管理layout、quota等信息
sm = &sm_simplelock;
break;
case CEPH_LOCK_IDFT: // 管理分片信息
case CEPH_LOCK_INEST: // 管理目錄遞歸統(tǒng)計信息省有,如文件個數(shù)等
sm = &sm_scatterlock;
break;
case CEPH_LOCK_IFILE: //對于目錄則是管理本層目錄的統(tǒng)計信息痒留,對于普通文件則是管理文件大小等
sm = &sm_filelock;
break;
case CEPH_LOCK_DVERSION:
case CEPH_LOCK_IVERSION:
sm = &sm_locallock;
break;
default:
sm = 0;
}
}
};
其中CEPH_LOCK_DVERSION
和CEPH_LOCK_DN
是dentry使用的兩個鎖,其余都是inode使用的鎖蠢沿。dir中沒有鎖伸头。
對鎖共有4種操作:加讀鎖(rdlock
),加寫鎖(wrlock
)舷蟀,加遠程寫鎖(remote_wrlock
)恤磷,加互斥鎖(xlock
)面哼。每個鎖會用到哪些操作根據(jù)所屬狀態(tài)機類型區(qū)分,總的來說扫步,rdlock
用于共享讀魔策,xlock
用于獨占資源,wrlock
是針對目錄進行的優(yōu)化鎖操作河胎,remote_wrlock
則是在處理rename
操作中可能會用到的一種加鎖方式(因為處理rename
請求的MDS是dest-dn為auth的節(jié)點闯袒,可能會和src-inode的auth不不是同一個MDS上,這時需要在dest-dn的auth節(jié)點上對src-inode進行remote_wrlock
)游岳。
MDS每次操作目錄樹時都會先確定好需要鎖定的資源(即鎖類型)和要進行的操作政敢,然后通過Locker::acquire_locks()
集中進行加鎖,如果中途碰到某個鎖無法加成功胚迫,則這個mdr被掛起喷户,直到對應資源可用后再被重新執(zhí)行。
sm_locallock
locallock sm(sate machine) 有兩個分別用于dn version和inode version管理的鎖访锻。這兩個鎖都是為了在本地mds中維護version的一致性褪尝。而其他三種狀態(tài)機則是為了在全部Active mds中維護資源的一致性。
來自客戶端的修改請求處理前都會對相應資源進行xlock
期犬,在沒有明確要求對version進行加鎖時河哑,Locker
會根據(jù)mdr是否為master為相應的version locker默認進行wrlock
或xlock
。比如創(chuàng)建新文件時會對新文件的dentry進行xlock
哭懈,這個過程中mds會自動對dentry 的version lock加鎖灾馒。
對version lock進行xlock
和wrlock
區(qū)別在于xlock在同一個MDS上是互斥的茎用,wrlock是可以重復加的遣总。
locallock sm 是四種狀態(tài)機中最簡單的一種,它只有一個狀態(tài)轨功,是否可加鎖是通過計數(shù)方式進行判斷旭斥,不能加鎖時并不會對鎖進行狀態(tài)調整。-
sm_simplelock
simplelock sm中的鎖只能進行rdlock
和xlock
兩種操作古涧,這和通常的共享/互斥概念是一致的垂券。兩種操作都會根據(jù)sm判斷是否可成功加鎖,不滿足加鎖條件時會根據(jù)狀態(tài)機進行調整羡滑。
simple sm在auth和!auth節(jié)點上加鎖 -
sm_scatterlock
scatterlock sm有兩個鎖:IDFT用于目錄分片管理菇爪,INEST用于目錄遞歸統(tǒng)計信息管理,兩者都可以進行rdlock
柒昏,wrlock
凳宙,但INEST lock多了在!auth
上進行remote_wrlock
的操作。相比simple lock sm职祷,scatter sm多了MIX狀態(tài)氏涩,提供多個副本同時寫入的功能届囚。舉例來說,假設兩個Active MDS是尖,某個inode關聯(lián)的目錄分裂成兩個分片分別位于兩個MDS上意系,在兩個分分片下各自創(chuàng)建新文件,這時如果INEST鎖在MIX狀態(tài)饺汹,則rstat信息會在兩個MDS上各自更新(各自+1)蛔添,當有讀請求需要讀取inode的rstat信息時,由于需要對INEST進行rdlock
首繁,這時會先把兩個MDS上分散的數(shù)據(jù)整合到inode的auth節(jié)點上作郭,然后加鎖才會成功,最后客戶端讀到正確數(shù)據(jù)弦疮。
scatter sm在auth和!auth上加鎖 sm_filelock
filelock sm只有一個類型的鎖:IFILE夹攒。
對于目錄IFILE管理本層目錄的統(tǒng)計信息(INEST管理的是遞歸信息),可以進行rdlock
胁塞,wrlock
咏尝,remote_wrlock
。三種加鎖行為和scatterlock sm一樣啸罢。
對于文件编检,IFILE管理每個client對文件的讀寫及范圍∪挪牛可以進行rdlock
允懂,xlock
,這兩種加鎖行為和simplelock sm一樣衩匣。
lease
在client端元數(shù)據(jù)依然有dir
蕾总,inode
,dn
三種形式琅捏,但比mds中要簡單得多生百,dn不再有三種形態(tài),而是只有兩種:有inode關聯(lián)柄延,沒有inode關聯(lián)蚀浆。dentry lease被用來表示dn在client端的有效性。
dentry lease存在的必要性可能有這樣兩個原因:
- 有inode關聯(lián)的dn可以通過inode的cap來判斷dn有效性搜吧,但沒有inode關聯(lián)的dn就無法借助inode的cap來判斷了
- 在read dir的時候市俊,可以不用獲取dir下各個節(jié)點的inode
loner
從CInode::calc_ideal_loner()
可以看出loner是指在所有client中,當只有一個client在請求寫權限時滤奈,這個client就被當做loner摆昧。
根據(jù)src/mds/locks.c
中狀態(tài)機的定義,只有simplelock sm和filelock sm有l(wèi)oner的概念僵刮,作為loner的client對元數(shù)據(jù)具有全部權限(讀/互斥)据忘,非loner的client則沒有任何權限鹦牛,因此也就無法操作元數(shù)據(jù),這本質上是加鎖過程產(chǎn)生的一個結果勇吊。加鎖簡單來說是為了保證數(shù)據(jù)一致性曼追,具體來說是mds根據(jù)狀態(tài)機收回其他client的cap,如果client端有臟數(shù)據(jù)汉规,則先更新數(shù)據(jù)礼殊,再將cap授予給請求操作的client這樣一個過程。拿simplelock sm舉例针史,當一個client需要對一個文件修改owner時晶伦,請求發(fā)到mds后,mds對inode的AUTH lock進行xlock
啄枕,當xlock
成功時婚陪,表明之前(如果有的話)授予給其他client的對于AUTH的cap已經(jīng)被收回,這時mds可以對inode進行修改频祝,修改完后要進行drop locks泌参,如果自從xlock
后,再沒有其他client請求這個inode的cap常空,那么這時發(fā)起請求的這個client就是loner沽一,AUTH lock進入到LOCK_EXCL
狀態(tài),根據(jù)狀態(tài)機定義這個client現(xiàn)在對AUTH具有全部權限漓糙,這也和loner的字面意思也相符铣缠。如果在xlock
成功后,請求處理完成前昆禽,又有其他client請求inode的寫cap(CEPH_CAP_GEXCL
)蝗蛙,那么當?shù)谝粋€請求處理完,drop locks時發(fā)現(xiàn)其他節(jié)點也在請求寫为狸,這時不滿足loner條件歼郭,鎖的狀態(tài)不再進入到LOCK_EXCL
遗契,二是根據(jù)狀態(tài)機定義和各個client對cap的請求辐棒,重新計算狀態(tài),根據(jù)得到的狀態(tài)將cap發(fā)送給第一個請求中的client牍蜂,至此漾根,修改文件owner的那個請求完成。
cap
client端針對每個inode都有獨立的cap鲫竞,表示是否可以相應元數(shù)據(jù)進行讀寫辐怕。從狀態(tài)機定義可以看出,scatter sm只有sync狀態(tài)下允許client讀从绘,其他狀態(tài)下client沒有任何權限寄疏,這和scatter sm下的兩個鎖作用也相符合:IDFT管理目錄分片和INEST管理目錄遞歸統(tǒng)計是牢,這兩種信息對于client來說只能讀取,client不應該去嘗試修改陕截,因為這兩種信息是在mds中進行維護的驳棱。對于simplelock sm,client對每種資源(對應一種鎖類型)有讀和互斥兩個權限农曲,符合常理社搅。對于filelock sm,SHARED
和EXCL
用來維護對stats(對目錄)和size(對普通文件)這些資源的互斥乳规,CEPH_CAP_FILE_RD
和CEPH_CAP_FILE_WR
用來管理普通文件的讀取和寫入形葬,CEPH_CAP_FILE_CACHE
和CEPH_CAP_FILE_BUFFER
用來管理普通文件的緩沖讀寫能力(對應本地文件系統(tǒng)中的Cache和Buffer功能)。
client range
根據(jù)filelock sm可以看出對普通文件是支持多個client下同時讀寫的暮的,比如LOCK_MIX
狀態(tài)下笙以,每個client都能擁有CEPH_CAP_GRD|CEPH_CAP_GWR
權限。相應的在MDS端冻辩,client range結構用來記錄每個client當前的讀寫范圍源织,當有其他client改變了文件的size后,相應client range要更新微猖。
inline data
當一個文件過小時(不超過client_max_inline_size
)把數(shù)以inode的attr(blustore中最終就是rocksdb的key-val)形式存在谈息。
pin和freeze
pin表示元數(shù)據(jù)正在被引用,這時無法對目錄進行遷移凛剥、分裂操作侠仇,需要進行遷移或者分裂時需要先freeze目標子樹,freeze后相關的元數(shù)據(jù)節(jié)點無法被pin犁珠,也就無法被修改逻炊。