天天看點

GlusterFS源碼解析 —— GlusterFS 結構體系分析簡述對體系結構的具體分析

經過這幾天對glusterfs的分析, 對其體系結構已經有了初步的了解。 值得慶賀的一點就是  glusterfs 的整個體系結構非常清晰, 高度子產品化的設計使得我們對他的了解和擴充變得比較容易。

我打算從下面幾步來分析其體系結構:

1. 給出幾個從網絡上收集的結構圖, 用以幫助我們來從整理上認識其體系結構。

2. 以 glusterfs 的一個用戶端配置檔案入手, 來了解配置檔案的同時也進一步來了解其體系結構。

上面的兩項都是基于宏觀方面的分析, 下面我們将從系統的微觀方面來了解其相關的資料流 :

3. glusterfs 系統中, 系統的主體是一顆 translator 的樹結構,我們來分析整個translator樹結構的建立過程(以上面給出的用戶端的配置檔案為例, 來建立這棵樹)

4. 以一個 "write" 操作為例, 來了解glusterfs的整個處理流程

    以上就是本文的一個大緻分析思路。

GlusterFS源碼解析 —— GlusterFS 結構體系分析簡述對體系結構的具體分析

圖一

這是來自 glusterfs 的官方結構圖, 從這個圖中, 我們可以得到如下的資訊:

glusterfs 沒有 metedata 子產品, 沒有metedata的設計模式, 使得系統的複雜度降低, 也避免了metedata成為整個系統性能瓶頸的問題, 當然, 這種體系結構僅僅适合于基于以檔案為對象的存儲體系, 對于像 googlefs,lustre 等基于磁盤塊,inode的存儲系統是不能沒有metedata的。

 類似于 google, lustre等, metedata是其題寫結構中不可缺少的部分, 因為他們是基于磁盤塊,inode的存儲系統。 優點: 系統性能很好,他們将檔案進行了一定的分割,并且以塊的方式直接存儲在磁盤上,減少了類似于 vfs的處理流程, 是以他們對于高性能的資料處理是很有優勢的。 缺點: 正是因為引入了 metedata, 使得系統的複雜度增加, 并且并發能力受到很大的限制(因為所有的處理首先要通過metedata來定位資料的分布),增對于這個問題, 業界也出現了對metedata的叢集, 這可以緩解其并發瓶頸的問題。 glusterfs就是這一類系統 其優勢是:系統複雜度降低, 擴充容易,并且是在使用者層實作,容易部署和維護,并且沒有metedata的瓶頸限制, 是以其并發性能較上面的系統有優勢。 但其不足也是很明顯的: 這種類型的系統隻能是以檔案為存儲對象,是以他的處理性能會比metedata系統差。 基于我們的實際應用,結合 glusterfs 的優勢和不足, 綜合起來,glusterfs對于我們的應用還是一個不錯的選擇, 況且他在業界的實際使用和被關注度也越來越多, 這也是以後叢集存儲的一個發展方向, 也更加适合于民間的實際使用。

client 和 伺服器之間可以通過 rdma 來進行資料通訊。

infiniband 将是我們需要重點考慮和采用的方案, 他可以有效提高資料的傳輸效率。

GlusterFS源碼解析 —— GlusterFS 結構體系分析簡述對體系結構的具體分析

圖二

這個圖是上面圖一的細化, 從中我們可以知道:

1. client and server 的設計是高度子產品化的

2. client 的複雜度比 server 要大, 用戶端需要考慮的問題很多, 比如 read ahead, i/o cache, stripe, unify, replicate(afr)  等。

3. 是以,我們以後的重點是在client端。

GlusterFS源碼解析 —— GlusterFS 結構體系分析簡述對體系結構的具體分析

圖三

圖三是整個 glusterfs 資料流的一個概要圖:

1. 首先是在用戶端, 使用者通過glusterfs的mount point 來讀寫資料, 對于使用者來說, 叢集系統的存在對使用者是完全透明的, 使用者感覺不到是操作本地系統還是遠端的叢集系統。

2. 使用者的這個操作被遞交給 本地linux系統的vfs來處理。

