Glusterfs3.3.1DHT(hash分布)源代碼分析

作者:老叮當(dāng)貓

來源:開源中國

原文:https://my.oschina.net/uvwxyz/blog/182224

版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!

1.DHT簡介

GlusterFS使用算法進(jìn)行數(shù)據(jù)定位,集群中的任何服務(wù)器和客戶端只需根據(jù)路徑和文件名就可以對數(shù)據(jù)進(jìn)行定位和讀寫訪問。換句話說,GlusterFS不需要將元數(shù)據(jù)與數(shù)據(jù)進(jìn)行分離,因?yàn)槲募ㄎ豢瑟?dú)立并行化進(jìn)行。GlusterFS中數(shù)據(jù)訪問流程如下:

1)? ? 計(jì)算hash值,輸入?yún)?shù)為文件路徑和文件名;

2)? ? 根據(jù)hash值在集群中選擇子卷(存儲服務(wù)器),進(jìn)行文件定位;

3)? ? 對所選擇的子卷進(jìn)行數(shù)據(jù)訪問。

2.DHT源碼流程分析

2.1正常流程

2.1.1創(chuàng)建目錄

創(chuàng)建目錄的主要步驟有:

1)? ? ? 根據(jù)目錄名計(jì)算哈希值,由其哈希值所在的hash區(qū)間確定hashed卷。

2)? ? ? 向hashed卷下發(fā)mkdir操作。

3)? ? ? 待hashed卷返回后,再向除hashed卷之外的所有子卷下發(fā)mkdir操作。

4)? ? ? 待所有子卷均返回后,合并目錄屬性。

5)? ? ? 為每個子卷在該目錄上分配hash區(qū)間。

6)? ? ? 將各自的hash區(qū)間寫入子卷上該目錄的擴(kuò)展屬性中。

7)? ? ? 創(chuàng)建目錄結(jié)束。

其流程如下圖所示:

2.1.2創(chuàng)建文件

創(chuàng)建文件的主要步驟有:

1)? ? ? 根據(jù)文件名計(jì)算hash值,根據(jù)父目錄hash分布獲取其hashed卷。

2)? ? ? 若hashed卷空間,inode數(shù)目等沒有超過上限,則直接在hashed卷創(chuàng)建該文件。

3)? ? ? 若hashed卷空間,inode數(shù)目等超過了上限,則在子卷中選擇一個最優(yōu)的作為其avail卷。

4)? ? ? 在hashed卷上創(chuàng)建DHTLINKFILE,其擴(kuò)展屬性中記錄著avail卷的名字。

5)? ? ? 在avail卷上創(chuàng)建該文件。

6)? ? ? 創(chuàng)建文件結(jié)束。

其流程如下圖所示:

2.1.3打開文件

Open文件的主要步驟有:

1)? ? ? 向其cached卷下發(fā)open操作(在open前會調(diào)用lookup獲取其cached卷)。

2)? ? ? 若open成功,則將文件fd等信息返回,open操作完成(如果失敗且返回的錯誤碼是不存在,也會直接返回)。

3)? ? ? 若open失敗后會重新獲取dst_node(因?yàn)橛锌赡芴幱跀?shù)據(jù)遷移第二階段)。

4)? ? ? 向重新獲取dst_node在此下發(fā)open。

5)? ? ? 若失敗,返回錯誤碼。

6)? ? ? 若成功,將fd等返回上層,open操作完成。

其流程如下圖所示:

2.1.4讀取文件

讀取文件的主要流程有:

1)? ? ? 向cached卷下發(fā)read操作。

2)? ? ? 若讀取成功且該文件未處于數(shù)據(jù)遷移第二階段,則將讀取數(shù)據(jù)返回,此次讀取結(jié)束。

3)? ? ? 若讀取成功但該文件處于數(shù)據(jù)遷移第二階段,則會重新獲取目標(biāo)卷,再次下發(fā)read操作。

4)? ? ? 若失敗且錯誤碼是ENOENT,則直接返回錯誤碼。

5)? ? ? 若失敗或該文件處于數(shù)據(jù)遷移第二階段,則會重新獲取目標(biāo)卷,再次下發(fā)read操作。

6)? ? ? 第二次讀取,若成功則將數(shù)據(jù)返回,若讀取失敗,將錯誤碼返回。

7)? ? ? 此次讀取操作結(jié)束。

其流程如下圖所示:

2.1.5寫入文件

向文件寫入數(shù)據(jù)的主要流程有:

1)? ? ? ? 向cached卷下發(fā)write命令。

2)? ? ? ? 待返回,若正處于數(shù)據(jù)遷移第二階段,重新獲取目標(biāo)卷等信息,再次下發(fā)write命令。

3)? ? ? ? 若正處于數(shù)據(jù)遷移第一階段,重新獲取目標(biāo)卷等信息,在次下發(fā)write命令。

4)? ? ? ? 將返回值等返回給上層(若有第二次write,將第二次write的返回值等返回給上層)。

寫入數(shù)據(jù)的流程如下圖所示:

2.1.6讀取目錄

讀取目錄項(xiàng)主要流程有:

1)? ? ? 向所有子卷下發(fā)opendir操作。

2)? ? ? 只將最后一個返回的返回值返回。

3)? ? ? 根據(jù)上層readdir中offset定位到某個子卷,向該子卷下發(fā)readdir操作。

4)? ? ? 將該子卷讀取的目錄項(xiàng)進(jìn)行過濾(過濾DHTLINKFILE,若不是first_up_subvol,也將目錄過濾掉),將讀取的目錄項(xiàng)返回。

5)? ? ? 若該子卷讀取的目錄項(xiàng)過濾后個數(shù)為0且next_offset != 0,說明該subvol尚未讀完,則繼續(xù)向該subvol下發(fā)readdir操作。

6)? ? ? 若該子卷讀取的目錄項(xiàng)過濾后個數(shù)為0但next_offset == 0,說明該subvol已經(jīng)讀完,則向next_subvol下發(fā)readdir操作。

7)? ? ? 如果next_subvol不為空,則next_subvol下發(fā)readdir操作返回后,重復(fù)執(zhí)行步驟4)的操作。

8)? ? ? 如果next_subvol為空,說明該目錄內(nèi)的所有項(xiàng)以讀取完畢。

? 注:上述中若count = 0但next_offset != 0,說明此次讀取的目錄項(xiàng)中均為目錄和DHTLINKFILE,全部被過濾掉,所以count = 0。

讀取目錄的流程如圖所示:

2.1.7lookup

Lookup操作的主要流程有:

1)? ? ? 根據(jù)name獲取其hash卷。

2)? ? ? 若不是第一次查詢且是目錄,則向所有子卷下發(fā)lookup操作,比對與inode中的信息是否一致,若不一致則更新。

3)? ? ? 若不是第一次查詢但不是目錄,則向cached下發(fā)lookup操作,若不存在,則需調(diào)用dht_lookup_everywhere.,找到后為其創(chuàng)建DHTLINKFILE。

4)? ? ? 若是第一次查詢且是目錄,則會向其hashed卷下發(fā)lookup操作,然后再向其它子卷下發(fā)lookup操作,合并后返回。

5)? ? ? 若是第一次查詢但不是目錄,則會向其hashed卷下發(fā)lookup操作,若返回的是DHT_LINKFILE,則還有向其cached卷下發(fā)lookup操作,將其屬性返回。

Lookup操作的流程如下圖所示:

2.2特殊處理

2.2.1添加卷后lookup

添加卷后lookup的主要流程有:

1)? ? ? 執(zhí)行添加卷命令后,將會重新初始化。

2)? ? ? lookup目錄時(shí),待各個子卷將目錄信息返回后,都會調(diào)用dht_layout_merge(),將各個子xlator指針,返回值等添加到layout中。

