原文地址: https://github.com/collie/sheepdog/wiki/Sheepdog-Design
Sheepdog 設計
Sheeepdog采用完全對稱的結構,沒有類似元數據服務的中心節點. 這種設計有以下的特點.
1) 性能于容量的線性的可擴展性.
當需要提升性能或容量時,只需向集群中增加新的機器便能使Sheeepdog線性成長.
2) 沒有單點故障
即使某臺機器發生故障,依然可以通過其他機器訪問數據.
3) 容易管理
不需要配置機器角色,當管理員在新增的機器開啟Sheepdog守護進程時, Sheepdog會自動檢測新加入的機器并配置它成為存儲系統中的一員.
結構概述

Sheepdog是一個分布式存儲系統.為Sheepdog客戶端(QEMU的塊驅動程序)提供對象存儲(類似于簡單的鍵值對). 接下來幾章將更加詳細的闡述Sheepdog各個部分.
1) 對象存儲(Object對象存儲(Object Storage)
2) )
Sheepdog不同于一般的文件系統, Sheepdog進程為QEMU(Sheepdog進程名)創建一個分布式對象存儲系統,它可以存儲”對象”.這里的”對象”數據大小可變,并有唯一的標識,通過標識可以進行讀/寫/創建/刪除操作.對象存儲組成”網關”和”對象管理器”.
3) 網關(getway)
Getway接收QEMU塊驅動的I/O請求(對象id,偏移,長度和操作類型),通過一直散列算法獲得目標節點,然后轉發I/O請求至該節點.
4) 對象管理器(Object manager)
對象管理器接收getway轉發過來的I/O請求,然后對磁盤執行讀/寫操作.
5) 集群管理器(Cluster manager)
集群管理器管理管理節點成員(探測失敗/新增節點并報告節點成員的變化),以及一些需要節點一致的操作(vdi 創建, 快照 vdi等).當前集群管理器使用corosync集群引擎.
6) QEMU 塊驅動
QEMU塊驅動把VM image分為固定大小(默認4M),并通過其getway存儲到對象存儲中
對象存儲(Object Storage)
每個對象使用一個64bit的整數作為全局標識,并在多臺機器存有備份,QEMU塊驅動并不關心存儲的位置,對象存儲系統負責管理存儲的位置.
對象類型(object types)
Sheepdog的對象分為以下四種:
1) 數據類型(data object)
它包括虛擬磁盤映射的真實數據,虛擬磁盤映射分為固定大小的數據對象, Sheepdog客戶端訪問這個對象.
2) vdi object
它包括虛擬磁盤映射的元數據(例:映射名,磁盤大小,創建時間,vdi的數據對象ID等).
3) vmstate object
它存儲運行中的VM狀態映射.管理員通過它獲取實時快照信息.
4) vdi attr object
使用它存儲各個vdi的屬性,屬性為鍵值對類型,類似于普通文件的擴展信息.
對象ID規則(object ID rules)
1) 0 - 31 (32 bits): 對象類型詳細信息
2) 32 - 55 (24 bits): vdi id
3) 56 - 59 ( 4 bits): 預留
4) 60 - 63 ( 4 bits): 對象類型標識符
每個VDI有一個全局唯一的ID(vdi id), 通過VDI名求得的散列值,低三十二位使用如下:
對象類型 | 低32位的作用 |
數據類型 | 虛擬磁盤映射的索引號 |
Vdi對象 | 未使用(填0) |
Vm狀態對象 | Vm狀態映射索引 |
Vdi屬性對象 | 鍵名的散列值 |
對象格式(object format)
1) 數據對象
虛擬磁盤映射的塊
2) Vdi對象
2 char name[SD_MAX_VDI_LEN]; /* the name of this VDI*/
3 char tag[SD_MAX_VDI_TAG_LEN]; /* the snapshot tag name */
4 uint64_t ctime; /* creation time of this VDI */
5 uint64_t snap_ctime; /* the time snapshot is taken */
6 uint64_t vm_clock_nsec; /* vm clock (used for live snapshot) */
7 uint64_t vdi_size; /* the size of VDI */
8 uint64_t vm_state_size; /* the size of vm state (used for live snapshot) */
9 uint16_t copy_policy; /* reserved */
10 uint8_t nr_copies; /* the number of object redundancy */
11 uint8_t block_size_shift; /* info about the size of the data object */
12 uint32_t snap_id; /* the snapshot id */
13 uint32_t vdi_id; /* the vdi id */
14 uint32_t parent_vdi_id; /* the parent snapshot vdi id of this VDI */
15 uint32_t child_vdi_id[MAX_CHILDREN]; /* the children VDIs of this VDI */
16 uint32_t data_vdi_id[MAX_DATA_OBJS]; /* the data object IDs this VDI contains*/
17 };
3) Vm狀態對象
Vm狀態映射塊
4) Vdi屬性對象
前SD_MAX_VDI_ATTR_KEY_LEN位(256位)為屬性的鍵名,余下的是屬性指.
只讀/可寫對象(read-only/writable objects)
從如何訪問對象的角度,我們還可以把Sheepdog對象分為以下兩類.
1) 只讀對象(例:VDI快照數據對象)
只允許一個VM對其讀寫,其他vm無法訪問
2) 可寫對象
不允許任何VM對其寫,所有VM都可讀
其他功能(other features)
Sheepdog對象存儲可接收正在寫時復制(copy-on-write)的請求.當一個客戶端發送一個創建和寫的請求時,同時可以指定基本對象(CoW操作的來源),這用于快照和克隆操作.
網關(Gateway)
對象存在哪(where to store objects)
Sheepdog使用一致性哈希算法決定存放對象的位置,一致性哈希算法提供哈希表,而且增加或介紹節點不回顯著的改變對象映射,通過哈希表能使I/O負載均衡.
副本(replication)
Sheepdog的數據副本很簡單,我們假設只有一個寫,所以寫沖突不會發生,客戶端可以并行發生請求到目標節點,發生讀請求到一個目標節點如果客戶端自己處理I/O請求順序.
寫I/O流(write I/O flow)
Getway使用一致性哈希算法計算目標節點并發送寫請求到所有目標節點,只有所有副本均更新成功寫請求才會成功,這是因為如果一個副本未更新,getway有可能從未更新的節點讀取舊數據.
讀I/O流(read I/O flow)
Getway使用一致性哈希算法計算目標節點,并發送讀請求到一個目標節點.
1) 修復對象一致性
當某節點在轉發I/O請求時crash,有可能破壞副本的一致性,所以當getway第一次讀取對象時會試圖修復其一致性,從一節點讀取整個對象并用它覆蓋所有副本.
重試I/O請求(retrying I/O requests)
Sheepdog存儲所有成員節點的歷史信息,我們把歷史版本號叫做”epoch”(詳見章節’對象恢復’). 如果getway轉發I/O請求至目標節點并且getway與目標節點epoch號不相符,I/O請求失敗且getway重試請求直到epcho號相符,這就需要保持副本強一致性.
I/O重試也可能發生在目標節點掛了導致無法完成I/O操作.
對象管理器(Object Manager)
對象管理器把對象存儲到本地磁盤,當前把每個對象存儲為一個文件,這中方法簡單.我們也可以使用DBMS(例: BerkeleyDB, Tokyo Cabinet等) 作為對象存儲器,但還不支持.
路徑命名規則(path name rule)
對象存儲成如下路徑:
/store_dir/obj/[epoch number]/[object ID]
所有對象文件有一個擴展屬性: 副本數(sheepdog.copies),
寫日志(write journaling)
當sheep進程在寫操作過程中失敗,對象有可能至少部分更新,一般情況這不會有問題,因為如果VM未接收成功消息,不保證所寫部分的內容.然而對于vdi對象,我們必須整體更新或整體未更新,因為如果vdi對象只是部分更新,VDI的元數據有可能被破壞. 為例防止這個問題,我們使用日志記錄對vdi對象的寫操作. 日志過程很簡單:
1) 創建日志文件"/store_dir/journal/[epoch]/[vdi object id]"
2) 首先寫數據到日志文件
3) 寫一個數據到vdi對象
4) 刪除日志文件
集群管理器(Cluster Manager)
大多情況, Sheepdo客戶端單獨訪問它們的映射因為我們不允許兩個客戶端同時訪問一個映射,但是某些VDI操作(例:克隆VDI,創建VDI)必須做,因為這些操作更新全局信息,我們使用Corosync集群引擎完成而不是中心服務器.
我們將擴展Sheepdog以支持其他集群管理系統.
本章正在編輯
QEMU 塊驅動(QEMU Block Driver)
Sheepdog卷被分為4M的數據對象,剛創建的對象未分配,也就是說,只有寫對象被分配.
Open
首先QEMU塊驅動通過getway的bdrv_open()從對象存儲讀取vdi
讀/寫(read/write)
塊驅動通過請求的部分偏移量和大小計算數據對象id, 并向getway發送請求. 當塊驅動發送寫請求到那些不屬于其當前vdi的數據對象是,塊驅動發送CoW請求分配一個新的數據對象.
寫入快照vdi(write to snapshot vdi)
我們可以把快照VDI附加到QEMU, 當塊驅動第一次發送寫請求到快照VDI, 塊驅動創建一個新的可寫VDI作為子快照,并發送請求到新的VDI.
VDI操作(VDI Operations)
查找(lookup)
當查找VDI對象時:
1) 通過求vdi名的哈希值得到vdi id
2) 通過vdi id計算di對象
3) 發送讀請求到vdi對象
4) 如果此vdi不是請求的那個,增加vdi id并重試發送讀請求
快照,克隆(snapshot, cloning)
快照可克隆操作很簡單,
1) 讀目標VDI
2) 創建一個與目標一樣的新VDI
3) 把新vdi的‘'parent_vdi_id''設為目標VDI的id
4) 設置目標vdi的''child_vdi_id''為新vdi的id.
5) 設置目標vdi的''snap_ctime''為當前時間, 新vdi變為當前vdi對象
刪除(delete)
TODO:當前,回收未使用的數據對象是不會被執行,直到所有相關VDI對象(相關的快照VDI和克隆VDI)被刪除.
所有相關VDI被刪除后, Sheepdog刪除所有此VDI的數據對象,設置此VDI對象名為空字符串.
對象恢復(Object Recovery)
epoch
Sheepdog把成員節點歷史存儲在存儲路徑, 路徑名如下:
/store_dir/epoch/[epoch number]
每個文件包括節點在epoch的列表信息(IP地址,端口,虛擬節點個數).
恢復過程(recovery process)
1) 從所有節點接收存儲對象ID
2) 計算選擇那個對象
3) 創建對象ID list文件"/store_dir/obj/[the current epoch]/list"
4) 發送一個讀請求以獲取id存在于list文件的對象. 這個請求被發送到包含前一次epoch的對象的節點.( The requests are sent to the node which had the object at the previous epoch.)
5) 把對象存到當前epoch路徑.
沖突的I/O(conflicts I/Os)
如果QEMU發送I/O請求到某些未恢復的對象, Sheepdog阻塞此請求并優先恢復對象.
協議(Protocol)
Sheepdog的所有請求包含固定大小的頭部(48位)和固定大小的數據部分,頭部包括協議版本,操作碼,epoch號,數據長度等.
between sheep and QEMU
操作碼 | 描述 |
SD_OP_CREATE_AND_WRITE_OBJ | 發送請求以創建新對象并寫入數據,如果對象存在,操作失敗 |
SD_OP_READ_OBJ | 讀取對象中的數據 |
SD_OP_WRITE_OBJ | 向對象寫入數據,如果對象不存在,失敗 |
SD_OP_NEW_VDI | 發送vdi名到對象存儲并創建新vdi對象, 返回應答vdi的唯一的vdi id |
SD_OP_LOCK_VDI | 與SD_OP_GET_VDI_INFO相同 |
SD_OP_RELEASE_VDI | 未使用 |
SD_OP_GET_VDI_INFO | 獲取vdi信息(例:vdi id) |
SD_OP_READ_VDIS | 獲取已經使用的vdi id |
between sheep and collie
操作碼 | 描述 |
SD_OP_DEL_VDI | 刪除VDI |
SD_OP_GET_NODE_LIST | 獲取sheepdog的節點列表 |
SD_OP_GET_VM_LIST | 未使用 |
SD_OP_MAKE_FS | 創建sheepdog集群 |
SD_OP_SHUTDOWN | 停止sheepdog集群 |
SD_OP_STAT_SHEEP | 獲取本地磁盤使用量 |
SD_OP_STAT_CLUSTER | 獲取sheepdog集群信息 |
SD_OP_KILL_NODE | 退出sheep守護進程 |
SD_OP_GET_VDI_ATTR | 獲取vdi屬性對象id |
between sheeps
操作碼 | 描述 |
SD_OP_REMOVE_OBJ | 刪除對象 |
SD_OP_GET_OBJ_LIST | 獲取對象id列表,并存儲到目標節點 |