天天看點

LinkedIn 開源其分布式對象存儲系統 Ambry

日前,linkedin在github上基于apache 2許可證協定開源了其分布式對象存儲系統ambry。ambry是一個是不可變對象的存儲系統,非常易于擴充,它能夠存儲kb到gb大小的不可變對象,并且能夠實作高吞吐和低延遲,該系統支援跨資料中心的雙活部署,并且存儲成本低廉。它特别适于存儲各種媒體内容。

據linkedin的前工程主管sriram subramanian介紹,媒體内容在web中已經無處不在,linkedin中的每項新特性基本上都會與某種類型的媒體内容進行互動。這些媒體内容會存儲在後端,并且主要會由内容分發網絡(content delivery networks,cdn)來提供服務,背景存儲系統會作為cdn的原始伺服器(origin server)。

随着linkedin流量的不斷增長,原來所使用的媒體内容存儲方案在可擴充性、可用性以及運維方面所遇到的問題越來越多。兩年前,他們着手解決這些問題,而ambry正是該項工作的結果。

2013年時的媒體存儲是什麼樣的?

linkedin之前的系統被稱為媒體伺服器(因為沒有一個像樣的名字),這個系統由兩部分組成,分别是用于媒體檔案存儲的filer以及存儲中繼資料的大型oracle資料庫。這些系統的前端是一些運作在solaris上的無狀态機器,它們會将請求路由到對應的filer或資料庫上。filer是通過nfs的方式mount到無狀态機器上的,并使用java的file api進行遠端通路。前端會與資料中心(dc)裡面的一組緩存進行互動,進而保證如果下遊系統(filer/oracle)出現性能問題或不可用時,前端不會受其影響。

LinkedIn 開源其分布式對象存儲系統 Ambry

頻繁出現的可用性問題:每次對檔案的中繼資料操作出現峰值時,原有的系統都會出現延遲。當通路大量的小檔案時,對中繼資料的操作就會增多。每次檔案操作都要經過多級的轉換(java、nfs以及filer),使其很難進行調試;難以擴充:用來存儲資料和中繼資料的底層系統都是單體的。水準擴充中繼資料的存儲是不可能實作的,為資料存儲增加硬體也需要很多的手動過程;對小對象和大對象的支援效率低下:媒體資料集中包含了數萬億的小對象(50kb-1mb)也包括數億的大對象(1mb-1gb)。對于小對象的存儲來說,中繼資料操作的代價是很高昂的,而對于大資料,原有的系統缺乏端到端的流支援,難以支援新産品的使用場景;平均修複時間(mttr,mean time to repair)名額很差:老系統中的大多數組成部分在很大程度上都是黑盒,這需要獲得支援許可證,并且要通過電話的方式來描述和解決問題,這會影響到mttr;成本高昂:舊的媒體存儲成本很高,再繼續擴充的話,成本上已經吃不消了。如果想管理媒體的擴充性,就不能延續該方案了。

在這個過程中,linkedin探索過多種替代方案,最終還是決定自行實作更比對其需求的解決方案。

ambry是如何運作呢?

設計目标

在了解ambry的設計和内部運作原理之前,明确其設計目标是很有幫助的,這決定了它的實作方式。

高可用性和水準可擴充:該系統要處理實時流量,會直接影響到站點的可用性,是以它必須具有很高的可用性。另外,還希望新系統能夠盡可能地實作無縫的叢集擴充;降低運維的負擔:分布式系統一般都會難以管理,對于頻繁的叢集操作,能夠實作自動化是非常重要的,這能避免系統成為運維的一種負擔。複雜的系統通常很難實作自動化并可靠的運作,是以新系統的設計要簡單、優雅并自動化;更低的mttr:分布式系統出現故障是難以避免的,但是很重要的一點在于快速修複故障,讓各個子元件啟動并運作。這就需要系統的設計簡單,并且不會出現單點故障;跨dc雙活:linkedin有多個資料中心,是以所有的系統都要支援雙活配置,這樣的話,系統能夠更新不同資料中心中的同一個對象;提升小對象和大對象的效率:請求是由小對象和大對象所組成的,小對象通常是1k到100k,超出這個範圍的對象會位于大對象桶中(bucket)。要同時處理好各種大小的對象,通常來講是很困難的。大量的小對象會給中繼資料帶來很高的負載,造成硬碟碎片,需要很多的随機io,而大對象則需要很好的記憶體管理、端到端的流處理和有限的資源使用;廉價:媒體内容很快就會占據很大的存儲空間,它的另外一個特點是舊資料會變成“冷”資料,并不會頻繁通路。針對這種情況有很多優化技術,包括使用密集的硬體(denser hardware)、分層存儲、擦除編碼以及資料去重等。在設計時,ambry希望媒體内容能夠高效存儲在密集型的機器上,并且能夠非常容易地使用其他優化成本的方案。

