簡述
經過這幾天對Glusterfs的分析, 對其體系結構已經有了初步的理解。 值得慶賀的一點就是 Glusterfs 的整個體系結構非常清晰, 高度模塊化的設計使得我們對他的理解和擴展變得比較容易。1. 給出幾個從網絡上收集的結構圖, 用以幫助我們來從整理上認識其體系結構。
2. 以 Glusterfs 的一個客戶端配置文件入手, 來理解配置文件的同時也進一步來理解其體系結構。
3. Glusterfs 系統中, 系統的主體是一顆 translator 的樹結構,我們來分析整個translator樹結構的建立過程(以上面給出的客戶端的配置文件爲例, 來建立這棵樹)
4. 以一個 "write" 操作爲例, 來理解glusterfs的整個處理流程
以上就是本文的一個大致分析思路。
對體系結構的具體分析
一、給出幾個從網絡上收集的結構圖, 來幫助我們來認識其體系結構。
圖一
這是來自 glusterfs 的官方結構圖, 從這個圖中, 我們可以得到如下的信息:
1.
glusterfs 沒有 MeteData 模塊, 沒有MeteData的設計模式, 使得系統的複雜度降低, 也避免了MeteData成爲整個系統性能瓶頸的問題, 當然, 這種體系結構僅僅適合於基於以文件爲對象的存儲體系, 對於像 GoogleFS,Lustre 等基於磁盤塊,inode的存儲系統是不能沒有MeteData的。
1.1 有MeteData系統的優勢和不足:
類似於 Google, Lustre等, MeteData是其題寫結構中不可缺少的部分, 因爲他們是基於磁盤塊,inode的存儲系統。
優點: 系統性能很好,他們將文件進行了一定的分割,並且以塊的方式直接存儲在磁盤上,減少了類似於 VFS的處理流程, 所以他們對於高性能的數據處理是很有優勢的。
缺點: 正是因爲引入了 MeteData, 使得系統的複雜度增加, 並且併發能力受到很大的限制(因爲所有的處理首先要通過MeteData來定位數據的分佈),增對於這個問題, 業界也出現了對MeteData的集羣, 這可以緩解其併發瓶頸的問題。
1.2 沒有MeteData系統的優勢和不足:
Glusterfs就是這一類系統
其優勢是:系統複雜度降低, 擴展容易,並且是在用戶層實現,容易部署和維護,並且沒有MeteData的瓶頸限制, 所以其併發性能較上面的系統有優勢。
但其不足也是很明顯的: 這種類型的系統只能是以文件爲存儲對象,所以他的處理性能會比MeteData系統差。
1.3
基於我們的實際應用,結合 Glusterfs 的優勢和不足, 綜合起來,Glusterfs對於我們的應用還是一個不錯的選擇, 況且他在業界的實際使用和被關注度也越來越多, 這也是以後集羣存儲的一個發展方向, 也更加適合於民間的實際使用。
2.
client 和 服務器之間可以通過 RDMA 來進行數據通訊。
3.
InfiniBand 將是我們需要重點考慮和採用的方案, 他可以有效提高數據的傳輸效率。
圖二
這個圖是上面圖一的細化, 從中我們可以知道:1. client and server 的設計是高度模塊化的
2. client 的複雜度比 server 要大, 客戶端需要考慮的問題很多, 比如 Read Ahead, I/O Cache, Stripe, Unify, Replicate(AFR) 等。
3. 所以,我們以後的重點是在Client端。
圖三
圖三是整個 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 的一個客戶端配置文件入手, 來理解配置文件的同時也進一步來理解其體系結構。
配置文件如下:
*************************************************************
### Add client feature and attach to remote subvolume
## client 1
volume client1
type protocol/client
option transport-type tcp/client
option remote-host 10.0.0.2 # IP address of the remote brick
option remote-port 6996 # default server port is 6996
option remote-subvolume brick # name of the remote volume
end-volume
## client 2
volume client2
type protocol/client
option transport-type tcp/client
option remote-host 10.0.0.3
option remote-port 6996
option remote-subvolume brick
end-volume
## client 3
volume namespacenode
type protocol/client
option transport-type tcp
option remote-host 10.0.0.4
option remote-port 6996
option remote-subvolume brick
end-volume
## Add unify feature
volume bricks
type cluster/unify
subvolumes client1 client2
option scheduler rr
option namespace namespacenode
end-volume## Add readahead feature
volume readahead
type performance/read-ahead
option page-size 1MB # unit in bytes
option page-count 2 # cache per file = (page-count x page-size)
subvolumes bricks
end-volume
##Add io-cache feature
volume ioc
type performance/io-cache
subvolumes readahead
option page-size 1MB # 128KB is default
option cache-size 64MB # 32MB is default
option force-revalidate-timeout 5 # 1second is default
end-volume
我們可以給出上面配置文件對應的一個邏輯圖, 如下圖:
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 文件
volume client
type protocol/client
option transport-type tcp/client
option remote-host 10.0.0.3
option remote-port 6996
option remote-subvolume brick
end-volume
也就是 volume …. End-volume信息, 每一個這樣的信息會被生成一個新的樹節點(xlator_t), 掛接到以 FUSE 爲根節點的樹上, 每一個xlator_t節點有自己的屬性定義(就是上面的 option 字段定義的(key, value)值)和大量的函數指針定義。 我們也不難發現, 實質上配置文件從開始到最後, 是先定義這棵樹的葉子節點, 然後一層一層向樹根方向定義的。
每個xlator_t 結構
定義了大量的函數指針, 這些函數指針大致可以分爲三類:a) 普通的數據處理函數指針(用於正常的數據處理)
b) 回調函數指針,用於處理結果的返回。
c) 管理類函數指針從源代碼中可以看到, FUSE對這三類指針的定義爲空,因爲 FUSE是樹根節點,所以沒有定義這些處理函數。
以一個 "write" 操作爲例, 來理解整個過程的流程:
下面我們以在客戶端一個寫操作爲例, 來打通整個流程,例如在 /mnt/glusterfs(glusterfs 客戶端 的mount point)中 寫一個文件爲例: STACK_WIND (frame,
writev_cbk,
child,
child->fops->writev,
fd,
vector,
count,
off);
該宏的定義如下:
/* make a call */
#define STACK_WIND(frame, rfn, obj, fn, params ...) \
do { \
call_frame_t *_new = NULL; \
\
_new = CALLOC (1, sizeof (call_frame_t)); \
ERR_ABORT (_new); \
typeof(fn##_cbk) tmp_cbk = rfn; \
_new->root = frame->root; \
_new->next = frame->root->frames.next; \
_new->prev = &frame->root->frames; \
if (frame->root->frames.next) \ frame->root->frames.next->prev = _new; \
frame->root->frames.next = _new; \
_new->this = obj; \
_new->ret = (ret_fn_t) tmp_cbk; \
_new->parent = frame; \
_new->cookie = _new; \
LOCK_INIT (&_new->lock); \
frame->ref_count++; \
\
fn (_new, obj, params); \
} while (0)
3. 這樣, 每一個xlator_t 節點都會按照上面的方式將寫數據遞交給他的子節點來處理, 直到到達了樹的葉子節點。
/* return from function */
#define STACK_UNWIND(frame, params ...) \
do { \
ret_fn_t fn = frame->ret; \
call_frame_t *_parent = frame->parent; \
_parent->ref_count--; \
fn (_parent, frame->cookie, _parent->this, params); \
} while (0)
這樣, 處理的結果會一直被返回給 fuse_xlators, 然後通過 FUSE(kernel)返回給用戶。
通過上面的分析, 我相信大家對 Glusterfs 的整體框架和內部的結構和數據流有了一個大致的瞭解, 有了上面這些知識的指導, 然後在結合源代碼, 對Glusterfs 的理解就會更加透徹。 剩下的任務,就是針對各個 Translator 的研究分析了。
—— —— 以上內容整理自互聯網