【转载】OpenStack Swift学习笔记
免責聲明:
??? 本文轉自網絡文章,轉載此文章僅為個人收藏,分享知識,如有侵權,請聯系博主進行刪除。
??? 原文作者:崔炳華?
??? 原文地址:http://blog.csdn.net/i_chips/article/details/17787017
1?????? 概述
OpenStack Object Storage(Swift)是OpenStack開源云計算項目的子項目之一。Swift的目的是使用普通硬件來構建冗余的、可擴展的分布式對象存儲集群,存儲容量可達PB級。
Swift并不是文件系統或者實時的數據存儲系統,它是對象存儲,用于永久類型的靜態數據的長期存儲,這些數據可以檢索、調整,必要時進行更新。最適合存儲的數據類型的例子是虛擬機鏡像、圖片存儲、郵件存儲和存檔備份。
Swift無需采用RAID(磁盤冗余陣列),也沒有中心單元或主控結點。Swift通過在軟件層面引入一致性哈希技術和數據冗余性,犧牲一定程度的數據一致性來達到高可用性(High Availability,簡稱HA)和可伸縮性,支持多租戶模式、容器和對象讀寫操作,適合解決互聯網的應用場景下非結構化數據存儲問題。
2?????? 技術特性
2.1??????? Swift的主要特征
Swift的主要特性如下:
- 極高的數據持久性(Durability)。
- 完全對稱的系統架構:“對稱”意味著Swift中各節點可以完全對等,能極大地降低系統維護成本。
- 無限的可擴展性:一是數據存儲容量無限可擴展;二是Swift性能(如QPS、吞吐量等)可線性提升。
- 無單點故障:Swift的元數據存儲是完全均勻隨機分布的,并且與對象文件存儲一樣,元數據也會存儲多份。整個Swift集群中,也沒有一個角色是單點的,并且在架構和設計上保證無單點業務是有效的。
- 簡單、可依賴。
2.2??????? Swift和HDFS的技術差異
Swift和Hadoop分布式文件系統(HDFS)都有著相似的目的:實現冗余、快速、聯網的存儲,它們的技術差異如下:
- 在Swift中,元數據呈分布式,跨集群復制。而在HDFS使用了中央系統來維護文件元數據(Namenode,名稱節點),這對HDFS來說無異于單一故障點,因而擴展到規模非常大的環境顯得更困難。
- Swift在設計時考慮到了多租戶架構,而HDFS沒有多租戶架構這個概念。
- 在Swift中,文件可以寫入多次;在并發操作環境下,以最近一次操作為準。而在HDFS中,文件寫入一次,而且每次只能有一個文件寫入。
- Swift用Python來編寫,而HDFS用Java來編寫。
- Swift被設計成了一種比較通用的存儲解決方案,能夠可靠地存儲數量非常多的大小不一的文件;而HDFS被設計成可以存儲數量中等的大文件(HDFS針對更龐大的文件作了優化),以支持數據處理。
3?????? 關鍵技術
3.1??????? 一致性哈希(ConsistentHashing)
在分布式對象存儲中,一個關鍵問題是數據該如何存放。Swift是基于一致性哈希技術,通過計算可將對象均勻分布到虛擬空間的虛擬節點上,在增加或刪除節點時可大大減少需移動的數據量;虛擬空間大小通常采用2的n次冪,便于進行高效的移位操作;然后通過獨特的數據結構 Ring(環)再將虛擬節點映射到實際的物理存儲設備上,完成尋址過程。
圖1 一致性哈希環結構
衡量一致性哈希的4個指標:
- 平衡性(Balance):平衡性是指Hash的結果能夠盡可能分布均勻,充分利用所有緩存空間。
- 單調性(Monotonicity):單調性是指如果已經有一些內容通過哈希分派到了相應的緩沖中,又有新的緩沖加入到系統中。哈希的結果應能夠保證原有已分配的內容可以被映射到新的緩沖中去,而不會被映射到舊的緩沖集合中的其他緩沖區。
- 分散性(Spread):分散性定義了分布式環境中,不同終端通過Hash過程將內容映射至緩存上時,因可見緩存不同,Hash結果不一致,相同的內容被映射至不同的緩沖區。
- 負載(Load):負載是對分散性要求的另一個緯度。既然不同的終端可以將相同的內容映射到不同的緩沖區中,那么對于一個特定的緩沖區而言,也可能被不同的用戶映射為不同的內容。
Swift使用該算法的主要目的是在改變集群的node數量時(增加/刪除服務器),能夠盡可能少地改變已存在key和node的映射關系,以滿足單調性。
考慮到哈希算法在node較少的情況下,改變node數會帶來巨大的數據遷移。為了解決這種情況,一致性哈希引入了“虛擬節點”(vnode,也稱為partition)的概念: “虛擬節點”是實際節點在環形空間的復制品,一個實際節點對應了若干個“虛擬節點”,“虛擬節點”在哈??臻g中以哈希值排列。
總的來說,Swift中存在兩種映射關系,對于一個文件,通過哈希算法(MD5)找到對應的虛節點(一對一的映射關系),虛節點再通過映射關系(ring文件中二維數組)找到對應的設備(多對多的映射關系),這樣就完成了一個文件存儲在設備上的映射。
圖2 對象、虛結點、節點間的映射關系
在設置虛結點數的時候,需要對系統預期的規模做充分考慮,假如集群的規模不會超過6000個結點,那么可以將虛結點數設置為結點數的100倍。這樣,變動任意一個結點的負載僅影響1%的數據項。此時有6百萬個vnode數,使用2bytes來存儲結點數(0~65535)?;镜膬却嬲加檬?*(10^6)*2bytes=12Mb,對于服務器來說完全可以承受。
假設有65536(2^16)個node,有128(2^7)倍的partition數(2^23,則PARTITION_POWER=23)。由于MD5碼是32位的,使用PARTITION_SHIFT(等于32- PARTITION_POWER)將數據項的MD5哈希值映射到partition的2^23的空間中。
3.2??????? 數據一致性模型(ConsistencyModel)
按照Eric Brewer的CAP(Consistency,Availability,PartitionTolerance)理論,無法同時滿足3個方面,Swift放棄嚴格一致性(滿足ACID事務級別),而采用最終一致性模型(Eventual Consistency),來達到高可用性和無限水平擴展能力。
為了實現這一目標,Swift采用Quorum仲裁協議(Quorum有法定投票人數的含義):
- 定義:N:數據的副本總數;W:寫操作被確認接受的副本數量;R:讀操作的副本數量。
- 強一致性:R+W>N,以保證對副本的讀寫操作會產生交集,從而保證可以讀取到最新版本;如果 W=N,R=1,則需要全部更新,適合大量讀少量寫操作場景下的強一致性;如果 R=N,W=1,則只更新一個副本,通過讀取全部副本來得到最新版本,適合大量寫少量讀場景下的強一致性。
- 弱一致性:R+W<=N,如果讀寫操作的副本集合不產生交集,就可能會讀到臟數據;適合對一致性要求比較低的場景。
Swift針對的是讀寫都比較頻繁的場景,所以采用了比較折中的策略,即寫操作需要滿足至少一半以上成功W>N/2,再保證讀操作與寫操作的副本集合至少產生一個交集,即R+W>N。
在分布式系統中,數據的單點是不允許存在的。線上正常存在的replica數量是1的話將非常危險的,因為一旦這個replica再次錯誤,就可能發生數據的永久性錯誤。假如我們把N設置成為2,那么,只要有一個存儲節點發生損壞,就會有單點的存在。所以N必須大于2。但N越高,系統的維護和整體成本就越高。所以,工業界通常把N設置為3。
Swift默認配置是N=3,W=2>N/2,R=1或2,即每個對象會存在3個副本,這些副本會被盡量存儲在不同區域的節點上;W=2表示至少需要更新2個副本才算寫成功。
當R=1時,意味著某一個讀操作成功便立刻返回,此種情況下可能會讀取到舊版本(弱一致性模型)。
當R=2時,需要通過在讀操作請求頭中增加x-newest=true參數來同時讀取2個副本的元數據信息,然后比較時間戳來確定哪個是最新版本(強一致性模型)。
如果數據出現了不一致,后臺服務進程會在一定時間窗口內通過檢測和復制協議來完成數據同步,從而保證達到最終一致性。
圖3 Quorum協議示例
3.3??????? 環(Ring)
Ring是Swift中最重要的組件,用于記錄存儲對象與物理位置間的映射關系。在涉及查詢Account、Container、Object信息時就需要查詢集群的Ring信息。
環是為了將虛擬節點(partition,分區)均衡地映射到一組物理存儲設備上,并提供一定的冗余度而設計的,其數據結構由以下信息組成:
存儲設備列表、設備信息包括唯一標識號(id)、區域號(zone)、權重(weight)、IP 地址(ip)、端口(port)、設備名稱(device)、元數據(meta)。
Swift為賬戶、容器和對象分別定義了的Ring,其查找過程是相同的。Ring中每個partition在集群中都默認有3個replica。每個partition的位置由ring來維護,并存儲在映射中。
Ring使用zone來保證數據的物理隔離。每個partition的replica都確保放在了不同的zone中。Zone只是個抽象概念,它可以是一個磁盤(disk drive),一個服務器(server),一個機架(cabinet),一個交換機(switch),甚至是一個數據中心(datacenter),以提供最高級別的冗余性,建議至少部署5個zone。
權重參數是個相對值,可以來根據磁盤的大小來調節,權重越大表示可分配的空間越多,可部署更多的分區。
當集群中發生存儲節點宕機、新增(刪)存儲節點、新增(刪)zone等必須改變partition和node間的映射關系時,還可以對Ring文件通過重新平衡(rebalance)來進行更新。當虛節點需要移動時,環會確保一次移動最少數量的虛節點數,并且一次只移動一個虛節點的一個副本。
總的來說,Ring引入一致性哈希的原因是為了減少由于增加結點導致數據項移動的數量來提高單調性;引入partition的原因是為了減少由于節點數過少導致移動過多的數據項;引入replica的原因是防止數據單點、提高冗余性;引入zone的原因是為了保證分區容忍性;引入weight的原因是為了保證partition分配的均衡。
4?????? 架構設計
4.1??????? Swift數據模型
Swift采用層次數據模型,共設三層邏輯結構:Account/Container/Object(賬戶/容器/對象)。每層節點數均沒有限制,可以任意擴展。這里的賬戶和個人賬戶不是一個概念,可理解為租戶,用來做頂層的隔離機制,可以被多個個人賬戶所共同使用;容器類似文件夾,代表封裝一組對象;對象由元數據和數據兩部分組成。
4.2??????? Swift系統架構
Swift采用完全對稱、面向資源的分布式系統架構設計,所有組件都可擴展,避免因單點失效而擴散并影響整個系統運轉;通信方式采用非阻塞式 I/O 模式,提高了系統吞吐和響應能力。
Swift組件包括:
- 代理服務(ProxyServer):Swift通過Proxy Server向外提供基于HTTP的REST服務接口,會根據環的信息來查找服務地址并轉發用戶請求至相應的賬戶、容器或者對象,進行CRUD(增刪改查)等操作。由于采用無狀態的REST請求協議,可以進行橫向擴展來均衡負載。在訪問Swift服務之前,需要先通過認證服務獲取訪問令牌,然后在發送的請求中加入頭部信息 X-Auth-Token。代理服務器負責Swift架構的其余組件間的相互通信。代理服務器也處理大量的失敗請求。例如,如果對于某個對象PUT請求時,某個存儲節點不可用,它將會查詢環可傳送的服務器并轉發請求。對象以流的形式到達(來自) 對象服務器,它們直接從代理服務器傳送到(來自)用戶—代理服務器并不緩沖它們。
- 認證服務(AuthenticationServer):驗證訪問用戶的身份信息,并獲得一個對象訪問令牌(Token),在一定的時間內會一直有效;驗證訪問令牌的有效性并緩存下來直至過期時間。
- 緩存服務(CacheServer):緩存的內容包括對象服務令牌,賬戶和容器的存在信息,但不會緩存對象本身的數據;緩存服務可采用Memcached集群,Swift會使用一致性哈希算法來分配緩存地址。
- 賬戶服務(AccountServer):提供賬戶元數據和統計信息,并維護所含容器列表的服務,每個賬戶的信息被存儲在一個SQLite數據庫中。
- 容器服務(ContainerServer):提供容器元數據和統計信息(比如對象的總數,容器的使用情況等),并維護所含對象列表的服務。容器服務并不知道對象存在哪,只知道指定容器里存的哪些對象。 這些對象信息以SQLite數據庫文件的形式存儲,和對象一樣在集群上做類似的備份。?
- 對象服務(ObjectServer):提供對象元數據和內容服務,可以用來存儲、檢索和刪除本地設備上的對象。在文件系統中,對象以二進制文件的形式存儲,它的元數據存儲在文件系統的擴展屬性(xattr)中,建議采用默認支持擴展屬性(xattr)的XFS文件系統。每個對象使用對象名稱的哈希值和操作的時間戳組成的路徑來存儲。最后一次寫操作總可以成功,并確保最新一次的對象版本將會被處理。刪除也被視為文件的一個版本(一個以".ts"結尾的0字節文件,ts表示墓碑)。
- 復制服務(Replicator):會檢測本地分區副本和遠程副本是否一致,具體是通過對比哈希文件和高級水印來完成,發現不一致時會采用推式(Push)更新遠程副本:對于對象的復制,更新只是使用rsync同步文件到對等節點。帳號和容器的復制通過HTTP或rsync來推送整個數據庫文件上丟失的記錄;另外一個任務是確保被標記刪除的對象從文件系統中移除:當有一項(對象、容器、或者帳號)被刪除,則一個墓碑文件被設置作為該項的最新版本。復制器將會檢測到該墓碑文件并確保將它從整個系統中移除。
- 更新服務(Updater):當對象由于高負載或者系統故障等原因而無法立即更新時,任務將會被序列化到在本地文件系統中進行排隊,以便服務恢復后進行異步更新;例如成功創建對象后容器服務器沒有及時更新對象列表,這個時候容器的更新操作就會進入排隊中,更新服務會在系統恢復正常后掃描隊列并進行相應的更新處理。
- 審計服務(Auditor):在本地服務器上會反復地爬取來檢查對象,容器和賬戶的完整性,如果發現比特級的錯誤,文件將被隔離,并復制其他的副本以覆蓋本地損壞的副本;其他類型的錯誤(比如在任何一個容器服務器中都找不到所需的對象列表)會被記錄到日志中。
- 賬戶清理服務(AccountReaper):移除被標記為刪除的賬戶,刪除其所包含的所有容器和對象。刪除賬號的過程是相當直接的。對于每個賬號中的容器,每個對象先被刪除然后容器被刪除。任何失敗的刪除請求將不會阻止整個過程,但是將會導致整個過程最終失敗(例如,如果一個對象的刪除超時,容器將不能被刪除,因此賬號也不能被刪除)。整個處理過程即使遭遇失敗也繼續執行,這樣它不會因為一個麻煩的問題而中止恢復集群空間。賬號收割器將會繼續不斷地嘗試刪除賬號直到它最終變為空,此時數據庫在db_replicator中回收處理,最終移除這個數據庫文件。
圖4 Swift系統架構
Swift支持的所有操作可以總結為下表:
表1 SwiftRESTful API總結
4.3??????? Ring的數據結構
Ring 的數據結構由三個頂層域構成,其中:
- List of Devices,表示集群中設備的列表,在Ring類內部被稱為devs;
- Partition Assignment List,用于存放每個replica與device間映射關系,在Ring類內部被稱為_replica2part2dev_id;
- Partition Shift Value,表示計算數據hash的移位量,在Ring類內部稱為_part_shift。
使用python讀取/etc/swift/object.ring.gz存放的數據,可以獲得以devs、 part_shift、 replica2part2dev_id 為key的dict類數據。
4.4??????? Swift存儲結構
在Storage Node上運行著Linux系統并使用了XFS文件系統,邏輯上使用一致性哈希算法將固定總數的partition映射到每個Storage Node上,每個data也使用同樣的哈希算法映射到partition上。
存儲內容一般放在/srv/node/sdb1之類的路徑下,其目錄結構如下所示:accounts、async_pending、containers、objects、quarantined和tmp。其中accounts、containers、objects分別是賬號、容器、對象的存儲目錄,async_pending是異步待更新目錄,quarantined是隔離目錄,tmp是臨時目錄。
- objects:在objects目錄下存放的是各個partition目錄,其中每個partition目錄是由若干個suffix_path名的目錄和一個hashes.pkl文件組成,suffix_path目錄下是由object的hash_path名構成的目錄,在hash_path目錄下存放了關于object的數據和元數據;object的數據存放在后綴為.data的文件中,它的metadata存放在以后綴為.meta的文件中,將被刪除的Object以一個0字節后綴為.ts的文件存放。
- accounts:在accounts目錄下存放的是各個partition,而每個partition目錄是由若干個suffix_path目錄組成,suffix_path目錄下是由account的hsh名構成的目錄,在hsh目錄下存放了關于account的sqlite db;在account的db文件中,包含了account_stat、container、incoming_sync 、outgoing_sync 4張表;其中,表account_stat是記錄關于account的信息,如名稱、創建時間、container數統計等等;表container記錄關于container的信息;表incoming_sync記錄到來的同步數據項;表outgoing_sync表示推送出的同步數據項。
- containers:containers目錄結構和生成過程與accounts類似,containers的db中共有5張表,其中incoming_sync和outgoing_sync的schema與accounts中的相同。其他3張表分別為container_stat、object、sqlite_sequence;表container_stat與表account_stat相似,其區別是container_stat存放的是關于container信息。
- tmp:tmp目錄作為account/container/object server向partition目錄內寫入數據前的臨時目錄。例如,client向server上傳某一文件,object server調用DiskFile類的mkstemp方法創建在路徑為path/device/tmp的目錄。在數據上傳完成之后,再調用put()方法,將數據移動到相應路徑。
- async_pending:async_pending存放未能及時更新而被加入更新隊列的數據。本地server在與remote server建立HTTP連接或者發送數據時超時導致更新失敗時,將把文件放入async_pending目錄。這種情況經常發生在系統故障或者是高負荷的情況下。如果更新失敗,本次更新被加入隊列,然后由Updater繼續處理這些失敗的更新工作;account與container的db和object兩者的pending文件處理方式有所不同:db的pending文件在更新完其中的一項數據之后,刪除pending文件中的相應的數據項,而object的數據在更新完成之后,移動pending文件到目標目錄。
- quarantined:quarantined路徑用于隔離發生損壞的數據。Auditor進程會在本地服務器上每隔一段時間就掃描一次磁盤來檢測account、container、object的完整性。一旦發現不完整的數據,該文件就會被隔離,該目錄就稱為quarantined目錄。為了限制Auditor消耗過多的系統資源,其默認掃描間隔是30秒,每秒最大的掃描文件數為20,最高速率為10Mb/s。account和container的Auditor的掃描間隔比object要長得多。
圖5 隔離對象的處理流程
5?????? 小結
Swift犧牲一定程度的數據一致性,來達到高可用性和可伸縮性,支持多租戶模式、容器和對象讀寫操作,適合解決互聯網的應用場景下非結構化數據存儲問題。
有理由相信,因為其完全的開放性、廣泛的用戶群和社區貢獻者,Swift可能會成為云存儲的開放標準,從而打破Amazon S3在市場上的壟斷地位,推動云計算在朝著更加開放和可互操作的方向前進。
6?????? 參考資料
1) 《Openstack Swift 原理、架構與 API 介紹》,http://www.kankanews.com/ICkengine/archives/66411.shtml
2) 《深入云存儲系統Swift核心組件:Ring實現原理剖析》,http://www.cnblogs.com/yuxc/archive/2012/06/22/2558312.html
3) 《深入云存儲系統Swift核心組件:Ring數據結構及構建、重平衡操作》,http://www.cnblogs.com/yuxc/archive/2012/06/28/2568584.html
4) 《深入云存儲系統Swift存儲節點:存儲實現分析》,http://www.cnblogs.com/yuxc/archive/2012/07/04/2575536.html
5) 《OpenStack對象存儲——Swift開源云計算》,http://dev.yesky.com/244/33228744.shtml
6) 《討論:HDFS和OpenStack對象存儲的技術差異》,http://os.51cto.com/art/201202/314254.htm
轉載于:https://www.cnblogs.com/sdjnzqr/p/3909498.html
總結
以上是生活随笔為你收集整理的【转载】OpenStack Swift学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EasyPR编译指南
- 下一篇: 学算法先学数据结构?是否是无稽之谈?