概覽

總體上來講,ambry由三部分組成,分别是用來存儲和檢索資料的一組資料節點,路由請求的前端機器(請求會在一些預處理之後路由到資料節點上)以及協調和維護叢集的叢集管理器。資料節點會在不同節點之間複制資料,同時支援資料中心内部和資料中間之間的複制。前端提供了支援對象put、get和delete操作的http api。另外,前端所使用的路由庫也可以直接用在用戶端中,進而實作更好的性能。在linkedin,這些前端節點會作為cdn的原始伺服器。

LinkedIn 開源其分布式對象存儲系統 Ambry

  api

ambry提供了rest api,它們适用于大多數的場景。在有些場景下,需要更好的性能,如果是這樣的話,ambry也支援在用戶端使用路由庫,直接針對資料節點的流位元組進行讀取和寫入。目前,路由庫是阻塞的(同步),不過ambry目前正在緻力于實作非阻塞(異步)版本,同時也會提供對路由庫的多語言支援。

clustermap

clustermap控制拓撲結構、維護狀态并幫助協調叢集的操作。clustermap有兩部分組成:

硬體布局:包含了機器的清單、每台機器上的磁盤以及每個磁盤的容量。布局還維護資源的狀态(機器和磁盤)并指定主機名和端口,通過主機名和端口就能連接配接到資料節點;分區布局:包含了分區的清單、它們的位置資訊以及狀态。在ambry中,分區有一個數字表示的id,副本的清單可以跨資料中心。分區是固定大小的資源,叢集間的資料重平衡都是在分區級别進行的。

LinkedIn 開源其分布式對象存儲系統 Ambry

資料節點和前端伺服器都能夠通路clustermap,并且會始終使用它們目前的視圖來做出決策,這些決策涉及到選擇可用的機器、過濾副本以及識别對象的位置等。

存儲

存儲節點會用來存放不同分區的副本。每個存儲節點會有n塊磁盤,副本會跨磁盤分布存儲。這些副本的結構和管理都是相同的。

LinkedIn 開源其分布式對象存儲系統 Ambry

  在存儲方面,ambry涵蓋的功能包括如下幾個方面:

持久化:磁盤上的每個副本均被模組化為預先配置設定的log(preallocated log)。所有新的消息都會按照順序附加到log上,消息是由實際的對象塊(chunk)和相關的中繼資料(系統和使用者)所組成的。這能夠使寫入操作實作很高的吞吐量,并且避免出現磁盤碎片。ambry會使用索引将對象id與log中的消息映射起來,索引本身是一組排序的檔案片段,條目按照最新使用在前,最舊的條目在後的順序,進而便于高效查找。索引中的每個條目都維護了log中消息的偏移量、消息的屬性以及一些内部使用的域。索引中的每個片段會維護一個bloom filter,進而優化實際磁盤操作所耗費的時間;零拷貝:通過使用sendfile api,在進行讀取時,位元組從log轉移到網絡的過程中實作了零拷貝。通過避免額外的系統調用,實作了更好的性能,在這個過程中,會確定位元組不會讀入到使用者記憶體中,不必進行緩存池的管理;恢複:因為系統和機器會出現當機,磁盤上的資料也有可能會損壞,是以有必要實作恢複(recovery)的功能。在啟動的時候,存儲層會從最後一個已知的檢查點讀取log,并重建索引。恢複也有助于重建記憶體中的狀态。log是恢複的來源,并且會永久儲存;複制:存儲節點還需要維護分區中各副本的同步。每個節點上都會有一個複制服務(replication service),它會負責保證本地存儲中的副本與所有的遠端副本是同步的。在這裡,進行了很多的優化,以保證複制過程的高效可靠。

路由/前端

前端伺服器提供了http接口,供用戶端與之通信。除此之外,它們還會負責為cdn設定正确的頭資訊、進行安全校驗,并将對象以流的形式傳回給路由庫和用戶端。

路由所負責的功能如下所示:

請求管理:請求的端到端生命周期是由路由來進行管理的。路由會處理put、get以及delete請求。對于其中的每個請求類型,路由都會跟蹤副本成功和失敗的數量進而确定quorum的值、維護分塊的狀态、生成對象id并在成功或失敗的時候觸發對應的回調;分塊:大對象會分解為塊(chunk),每個塊都能夠跨分區獨立地進行路由。每個塊都會有一個id來進行唯一辨別。路由會生成一個中繼資料對象,其中包含了塊的清單以及它們所需的擷取順序。中繼資料對象存儲為獨立的blob,它的id也會作為blob的id。在讀取的時候,會得到中繼資料對象,然後檢索各個塊并傳回給用戶端;故障檢測:故障檢測的邏輯要負責主動識别當機或狀态出問題的資源。資源可以是機器、磁盤或分區。路由會将出現問題的資源标記為不可用,這樣後續的請求就不會使用它們了;quorum:ambry為寫入和讀取實作了一種多主人(multi-master)的政策。這能夠實作更高的可用性并減少端到端的延遲,這是通過減少一個額外的hop來實作的,在基于主從結構(master slave)的系統中,往往會有這個額外的hop。請求通常會發往m個副本,然後等待至少n個成功的響應(這裡n<=m)。路由會優先使用本地資料中心的副本,向其發送請求,如果本地存儲無法實作所需的quorum的話,它會代理遠端資料中心的通路;變更捕獲:在每次成功的put或delete操作之後,路由會生成一個變更捕獲(change capture)。變更捕獲中所包含的資訊是blob id以及blob相關的中繼資料,這個資訊可以被下遊的應用所使用。

在路由中,典型的put和get操作的流程分别如下所示,系統的實際運作過程會比下述的描述會更複雜一些:

put操作:用戶端會将對象以及一些中繼資料資訊以流的形式發送到前端,當流到達時,前端會将對象進行分塊、選擇可用的分區、為blob或分塊生成blob id,并将請求分發給w個副本。然後,前端就開始等待至少q個成功的響應(q<=w),等到之後,會将blob id傳回給用戶端。如果無法達到足夠的quorum,那麼前端會報告一個錯誤。當然,ambry也實作了當quorum失敗的時候,選擇另外一個分區的功能,進而提升可用性。

LinkedIn 開源其分布式對象存儲系統 Ambry

get操作:用戶端通過将id發送給前端來請求某一個blob。前端會根據id來确定分區,并在資料節點中檢索blob相關的塊。對于每個塊,前端會并行發送r個請求,在将blob或分塊發送給用戶端之前,前端會等待q個成功響應(q<=r)。

LinkedIn 開源其分布式對象存儲系統 Ambry

  解決運維的難題

分布式系統最困難的在于它的運維,在這個過程中,需要工具、度量并且要進行廣泛地測試,進而保證所有的事情都能符合預期。在這個過程中,ambry積累了很多的工具和實踐。

simoorg:為了模拟各種故障,他們孵化并開源了simoorg。這是一個分布式的故障引入系統,能夠在叢集中引入各種故障,如gc暫停、磁盤錯誤、節點當機以及網絡故障,進而校驗在各種情況下,系統的正确性,有助于預先發現并修正嚴重的缺陷;生産環境的正确性測試:當新版本部署到叢集中的部分機器進行驗證時,可以進行正确性測試,進而保證生産環境的健康狀态。通過加壓通路所有可用的api(組合使用各種可能出現的輸入參數),確定結果的正确性;審計:當新的blob寫入到磁盤時,都會産生複制事件,這個事件包含了blob的資訊以及事件的來源。所有存儲節點的事件都會聚集到hadoop中,這樣就能審計是否所有的副本都進行了寫入。目前該系統并不是實時的,不過,ambry規劃會建構一個實時的審計系統。

除此之外,ambry還實作了名額和告警工具,用來幫助識别系統中的異常行為以及維護叢集的管理工具。

遷移工作是如何進行的?

團隊需要将所有的媒體内容從遺留系統遷移至ambry,在這個過程中還要服務于所有的流量,不能出現任何的當機時間。除此之外,團隊還面臨着多項deadline,了解ambry是如何組織研發和部署的,對我們會有一定的指導意義:

當時,公司正在将所有的服務從spring rpc方案中剝離出來。從建構ambry開始計算,團隊有四個月的時間支援新的api并移除spring rpc;一個新的資料中心正好需要搭建,ambry團隊并不想再去部署遺留系統了,因為這會帶來很高的成本。這同時也就意味着為了避免部署遺留系統,需要在八個月内完成ambry;最後,團隊希望在資料中心裡面移除掉solaris的方案,遺留系統是運作在solaris上的,它的deadline是一年。

ambry團隊采用了一種特殊的方式來達到這些裡程碑節點。首先,建構前端并使用它來代理所有對舊系統的請求,然後再将所有的用戶端遷移到新的前端上。這雖然費了很大的功夫,但是確定了第一個deadline目标的達成。

第二步是讓ambry能夠以端到端的方式運作,并且隻将其部署到新的資料中心上,然後将所有的資料從舊系統遷移至ambry。在代碼中,添加了一定的邏輯,確定如果新資料中心發生故障的話,将會使用舊的系統。這可能會産生更多的延遲,但是團隊決定承擔這個風險。

在新資料中心搭建完成之後,在接下來的幾個月裡,團隊不斷運作并穩定ambry。基于測試和審計結果,當對新系統完全自信的時候,團隊決定停掉遺留的系統。這樣就在一年的deadline之内完成了目标。

在接下來的一年中,ambry成為了linkedin中媒體内容的唯一來源。它的成功要歸因于周密的規劃以及漸進式的基礎設施研發。

ambry是如何适應linkedin的生态系統的?

媒體基礎設施是針對媒體内容的端到端管道,涉及到上傳、存儲、處理、中繼資料管理以及内容下載下傳。在基礎設施中,ambry是很重要的一個環節,基礎的穩固是非常重要的。在ambry就緒之後,就可以圍繞着它進行擴充并關注生态系統中的其他組成部分。

LinkedIn 開源其分布式對象存儲系統 Ambry

  下一步的研發計劃

目前,ambry主要進行中的任務包括在前端和路由層實作非阻塞、存儲節點實作機架感覺等功能。團隊希望不斷地為ambry添加新的特性,并且建構活躍的開源社群。完整的未來工作計劃清單可以參見github上的相關頁面,如下列出了目前正在進行的或者可能會開展的項目:

非阻塞:阻塞類型的請求通常會占用一個程序,直到請求結束并且不支援管道。為了達到更高的吞吐量,并且避免大對象所造成的資源枯竭現象,需要将路由和前端變成完全非阻塞的。這樣的話,就能支援更大吞吐量,在操作執行時,不再受限于線程資源,進而能夠實作更好的可用性。目前,前端實作已經完成,正在進行測試。路由庫的代碼預計也将會很快完成,可以參考其repository來了解最近的更新情況;機架感覺:現代的資料中心為了降低成本都将機架切換視為很重要的因素。這意味着軟體要足夠智能來應對切換故障。ambry正在建構的一項功能就是確定新分區的副本在跨資料中心存放時,能夠遵循機架感覺的方式。目前,該項工作正在進行之中;bucket/container:ambry尚不支援命名空間的概念。如果要在群組的級别上強化控制的話,那命名空間是非常有用的。在ambry中,可能将會引入bucket或container的理念。這有助于在bucket級别上定義使用者群組、通路控制和配額,這種方式會比在對象級别進行維護容易得多;安全:ambry目前支援資料節點之間的加密,在前端和資料節點之前的通信也可以啟用加密功能。不過,在安全方面,ambry會有更多的進展,包括rest級别的認證、授權以及對加密的支援。該項功能預計會在bucket/container實作完成之後開展。

對于社群來講,這個系統會有很大的用處,有助于支援媒體内容的實時上傳和媒體服務的建構,詳細的文檔可以參見github上的相關頁面。如果讀者有回報意見或有志于為該項目做出貢獻的話,可以參考其開發指南。ambry團隊希望該項目的開發能夠保持開放的狀态,并幫助社群使用它來建構應用程式。另外值得一提的是,2016年度的sigmod(special interest group on management of data)已經接受了一篇關于ambry的論文,該會議将會在六月份舉行,可以浏覽其網站了解更多資訊。 

本文轉自d1net(轉載)