理解 OpenStack Swift (2):架構、原理及功能 [Architecture, Implementation and Features]


本系列文章着重學習和研究OpenStack Swift,包括環境搭建、原理、架構、監控和性能等。

(1)OpenStack + 三節點Swift 集群+ HAProxy + UCARP 安裝和配置 

(2)原理、架構和性能

(3)監控

1. 架構

1.1 總體架構

Swift 的總體架構非常的清晰和獨立:

# 分層(Tier) 組件(Service) 功能(Function) 特性 部署考量
1 訪問層(Access Tier) Load Balancer 硬件(比如F5)或者軟件(比如HAProxy)負載均衡器,將客戶端的請求按照配置的策略分配到無狀態的 proxy service。    按照實際需求選擇硬件還是軟件LB
2 Proxy Server
  • 提供 REST API 給客戶端
  • 無狀態的 WSGI 服務,由多個 Proxy Server 組成一個集群
  • 將客戶端請求轉給某個存儲節點上的 Account,Container 或者 Object 服務

是 CPU 和網絡帶寬敏感的

  • 分配更多的CPU和網絡帶寬,比如 10GbE 網絡
  • 使用 Memcached 來做 token、account 和 container 數據緩存
  • 和存儲服務分開部署
  • 使用負載均衡器
  • 往往每五個存儲節點使用兩個 proxy server 節點,然后再按比例擴展
  • 將 public network (用於客戶端訪問)和 backend network (用於訪問存儲服務)分開
  • 需要考慮安全性,可以將 SSL Termination 放在 Proxy Server 上
3 存儲層 (Capactity Tier)

Account Server

提供 Account 操作 REST API 是磁盤性能和網絡帶敏感的
  • 對 Account 和 Container 服務使用更好的磁盤,比如 SAS 或者 SSD,來提高性能;
  • 使用 1GbE 或者 10GbE 網絡
  • 需要的話,可以將 replicaiton network 獨立出來
  • 需要的話,可以將 Account 和 Container 服務部署到獨立的服務器上
4 Container Server 提供 Container 操作 REST API
5 Object Server 提供 Object 操作 REST API
 6 Consistency Servers 包括 Replicators, Updaters 和 Auditors 等后台服務,用於保證 object 的一致性

這是一張比較經典的 Swift 物理部署圖:

1.2 網絡架構

以一個對外提供對象存儲服務的集群為例,其網絡架構可以為:

  • 外部流量被放在一個單獨的(上圖中紫色)VLAN 中,終點為 LB
  • 控制(管理)網絡連接所有節點
  • Swift 前端(front end / public)網絡連接 LB 和 所有 Proxy server 節點
  • Swift 后端 (backend / private) 網絡連接所有 Proxy server 節點和 存儲節點
  • 需要的話,還可以從后端網絡中分離出復制(replication)網絡

在網絡帶寬選擇上,

  • 考慮到復制數據的容量較大(往往是幾個TB起步),后端網絡往往是用 10GbE 網絡
  • 根據前端負載,前端網絡可以使用 1GbE 網絡,或者有條件時使用 10GbE 網絡
  • 管理/IPMI網絡往往是用 1GbE 網絡

這是 SwiftStack 的一個例子:

2. 數據存放

2.1 Swift 的數據存放

2.1.1 Swift 的數據模型