3. vfs 将資料遞交給fuse 核心檔案系統:在啟動 glusterfs 用戶端以前, 需要想系統注冊一個實際的檔案系統fuse,如上圖所示,該檔案系統與ext3在同一個層次上面,  ext3 是對實際的磁盤進行處理, 而 fuse 檔案系統則是将資料通過 /dev/fuse 這個裝置檔案遞交給了glusterfs client端。是以, 我們可以将 fuse 檔案系統了解為一個代理。

4. 資料被 fuse 遞交給 glusterfs client 後, client 對資料進行一些指定的處理(所謂的指定,是按照client 配置檔案據來進行的一系列處理,  我們在啟動glusterfs  client  時 需 要 指 定 這 個 文 件 , 其 默 認 位 置 :/etc/glusterfs/client.vol)。

5. 在glusterfs client的處理末端, 通過網絡将資料遞交給 glusterfs server,

并且将資料寫入到伺服器所控制的儲存設備上。

這樣, 整個資料流的處理就完成了。

配置檔案如下:

我們可以給出上面配置檔案對應的一個邏輯圖, 如下圖:

GlusterFS源碼解析 —— GlusterFS 結構體系分析簡述對體系結構的具體分析

圖四

在 glusterfs 系統中引入了 translator(翻譯器)的處理機制(該機制有點類似于 linux 的檔案系統架構, linux檔案系統中, 采用了分層的設計, 也就是 vfs處理了所有檔案的公共部分, 當vfs處理完成後, 會将資料流遞交給下面的實際檔案系統,例如ext3, reiserfs,等, 隻不過  linux 的這種機制是兩層的設計, 而 glusterfs 的translator是一個多層次的設計, 也就是一顆樹的構造設計,這顆書中的每一個節點稱為一個 translator, 在glusterfs的内部資料結構中稱為

xlator_t)。

上面的圖四就是這樣的一顆 translator 樹(根據上面給出的配置檔案生成),我們可以把上圖中的每一個橢圓了解為一個  translator, 也可以稱為一個功能塊吧, 在glusterfs中就是這樣的體系結構, 系統對每一個translator 單獨定義為一個子產品, 系統會按照使用者配置檔案給定的資訊在系統初始化時來自動生成這樣的一顆樹, 如果是在用戶端, 樹根就是fuse子產品, 也就是io-cache的父節點是fuse子產品。

那麼照這樣了解的話, 整個glusterfs系統豈不是是由一棵樹組成的? 沒錯, 就是這樣的(可以對照linux的檔案系統來了解這個機制, 他們具有類似的原理):

GlusterFS源碼解析 —— GlusterFS 結構體系分析簡述對體系結構的具體分析

圖五

這個圖可以了解為glusterfs的一個内部架構圖, 所有的子功能(io-cache, readahead, unify, stripe …)被以一個xlator_t的結構表現在系統樹中, 每一個 xlator_t(也就是官方文檔中的translator)定義了自己的處理函數, 可以把 xlator_t 了解為c++語言中的類。我們還是以上面的配置檔案以及她所對應的圖為例,來講解glusterfs系統在初始化的時候是如何來構造這棵樹的:(glusterfs 系統的初始化部分)

  用戶端的啟動指令:

  glusterfs –l /tmp/glusterfs.log –f /etc/glusterfs/client.vol /mnt/gluster

  指令說明: -l /tmp/glusterfs.log : 指出log 資訊檔案

             -f /etc/glusterfs/client.vol 給出用戶端對應的卷配置檔案

             /mnt/glusterfs : 用戶端的mount point

1. 在系統啟動的時候, 首先從指令行知道用戶端的配置檔案是 client.vol 檔案

2. 讀取該配置檔案, 并進行分析, 每一個如下的資訊:

也就是 volume …. end-volume資訊, 每一個這樣的資訊會被生成一個新的樹節點(xlator_t), 挂接到以 fuse 為根節點的樹上, 每一個xlator_t節點有自己的屬性定義(就是上面的 option 字段定義的(key, value)值)和大量的函數指針定義。 我們也不難發現, 實質上配置檔案從開始到最後, 是先定義這棵樹的葉子節點, 然後一層一層向樹根方向定義的。

