本系列文章着重學習和研究OpenStack Swift,包括環境搭建、原理、架構、監控和性能等。html
(1)OpenStack + 三節點Swift 集羣+ HAProxy + UCARP 安裝和配置 前端
(2)原理、架構和性能node
(3)監控git
Swift 的整體架構很是的清晰和獨立:github
# | 分層(Tier) | 組件(Service) | 功能(Function) | 特性 | 部署考量 |
1 | 訪問層(Access Tier) | Load Balancer | 硬件(好比F5)或者軟件(好比HAProxy)負載均衡器,將客戶端的請求按照配置的策略分配到無狀態的 proxy service。 | 按照實際需求選擇硬件仍是軟件LB | |
2 | Proxy Server |
|
是 CPU 和網絡帶寬敏感的web |
|
|
3 | 存儲層 (Capactity Tier) | Account Server算法 |
提供 Account 操做 REST API | 是磁盤性能和網絡帶敏感的 |
|
4 | Container Server | 提供 Container 操做 REST API | |||
5 | Object Server | 提供 Object 操做 REST API | |||
6 | Consistency Servers | 包括 Replicators, Updaters 和 Auditors 等後臺服務,用於保證 object 的一致性 |
這是一張比較經典的 Swift 物理部署圖:數據庫
以一個對外提供對象存儲服務的集羣爲例,其網絡架構能夠爲:ubuntu
在網絡帶寬選擇上,swift
這是 SwiftStack 的一個例子:
Swift 的數據模型使用瞭如下三個概念來(見下圖1):
(圖1) (圖2)
Swift 保存每一個對象爲多分拷貝,它按照物理位置的特色,儘可能將這些拷貝放在不一樣的物理位置上,來保證數據的地理位置上的可靠性。它主要考慮如下幾種位置屬性:
Swift 在肯定對象的放置位置時,會盡可能將對象及其拷貝放在不會同時損失的物理位置上。見上圖2.
對象及其拷貝放置在某個磁盤上後,Swift 會使用Replicators, Updaters 和 Auditors 等後臺服務來保證其數據的最終一致性。
其中,Replicator 服務以可配置的間隔來週期性啓動,默認是 30s,它以 replication 爲最小單位,以 node 爲範圍,週期性地執行數據拷貝。詳細過程請參考文末的參考文檔。考慮到Swift 實現的是最終一致性而非強一致性,它不合適於須要數據強一致性的應用,好比銀行存款和訂票系統等。須要作 replication 的情形包括但不限於:
Swift 根據由管理員配置的 Ring 使用相對簡單直接的算法來肯定對象的存放位置。對象會以文件的形式保存在本地文件系統中,使用文件的擴展屬性來保存對象的元數據,所以,Swift 須要支持擴展屬性的文件系統,目前官方推薦是 XFS。
簡單來講,Swift 的 Proxy Server 根據account,container 和 object 各自的 Ring 來肯定各自數據的存放位置,其中 account 和 container 數據庫文件也是被看成對象來處理的。
所以,Swift 須要 Ring 的配置文件分佈在全部 Proxy節點上。同時,Consistency Servers 須要它來肯定後臺對象拷貝的位置,所以也須要部署在全部存儲節點上。Ring 以文件的形式保存:
在分析 Ring 是如何工做的以前,先來看看 Ring 的幾個關鍵配置:
管理員使用 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
數據結構中:
其讀法是:
所以,Swift 經過該數據結構能夠方便地查到某個 replica 應該經過哪些節點上的存儲服務放在哪一個 disk 上。
除了生成 Ring 外,對 Ring 的另外一個重要操做是 rebalance(再平衡)。在你修改builder文件後(例如增減設備),該操做會從新生成ring文件,使系統中的partition分佈平衡。固然,在 rebalance 後,須要從新啓動系統的各個服務。 詳情能夠參考 OpenStack Swift源碼分析(二)ring文件的生成。
當收到一個須要保存的 object 的 PUT 請求時,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。
(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
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 (對象條帶化)方案,好比下面的方案,不知道是否已經支持仍是將要支持。
經過將對象存放在不一樣物理位置上的 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 異步寫入
上面的描述中,一個Swift 集羣只支持一套 Ring 配置,這意味着整個機器的配置是惟一的。相似 Ceph 中 pool 的定義,Swift 在 2.0 版本(包含在 OpenStack Juno 版本中)中,添加了一個很是大的功能:Storage policy。在新的實現中,一個 Swift 能夠由多套 Ring 配置,每套 Ring 的配置能夠不相同。好比,Ring 1 保存 3 份對象拷貝,Ring 2 保存 2 份對象拷貝。幾個特色:
經過應用該新的功能,Swift 用戶能夠制定不一樣的存儲策略,來適應不一樣應用的存儲需求。好比對關鍵應用的數據,制定一個存儲策略使得數據被保存到 SSD 上;對於通常關鍵性的數據,指定存儲策略使得數據只保存2份來節約磁盤空間。好比說:
詳細信息,請參考 OpenStack 官方文檔 和 SwiftStack 官方文檔。
(1)Large object support
(2)Static web hosting
(3) S3 compatible API
(4) Object expiration
(5) Temp url
(6) Global cluster
(7) Storage policy
Swift如今支持糾刪碼(EC)存儲策略類型。這樣部署人員、以極少的RAW容量達到極高的可用性,如同在副本存儲中同樣。然而,EC須要更多的CPU和網絡資源,因此並不適合全部應用場景。EC很是適合在一個獨立的區域內極少訪問的、大容量數據。
Swift糾刪碼的實現對於用戶是透明的。對於副本存儲和糾刪碼存儲的類型,在API上沒有任何區別。
爲了支持糾刪碼,Swift如今須要依賴PyECLib和liberasurecode。liberasurecode是一個可插件式的庫,容許在你選擇的庫中實現EC算法。
更詳細文檔請參閱 http://swift.openstack.org/overview_erasure_code.html
複合型令牌容許其餘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)拷貝。
像往常同樣,你能在不影響最終用戶體驗的前提下,升級到這個版本的Swift。
L版本中Swift 沒有加入大的新功能,詳細狀況能夠參考 官方文檔。
其它參考文檔:
http://www.florentflament.com/blog/openstack-swift-ring-made-understandable.html
https://www.mirantis.com/blog/configuring-multi-region-cluster-openstack-swift/