3)? ? ? 然后調(diào)用dht_layout_normalize時(shí),新添加的list.err(start=stop=0,在檢測是否有空洞和重疊時(shí)已按hash區(qū)間排序,所以新添加的卷沒有空洞和重疊)會被置為ENOENT。

4)? ? ? 所以dht_layout_normalize返回!=0,然后進(jìn)入目錄修復(fù)。

5)? ? ? 會調(diào)用dht_selfheal_dir_mkdir在新添加的卷上創(chuàng)建該目錄setattr(該目錄沒有分布區(qū)間信息,所以不需要setxattr)。

6)? ? ? 最后調(diào)用dht_selfheal_dir_finish結(jié)束。

注:再次lookup時(shí),在dht_layout_normalize中因?yàn)閘ayout->list.err < 0(err ==-1),所有該函數(shù)返回0(第一次該函數(shù)會返回ret>0),不會觸發(fā)目錄修復(fù)動作。

2.2.2后端手動添加文件

在后端手動添加文件后,再執(zhí)行l(wèi)s操作,其主要流程有:

1)? ? ? readdir時(shí),其父目錄會將該目錄項(xiàng)返回給上層。

2)? ? ? 然后對該文件進(jìn)行l(wèi)ookup。

3)? ? ? 若通過hashed_subvol直接定位到了該文件,則將該文件屬性返回給上層。

4)? ? ? 若沒有,則會lookup_everywhere,找到該文件,然后將該文件作為其cached_subvol,并創(chuàng)建hashed_subvol到cached_subvol的鏈接文件。

2.2.3后端手動添加目錄

后端手動添加目錄后,執(zhí)行l(wèi)s操作,其主要流程有:

1)? ? ? 若該新添加的目錄不是位于first_up_subvol,則該目錄向在其父目錄readdir時(shí)會被過濾,即在掛載點(diǎn)不會看到你新添加的目錄。

2)? ? ? 若新添加的目錄位于first_up_subvol,則在readdir父目錄時(shí)會向?qū)⒃撃夸涰?xiàng)返回給上層。

3)? ? ? 然后對該目錄項(xiàng)進(jìn)行l(wèi)ookup,在其hashed_subvol找到該目錄的話,執(zhí)行l(wèi)ooku_directory(各個卷查找該目錄)。若找不到,則會執(zhí)行l(wèi)ookup_everywhere.

4)? ? ? 在lookup_diectory后,若需要修復(fù),則在各子卷創(chuàng)建該目錄,并分配hash區(qū)間。

5)? ? ? 在lookup_everywhere時(shí),找到該目錄,然后再執(zhí)行l(wèi)ooku_directory.

2.2.4修復(fù)目錄layout

修復(fù)目layout的主要流程有:

1)? ? ? 重新分配hash區(qū)間,hash區(qū)間按子卷個數(shù)劃分,優(yōu)先分配與原區(qū)間重疊最大的區(qū)間段。

2)? ? ? 將重新分配的hash區(qū)間,存儲到其擴(kuò)展屬性中。

2.2.5數(shù)據(jù)遷移

數(shù)據(jù)遷移的主要流程有:

1)? ? ? 首先lookup該目錄。

2)? ? ? 遍歷該目錄下的DHT_LINKFIFE.

3)? ? ? 如果該文件實(shí)際就是符號鏈接,則根據(jù)源文件信息在to上建立該符號鏈接,如果是設(shè)備文件,在to上mknode。然后將源文件unlink

4)? ? ? 如果是普通文件,則在其hash卷上create該文件。

5)? ? ? 然后打開源文件。

6)? ? ? 檢測是否含有空洞文件。

7)? ? ? 進(jìn)行讀寫。

8)? ? ? 讀寫完畢后,move擴(kuò)展屬性。

9)? ? ? unlink源文件,truncate,然后清楚標(biāo)志位等。

10)? ? 遷移該文件結(jié)束。

3.結(jié)束

? ? ? 通過對DHT源代碼的分析,已基本清楚其工作流程。本文檔描述了dht部分的工作流程,若有描述或理解錯誤,請各位給予指正,謝謝。

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容