3. 分析完整個配置檔案後, 系統中的一顆完整的 xlator_t結構樹就被建立成功, 每一個 xlator_t 結構有兩個重要的函數:  init(), fini(), 其中 init()是在對這個xlators 初始化的時候調用的,來初始化每一個 xlator_t對象。

每個xlator_t 結構

定義了大量的函數指針, 這些函數指針大緻可以分為三類:

a) 普通的資料處理函數指針(用于正常的資料處理)

b) 回調函數指針,用于處理結果的傳回。

c) 管理類函數指針從源代碼中可以看到, fuse對這三類指針的定義為空,因為 fuse是樹根節點,是以沒有定義這些處理函數。

可以對照源代碼來了解上面的說明, 進而對 xlator_t (也就是 translator 機制會有更加深刻的了解)

4. 當 整 個 樹 準 備 就 緒 後 ,  根 節 點 (fuse)  會 向 所 有 的 子 節 點 發 出 一 個 gf_event_parant_up的通知, 用以宣告父節點已經準備就緒, 直到到達樹的葉子節點的時候,這時葉子節點會向樹根方向來應答一個gf_event_child_up,用以向父節點宣告子節點也準備就緒。

至此,  xlator_t 結構樹的初始化工作宣告完成。 下面的工作就是事件(event)的dispatch。在glusterfs中, 有一個event(事件)處理部分, 用一個 event_poll 來管理整個系統的事件處理, 這些事件包括:  client發送資料, client接收資料。

為什麼要有event這個部分? 因為很多事情的發生不是我們能夠預知的,比如 client收到了來自伺服器的資料, 我們不知道什麼時候這個資料會來, 那麼我們可以通過向 event_poll 中注冊一個這個事件, 讓linux系統來監督(通過poll_wait系統調用, 早期是select系統調用, 大家對select的作用應該比較了解, 是以也能夠了解 event在系統中的作用了)對應的socket fd句柄,如果有資料到達, 那麼就按照事件在注冊時指定的處理函數來處理這個資料。 是以 event 機制主要處理的是一些需要監聽的事件。

以一個 "write" 操作為例, 來了解整個過程的流程:

下面我們以在用戶端一個寫操作為例, 來打通整個流程,例如在  /mnt/glusterfs(glusterfs 用戶端 的mount point)中 寫一個檔案為例:

1. 當向 /mnt/glusterfs 中寫入資料時, linux 會向 vfs 傳遞這個動作, vfs會将實際的處理交給 fuse(kernel)檔案系統, 然後通過 /dev/fuse 這個裝置檔案, 将實際的寫處理遞交給了 glusterfs 系統樹的 fuse_xlator_t 這個根節點,這樣, 一個寫資料流就正式流入了 系統的 xlator_t 結構樹。

2. fuse_xlator_t 這個樹的根節點會将這個寫處理遞交給他的子節點, 具體的遞交是通過下面的這個宏完成的:

該宏的定義如下:

3. 這樣, 每一個xlator_t 節點都會按照上面的方式将寫資料遞交給他的子節點來處理, 直到到達了樹的葉子節點。

4. 葉子節點是跟 socket 關聯在一起的, 是以這個寫操作就通過 socket 遞交給glusterfs 伺服器處理。

5. 至于在用戶端這邊,處理結果的傳回,與上面 父節點-> 子節點 的處理方向相反, 是由 子節點 -> 父節點, 這是通過下面的宏來實作的:

這樣, 處理的結果會一直被傳回給 fuse_xlators, 然後通過 fuse(kernel)傳回給使用者。

通過上面的分析, 我相信大家對 glusterfs 的整體架構和内部的結構和資料流有了一個大緻的了解, 有了上面這些知識的指導, 然後在結合源代碼, 對glusterfs 的了解就會更加透徹。 剩下的任務,就是針對各個 translator 的研究分析了。

                                                                                  —— —— 以上内容整理自網際網路

繼續閱讀