Swift 的數據模型使用了以下三個概念來(見下圖1):

  • Account: 賬戶/租戶。Swift 是天生支持多租戶的。如果使用 OpenStack Keystone 做用戶校驗的話,account 與 OpenStack project/tenant 的概念相同。Swift 租戶的隔離性體現在metadata上,而不是體現在 object data 上。數據包括自身元數據 和 container 列表,被保存在 SQLite 數據庫中。
  • Container: 容器,類似於文件系統中的目錄,由用戶自定義,它包含自身的元數據和容器內的對象列表。數據保存在 SQLite 數據庫中。在新版中,Swift 支持在容器內添加文件夾。
  • Object: 對象,包括數據和數據的元數據,以文件形式保存在文件系統上。

     

 (圖1)                                                     (圖2)

 

  • Containers 是用戶創建的,用來 hold objects。
  • objects 可以是 0 bytes 長度,或者包含數據。
  • container 中的 object 最大大小為 5GB;超過的話,會做特殊處理
  • 每個 object 使用它的 name 來被 referenced;Swift 沒有目錄概念
  • 在 object name 中可以使用任意的可以被 ‘URL-encoded’ 的 字符,最大長度為 URL - coded 之后 1034 個字符
  • object name 中可以帶 '/' 字符,它會帶來目錄結構的幻覺(illusion),比如 dir/dir2/name。即使看起來象個目錄,但是它仍然只是一個 object name。此時,不需要 dir 或者 dir/dir2 container 的存在。
  • 如果一個 container 所有 objects 的大小為0,那么它將看起來象一個目錄。
  • 客戶端使用 HTTP 或者 HTTPS 訪問 Swift,包括讀、寫、刪除 objects。也支持 COPY 操作,它會創建一個新的 object,使用一個新的 object name,包含老 object 的 data。沒有 rename 操作,它會首先 copy 出一個新的,然后再將老的刪除。

2.1.2 選擇數據存放位置

  Swift 保存每個對象為多分拷貝,它按照物理位置的特點,盡量將這些拷貝放在不同的物理位置上,來保證數據的地理位置上的可靠性。它主要考慮以下幾種位置屬性:

  • Region:地理位置上的區域,比如不同城市甚至不同國家的機房,這主要是從災備方面考慮的。
  • Zone:一個數據中心根據物理網絡、供電、空調等基礎設施分開的獨立的域,往往將一個機架(Rack)內的服務器分在一個 Zone 內。
  • Node (節點):物理服務器
  • Disk (磁盤):物理服務器上的磁盤

Swift 在確定對象的放置位置時,會盡量將對象及其拷貝放在不會同時損失的物理位置上。見上圖2.

