1. 簡介
Swift 前身是 Rackspace Cloud Files 項目, 有 Rackspace 於 2010 年貢獻給 OpenStack, 當時與 Nova 一起作為 OpenStack 最初僅有的兩個項目.
作為對象存儲的一種,Swift 比較適合存放靜態數據.所謂靜態數據是指長期不會發生更新的數據,或者在一定使其內更新頻率比較低的數據.例如,虛擬機的鏡像、多媒體數據及數據的被封.如果需要實時的更新數據,那么 Swift 並不是一個特別好的選擇,在這種情況下, Cinder 塊存儲更為合適.
若下圖所示,Swift 提供了 RESTful API 作為訪問的入口,存儲的每個對象都是一個 RESTful 資源,擁有一個唯一的 URL,我們可以發送 HTTP 請求將一些數據作為一個對象還給 Swift,也可以從 Swift 中請求一個之前存儲的對象,至於該對象是以何種形式存儲的且存儲於和中設備的什么位置,我們並不需要去關心.
- Swift 體系結構
如下圖所示,Swift 架構可以划分為兩個層次:訪問層(Access Tier) 與存儲層(Storage Nodes).
訪問層的更能類似於網絡設備中的 Hub, 主要包括兩個部分:代理服務器節點(Proxy Node)與認證(Authentication).分別負責 RESTful 請求的處理與身份的認證.在 Proxy Node 上運行的 Proxy Server 用來負責處理用戶的 RESTful 請求,在接受到用戶請求時,需要對用戶的神風進行認證,此時用戶所提供的身份資料會被轉發到認證服務進行處理. Proxy Server 可以使用 Memcached進行數據和對象的緩存,來減少書庫讀取的次數,提高用戶的訪問速度.
存儲層有一系列的物理存儲節點組成,負責對象數據的存儲,Proxy Node 在接受到用戶的訪問請求時,會將其轉發到相應的存儲節點上.為了在系統出現問題的情況下有效地將故障隔離在最小的物理范圍內,存儲層在物理上又分為如下一些層次:
- Region: 地理上隔絕的取余,也就是說不同的 Region 通常在地理位置上被隔絕開來.例如,兩個數據中心可以划分為兩個 Region.每個 Swift 系統默認至少有一個 Region.
- Zone: 在每個 Region 的內部又划分了不同的 Zone 來實現硬件上的隔絕.一個 Zone 可以是一個硬盤、一台主機、一個機櫃或一個交換機,我們可以簡單理解為一個 Zone 代表了一組獨立的存儲節點.
- Storage Node:存儲對象數據的物理節點,基於通用標准的硬件設備提供了不低於專業存儲設備水平的對象存儲服務.
- Device: 可以簡單理解為磁盤
- Partition: 這里的 Partition 僅僅是指在 Device 上的文件系統中的目錄,和我們通常所理解的硬盤分區是完全不同的概念.
2.1. Swift 對象組織結構
每個 Storage Node 上存儲的對象在邏輯上又由3 個層次組成:Account、Container 及 Object.Swift 對象組織結構如下圖所示
這里每一層包含的節點數都沒有限制,Account 在對象的存儲過程實現頂層的隔離,代表的並不是個人賬戶,而是租戶,一個 Account 可以被多個個人賬戶共同使用;Container 代表了 一組對象的封裝,類似文件夾或目錄,但是 Container 不能嵌套;Object 視具體的對象,由元數據和內容兩部分組成.Swift 要求一個對象必須存儲在某個 Container 中,因此一個 Account 至少有一個 Container 來提供對象的存儲.
與上述的 3 層組織結構相對應,Storage Node 上運行了 3 中服務.
- Account Server:提供 Account 相關服務,包括 Container 列表及 Account 的元數據等.Account 的信息被存儲在一個 SQLite 數據庫中.
- Container Server: 提供 Container 相關服務,包括 Ojbect 的列表及 Container 的元數據等.與 Account 一樣,Container 的信息也被存儲在一個 SQLite 數據庫中.
- Object Server: 提供對象的存取和元數據服務,每個對象的內容會以二進制文件的形式存儲在文件系統中,元數據會作為文件的擴展屬性來存儲,也就是說,存儲對象的物理節點上,本地文件系統必須支持文件的擴展屬性,有些文件系統(如ext3)的文件擴展屬性默認是關閉的.
2.2. 冗余策略
為了保證數據在某個存儲硬件損壞的情況下也不會丟失,Swift 為每個對象建立了一定數量的副本(默認為 3),並且每個副本存放在不同的 Zone 中,這樣即使某個 Zone 發生故障,Swift 仍然可以通過其他 Zone 繼續提供服務.
在 Swift 中,副本是以 Partition 為單位的,也就是說,對象的副本其實是通過 Partition 的副本來實現的(類似於 Ceph 中的 PG,可以減少系統復雜度).
2.3 副本一致性
對象保存了多份就需要着重考慮系統的一致性,當對象內容更新的時候副本也必須同時得到更新或總能讀到最新的數據.而且其中一份損壞時必須能迅速復制一份來完整替換.
Swift 通過以下 3 種服務來解決數據一致性的問題.
- Auditor: 通過持續掃描磁盤來檢查 Account、Container 和 Object 的完整性,如果返現數據有損壞的情況,Auditor 就會對文件進行隔離,然后通過 Replicator 從其他節點上獲取對應的副本用已恢復本地數據.
- Updater: 在創建一個 Container 的時候需要對包含該 Container的 Account 的信息進行更新,使得該 Account 數據庫里面的 Container 列表包含這個新創建的 Container.同樣在創建一個新的 Object 的時候,需要對包含該 Object 的 Container 的信息進行更新,使得該 Container 的數據里面的 Object 列表包含這個新創建的 Object.但是當 Account Server 或 Container Server 繁忙的時候,這樣的更新操作並不是在每個節點上都能成功完成.對於那些沒有成功更新的操作,Swift 會使用 Updater 服務繼續處理這些失敗的更新操作.
- Replicator: 負責檢測各個節點上的數據及副本是否一致.當發現不一致時會將過時的副本更新為最新版本,並且負責將標記為刪除的數據真正從物理介質上刪除.
2.4 物理位置選擇 - 環
Swift 引入環的概念來解決如何將對象與真正的物理存儲位置相互映射的問題.環記錄了存儲對象與物理位置之間的映射關系,Account、Container 和 Object 都有自己獨立的環,當 Proxy Server 接收到用戶請求時,會根據所操作的實體(Account、Container 和 Object)尋找對應的環,來確定他們在存儲服務器集群中的具體位置,Account、Container 和 Object 在環中的位置信息,也由 Proxy Server 來進行維護.
環通過 Zone、Device、Partition 和 Replica 的概念來維護映射信息.每個 Partition 的位置由環來維護,並存儲在映射中.環需要在 Swift 部署時使用"swift-ring-builder"工具手動進行構建,之后每次增減存儲節點時,都需要重新平衡環文件中的項目,以保證系統因此而發生前已的文件數量最少.
2.5 Swift 架構
如下圖所示, Proxy Srever 是運行在 Proxy Node上的 WSGI Server,Account Server、Container Server 與 Object Server 是運行在存儲節點上的 WSGI Server,Proxy Server 收到用戶 HTTP 請求后,將請求路由到響應的 Controller(Account Controller、Container Controller 與 Object Controller),Controller 會從對應的環文件中獲取到請求數據所在的存儲節點,然后將這個請求轉發給該節點上的 WSGI Server (Account Server、Container Server 與 Object Server)
3. 環
Swift 通過引入環來實現對物理節點的管理,包括記錄對象與物理存儲位置間的映射,物理節點的添加和刪除等.為了解決普通 hash 算法不能動態添加刪除節點的問題,Swift 也是用一致性 hash 算法來構建環(Ceph 的 CRUSH 和一致性 hash 的思想是相同).
3.1 一致性 hash 算法
在其他文章我們介紹了一致性 hash--一致性 hash 算法及 golang 實現,需要熟悉一致性 hash 算法才能繼續學習本章內容
3.2 環數據結構
Swift 中所謂的環就是基於一致性 hash 算法構造的環,環包括一下 3 中重要的數據結構:
- 設備表: Swift 將所有 Device 進行編號,設備表中的每一項都對應一個 Device,其中記錄了該 Device 的具體位置信息,包括 Device ID,所在的 Region、Zone、IP 地址及端口號,以及用戶為該 Device 定義的權重等.
- 當 Device 的容量大小不一致時,可以通過權重保證 Partition 均勻分布,容量較大的 Device 擁有更大的權重,也能容量那更多的 Partition.例如,一個 1TB 大小的 Device 有 100 的權重而一個 2TB 大小的 Device 將有 200 的權重.
- 設備查詢表(Device Lookup Table):存儲 Partition 的各個副本(默認為 3)與具體 Device 的映射信息.設備查詢表中的每 1 列對應 1 個 Partition,每 1 行對應 Partition 的 1 個副本,每個表格中的信息為設備表中 Device 的編號,根據這個編號,可以在設備表中檢索到該 Device 的具體信息(Device ID、IP 地址及端口號等信息)
- Partition 移位值:表示在 hash 之后將 Object 名字進行二進制位移的位數.
為了減少由於增加、減少借點帶來的數據遷移量,Swift 在對象存儲節點的映射之間增加了 Partition 的概念,使對象到存儲節點的映射 過程,變成了由對象到Partition再到存儲節點的映射過程。Partition的個數一旦確認,在整個運行過程中是不會改變的,所以對象到Partition的 映射是不會發生變化的。在增加或減少節點的情況下,通過改變 Partition到存儲節點的映射過程來完成數據的遷移。
而對象到Partition這層映射是通過哈希算法及二進制位移操作的, Partition到存儲節點的映射是通過設備查詢表完成的。
總結
本文是對 Swift 的簡單介紹,主要介紹了 Swift 的體系架構和環的概念.Swift 是 OpenStack 的對象存儲項目,可以安全高效的存儲對象數據,並且整個系統可以無限的擴展,系統會自動的達到平衡狀態,Swift 提供了類似 Amazon S3 的服務,可以作為網盤類產品的存儲引 擎,也非常適合用於存儲日志文件和作為數據備份倉庫,在OpenStack 中,它可以與鏡像服務Glance相結合,為其存儲鏡像文件。