2.1.3 保證數據一致性

    對象及其拷貝放置在某個磁盤上后,Swift 會使用Replicators, Updaters 和 Auditors 等后台服務來保證其數據的最終一致性。

  • Replicator – 拷貝對象,確保系統的最終一致性(Replicate objects and make a system in a consistent state);恢復磁盤和網絡錯誤(Recover disk failure, network outages situation)
  • Updater – 更新元數據(Update metadata),從容器和賬戶元數據高負載導致的問題上恢復(Recover failure caused by container, account metadata high load)
  • Auditor – 刪除問題賬戶,容器和對象,然后從別的服務器上拷貝過來(Delete problematic account, container or objects and replicate from other server);恢復數據庫和文件數據錯誤(Recover dbs or files which have bit rot problem.

其中,Replicator 服務以可配置的間隔來周期性啟動,默認是 30s,它以 replication 為最小單位,以 node 為范圍,周期性地執行數據拷貝。詳細過程請參考文末的參考文檔。考慮到Swift 實現的是最終一致性而非強一致性,它不合適於需要數據強一致性的應用,比如銀行存款和訂票系統等。需要做 replication 的情形包括但不限於:

  • Proxy server 在寫入第三份時失敗,它依然會向客戶端返回成功,后台服務會寫第三份拷貝
  • 后台進程發現某個replication 數據出現損壞,它會在新的位置重新寫入
  • 在跨 Region 的情況下,Proxy server 只會向它所在 Region 的存儲上寫入,遠處 region 上的數據由后台進程復雜寫入
  • 在更換磁盤或者添加磁盤的情況下,數據需要重新平衡時

2.2 Swift  是如何實現這些需求的:使用 Ring + 哈希算法

    Swift 根據由管理員配置的 Ring 使用相對簡單直接的算法來確定對象的存放位置。對象會以文件的形式保存在本地文件系統中,使用文件的擴展屬性來保存對象的元數據,因此,Swift 需要支持擴展屬性的文件系統,目前官方推薦是 XFS。

2.2.1 Ring 的內容和算法

    簡單來說,Swift 的 Proxy Server 根據account,container 和 object 各自的 Ring 來確定各自數據的存放位置,其中 account 和 container 數據庫文件也是被當作對象來處理的。

因此,Swift 需要 Ring 的配置文件分布在所有 Proxy節點上。同時,Consistency Servers 需要它來確定后台對象拷貝的位置,因此也需要部署在所有存儲節點上。Ring 以文件的形式保存:

  • object.ring.gz
  • container.ring.gz
  • account.ring.gz

在分析 Ring 是如何工作的之前,先來看看 Ring 的幾個關鍵配置:

  • Region,zone 和 disk:前面說過了,略過
  • partition:Swift 再將每個磁盤分成若干 partition (分區)。這是后端一致性檢查服務處理拷貝(replication)的基本單位。
  • Replica:對象和拷貝的總份數,常規推薦值是 3。

管理員使用 Swift 提供的 ring 生成工具(swift-ring-builder,位於源碼的bin目錄下,是swift最基本的命令,它與swift/common/ring/下的文件一起實現ring文件創建,添加,平衡,等操作),加上各種配置參數,得出該ring的內容。以 Object ring 為例,

root@swift1:/etc/swift# swift-ring-builder object.builder
object.builder, build version 6
1024 partitions, 3.000000 replicas, 1 regions, 3 zones, 6 devices, 0.00 balance, 0.00 dispersion
The minimum number of hours before a partition can be reassigned is 1
The overload factor is 0.00% (0.000000)
Devices:    id  region  zone      ip address  port  replication ip  replication port      name weight partitions balance meta
             0       1     1   9.115.251.235  6000   9.115.251.235              6000      sdb1 100.00        512    0.00
             1       1     1   9.115.251.235  6000   9.115.251.235              6000      sdc1 100.00        512    0.00
             2       1     2   9.115.251.234  6000   9.115.251.234              6000      sdb1 100.00        512    0.00
             3       1     2   9.115.251.234  6000   9.115.251.234              6000      sdc1 100.00        512    0.00
             4       1     3   9.115.251.233  6000   9.115.251.233              6000      sdb1 100.00        512    0.00
             5       1     3   9.115.251.233  6000   9.115.251.233              6000      sdc1 100.00        512    0.00

該 Ring 的配置為:1 個 region,3 個 zone,3 個 node,6 個磁盤,每個磁盤上 512 個分區。

內部實現上,Swift 將該 Ring 的配置保存在其 _replica2part2dev 數據結構中:

其讀法是:

  • 行:將集群所有的分區都順序編號,每個分區有唯一的一個ID
  • 列:包含 Ring 中的 id,該 id 唯一確定了一個 disk;和 replica 的編號。

因此,Swift 通過該數據結構可以方便地查到某個 replica 應該通過哪些節點上的存儲服務放在哪個 disk 上。

除了生成 Ring 外,對 Ring 的另一個重要操作是 rebalance(再平衡)。在你修改builder文件后(例如增減設備),該操作會重新生成ring文件,使系統中的partition分布平衡。當然,在 rebalance 后,需要重新啟動系統的各個服務。 詳情可以參考 OpenStack Swift源碼分析(二)ring文件的生成

2.2.2 數據放置和讀取過程

當收到一個需要保存的 object 的 PUT 請求時,Proxy server 會:

  1. 根據其完整的對象路徑(/account[/container[/object]])計算其哈希值,哈希值的長度取決於集群中分區的總數。
  2. 將哈希值的開頭 N 個字符映射為數目同 replica 值的若干 partition ID。
  3. 根據 partition ID 確定某個數據服務的 IP 和 port。
  4. 依次嘗試連接這些服務的端口。如果有一半的服務無法連接,則拒絕該請求。
  5. 嘗試創建對象,存儲服務會將對象以文件形式保存到某個磁盤上。(Object server 在完成文件存儲后會異步地調用 container service 去更新container數據庫)
  6. 在3份拷貝中有兩份被成功寫入后, Proxy Server 就會向客戶端返回成功。

 

當 Proxy server 收到一個獲取對象的 GET 請求時,它:

(1)(2)(3)(4)同前面的 PUT 請求,確定存放所有 replica 的 所有磁盤

(5)排序這些 nodes,嘗試連接第一個,如果成功,則將二進制數據返回客戶端;如果不成功,則嘗試下一個。直到成功或者都失敗。

應該說該過程蠻簡單直接,這也符合Swift的總體設計風格。至於具體的哈希算法實現,有興趣可以看相關論文。大致來說,它實現的是 “unique-as-possible” 即 “盡量唯一” 的算法,按照 Zone,Node 和 Disk 的順序。對於一個 replica,Swift 首先會去選擇一個沒有該對象 replica 的 zone,如果沒有這樣的 zone,選擇一個已使用 zone 中的沒用過的 node,如果沒有這樣的 node,就選擇已使用的 node 上的一個沒使用過的 disk。

2.2.3 Hash 計算和對象位置查找

(1)存放的目錄取決於哈希值

這里也表明,對象的存放目錄和其名稱是直接關聯的。因此,在Swift中的,對對象重命名,意味着對象位置的修改,該過程會產生數據拷貝,而且在很多時候是需要跨節點的遠程拷貝。在某些應用中,比如 Hadoop 大數據應用,如果采用 Swift 作為存儲,在其mapreduce 過程中,是會產生文件 rename 操作的,這在 Swift 中會帶來嚴重的性能下降。

(2)獲取某對象的存放路徑

root@swift1:~/s1# swift-get-nodes /etc/swift/object.ring.gz AUTH_dea8b51d28bf41599e63464828102759/container1/1

Account         AUTH_dea8b51d28bf41599e63464828102759
Container       container1
Object          1
Partition       277
Hash            456a95e2e66aad55d72756c6b0cd3b75

Server:Port Device      9.115.251.235:6000 sdb1
Server:Port Device      9.115.251.234:6000 sdc1
Server:Port Device      9.115.251.233:6000 sdc1

curl -I -XHEAD "http://9.115.251.235:6000/sdb1/277/AUTH_dea8b51d28bf41599e63464828102759/container1/1"
curl -I -XHEAD "http://9.115.251.234:6000/sdc1/277/AUTH_dea8b51d28bf41599e63464828102759/container1/1"
curl -I -XHEAD "http://9.115.251.233:6000/sdc1/277/AUTH_dea8b51d28bf41599e63464828102759/container1/1"

(3)遠程登錄后者 ssh 后可以看到保存對象的文件

root@swift1:~/s1# ls /srv/node/sdb1/objects/277/b75/456a95e2e66aad55d72756c6b0cd3b75 -l
total 8
-rw------- 1 swift swift 12 Nov  8 17:17 1447003035.84393.dataroot@swift1:~/s1# cat /srv/node/sdb1/objects/277/b75/456a95e2e66aad55d72756c6b0cd3b75/1447003035.84393.data
222222222222

2.2.4 對象分段

  Swift 對於小的文件,是不分段直接存放的;對於大的文件(大小閾值可以配置,默認是 5G),系統會自動將其分段存放。用戶也可以指定分段的大小來存放文件。比如對於 590M 的文件,設置分段大小為 100M,則會被分為 6 段被並行的(in parallel)上傳到集群之中:

root@controller:~/s1# swift upload container1 -S 100000000 tmpubuntu
tmpubuntu segment 5
tmpubuntu segment 2
tmpubuntu segment 4
tmpubuntu segment 1
tmpubuntu segment 3
tmpubuntu segment 0
tmpubuntu
root@controller:~/s1# swift list container1
1
admin-openrc.sh
cirros-0.3.4-x86_64-disk.raw
tmpubuntu

從 stat 中可以看出它使用一個 manifest 文件來保存分段信息:

root@controller:~/s1# swift stat container1 tmpubuntu
       Account: AUTH_dea8b51d28bf41599e63464828102759
     Container: container1
        Object: tmpubuntu
  Content Type: application/octet-stream
Content Length: 591396864
 Last Modified: Fri, 13 Nov 2015 18:31:53 GMT
          ETag: "fa561512dcd31b21841fbc9dbace118f"
      Manifest: container1_segments/tmpubuntu/1446907333.484258/591396864/100000000/
    Meta Mtime: 1446907333.484258
 Accept-Ranges: bytes
    Connection: keep-alive
   X-Timestamp: 1447439512.09744
    X-Trans-Id: txae548b4b35184c71aa396-0056462d72

但是 list 的時候依然只看到一個文件,原因是因為 manifest 文件被保存到一個獨立的 container (container1_segments)中。這里可以看到 6 個對象:

root@controller:~/s1# swift list container1_segments
tmpubuntu/1446907333.484258/591396864/100000000/00000000
tmpubuntu/1446907333.484258/591396864/100000000/00000001
tmpubuntu/1446907333.484258/591396864/100000000/00000002
tmpubuntu/1446907333.484258/591396864/100000000/00000003
tmpubuntu/1446907333.484258/591396864/100000000/00000004
tmpubuntu/1446907333.484258/591396864/100000000/00000005

每個對象大小是100M(考慮到存儲效率,不建議每個對象大小小於100M):

root@controller:~/s1# swift stat container1_segments tmpubuntu/1446907333.484258/591396864/100000000/00000000
       Account: AUTH_dea8b51d28bf41599e63464828102759
     Container: container1_segments
        Object: tmpubuntu/1446907333.484258/591396864/100000000/00000000
  Content Type: application/octet-stream
Content Length: 100000000

而且用戶可以單獨操作比如修改某一段。Swift 只會負責將所有段連接為用戶所見的大的對象。

關於大文件支持的更多細節,可以參考 官方文檔 和 Rackspace 的文檔。從上面的描述可以看出,Swift 對文件分段的支持是比較初級的(固定,不靈活),因此,已經有人提出 Object stripping (對象條帶化)方案,比如下面的方案,不知道是否已經支持還是將要支持。

2.3 Region

    通過將對象存放在不同物理位置上的 Region 內,可以進一步增強數據的可用性。其基本原則是:對於 N 份 replica 和 M 個 region,每個 region 中的 replica 數目為 N/M 的整數,剩余的 replica 在 M 個region 中隨機選擇。以 N = 3, M = 2 為例,一個 region 中有 1 個 replica,另一個 region 中有兩個 replica,如下圖所示:

對於一個 PUT 操作來說,Proxy server 只會將 replica 寫入它所在的 region 中的 node,遠端 region 中的 replica 由 replicator 寫入。因此,Swift 的算法應該盡量保證 proxy server 所在的 region 中的 replica 份數相對多一些,這也稱為 replica 的 proxy server 親和性。

顯然,跨 region 的數據復制加重了對網絡帶寬的要求。

兩種形式的 Region:

(1)遠端 region 實時寫入 replica

(2)遠端 region 的 replica 異步寫入

2.4 Storage Polices (存儲策略)

    上面的描述中,一個Swift 集群只支持一套 Ring 配置,這意味着整個機器的配置是唯一的。類似 Ceph 中 pool 的定義,Swift 在 2.0 版本(包含在 OpenStack Juno 版本中)中,添加了一個非常大的功能:Storage policy。在新的實現中,一個 Swift 可以由多套 Ring 配置,每套 Ring 的配置可以不相同。比如,Ring 1 保存 3 份對象拷貝,Ring 2 保存 2 份對象拷貝。幾個特點:

  • Policy 被實現在 container 級別
  • 創建 container 時可以指定 policy。一旦被指定,不可以修改。
  • 一個 policy 可以被多個 container 共享使用

    通過應用該新的功能,Swift 用戶可以制定不同的存儲策略,來適應不同應用的存儲需求。比如對關鍵應用的數據,制定一個存儲策略使得數據被保存到 SSD 上;對於一般關鍵性的數據,指定存儲策略使得數據只保存2份來節約磁盤空間。比如說:

詳細信息,請參考 OpenStack 官方文檔 和 SwiftStack 官方文檔

3. 版本及主要功能

3.1 Juno以及之前主要版本和功能

 

(1)Large object support

(2)Static web hosting

(3) S3 compatible API

(4) Object expiration

(5) Temp url

(6) Global cluster

(7) Storage policy

3.2 Kilo 版本中的更新

新功能

糾刪碼(beta)

Swift現在支持糾刪碼(EC)存儲策略類型。這樣部署人員、以極少的RAW容量達到極高的可用性,如同在副本存儲中一樣。然而,EC需要更多的CPU和網絡資源,所以並不適合所有應用場景。EC非常適合在一個獨立的區域內極少訪問的、大容量數據。

Swift糾刪碼的實現對於用戶是透明的。對於副本存儲和糾刪碼存儲的類型,在API上沒有任何區別。

為了支持糾刪碼,Swift現在需要依賴PyECLib和liberasurecode。liberasurecode是一個可插件式的庫,允許在你選擇的庫中實現EC算法。

更詳細文檔請參閱 http://swift.openstack.org/overview_erasure_code.html

復合型令牌(Composite tokens)

復合型令牌允許其他OpenStack服務以客戶端名義將數據存儲於Swift中,所以無論是客戶端還是服務在更新數據時,都不需要雙方彼此的授權。

一個典型的例子就是一個用戶請求Nova存放一個VM的快照。Nova將請求傳遞給Glance,Glance將鏡像寫入Swift容器中的一組對象中。在這種場景下,用戶沒有來自服務的合法令牌時,無法直接修改快照數據。同樣,服務自身也無法在沒有用戶合法令牌的情況下更新數據。但是數據的確存在於用戶的Swift賬戶中,這樣使得賬戶管理更簡單。

更詳細的文檔請參閱http://swift.openstack.org/overview_backing_store.html

更小規模、不平衡集群的數據位置更新

Swift數據的存放位置現在根據硬件權重決定。當前,允許運維人員逐漸的添加新的區域(zones)和地域(regions),而不需要立即觸發大規模數據遷移。同時,如果一個集群是非平衡的(例如,在一個區域(zones)的集群中,其中一個的容量是另外一的兩倍),Swift會更有效的使用現有空間並且當副本在集群空間不足時發出警告。

全局性集群復制優化

區域(regions)之間復制時,每次復制只遷移一個副本。這樣遠程的區域(region)可以在內部復制,避免更多的數據在廣域網(WAN)拷貝。

已知問題

  • 作為beta更新,糾刪碼(EC)的功能接近完成,但是對於某些功能仍然不完整(像多范圍(multi-range)讀取),並且沒有一個完整的性能測算。這個功能為了持久性依賴於ssync。部署人員督促我們做更大規模的測試,並且不要在生產環境部署中使用糾刪碼存儲策略。

升級提示

像往常一樣,你能在不影響最終用戶體驗的前提下,升級到這個版本的Swift。

  • 為了支持糾刪碼,Swift需要一個新的依賴PyECLib(和liberasurecode等)。並且eventlet的最低版本要求也升高了。

3.3 Liberty 版本中的更新

L版本中Swift 沒有加入大的新功能,詳細情況可以參考 官方文檔

3.4 優勢

 

 

其它參考文檔:

http://www.florentflament.com/blog/openstack-swift-ring-made-understandable.html

https://www.mirantis.com/blog/configuring-multi-region-cluster-openstack-swift/

OpenStack Swift源碼分析

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM