針對“互聯網+”時代的業務增長、變化速度及大規模計算的需求,廉價的、高可擴展的分布式x86集群已成為標準解決方案,如Google已經在幾千萬臺服務器上部署分布式系統。Docker及其相關技術的出現和發展,又給大規模集群管理帶來了新的想象空間。如何將二者進行有效地結合?本文將介紹數人科技基于Mesos和Docker的分布式計算平臺的實踐。
分布式系統設計準則
可伸縮性
首先分布式系統一定是大規模的系統,有很好的Scalability。出于成本的考慮,很多大規模的分布式系統一般采用廉價的PC服務器,而不是大型的高性能服務器。
沒有單點失效
廉價的PC服務器在大規模使用中經常會遇到各種各樣的問題,PC服務器的硬件不可能是高可靠的,比如Google的數據中心每天都會有大量的硬盤失效,所以分布式系統一定要對硬件容錯,保證沒有任何的單點失效。在這種很不穩定、很不可靠的硬件計算環境下,搭建一個分布式系統提供高可靠服務,必須要通過軟件來容錯。分布式系統針對不允許有單點失效的要求有兩方面的設計考慮,一種是服務類的企業級應用,每個服務后臺實例都要有多個副本,一兩臺硬件故障不至于影響所有服務實例;另外一種數據存儲的應用,每份數據也必須要有多個備份,保證即使某幾個硬件壞掉了數據也不會丟失。
高可靠性
除了單點失效,還要保證高可靠性。在分布式環境下,針對企業級服務應用,要做負載均衡和服務發現來保證高可靠性;針對數據服務,為了做到高可靠性,首先要按照某種算法來把整體數據分片(因為一臺服務器裝不下),然后按照同樣的算法來進行分片查找。
數據本地性
再一個分布式設計理念是數據本地性,因為網絡通信開銷是分布式系統的瓶頸,要減少網絡開銷,應當讓計算任務去找數據,而不是讓數據去找計算。
分布式系統與Linux操作系統的比較
由于縱向拓展可優化空間太小(單臺服務器的性能上限很明顯),分布式系統強調橫向擴展、橫向優化,當分布式集群計算資源不足時,就要往集群里面添加服務器,來不停地提升分布式集群的計算能力。分布式系統要做到統一管理集群的所有服務器,屏蔽底層管理細節,諸如容錯、調度、通信等,讓開發人員覺得分布式集群在邏輯上是一臺服務器。
和單機Linux操作系統相比,雖然分布式系統還沒有成熟到成為“分布式操作系統”,但它和單機Linux一樣要解決五大類操作系統必需的功能,即資源分配、進程管理、任務調度、進程間通信(IPC)和文件系統,可分別由Mesos、Docker、Marathon/Chronos、RabbitMQ和HDFS/Ceph來解決,對應于Linux下的Linux Kernel、Linux Kernel、init.d/cron、Pipe/Socket和ext4,如圖1所示。
圖1 分布式系統與Linux操作系統的比較
基于Mesos的分布式計算平臺
Mesos資源分配原理
目前我們的Mesos集群部署在公有云服務上,用100多臺虛擬機組成Mesos集群。Mesos不要求計算節點是物理服務器還是虛擬服務器,只要是Linux操作系統就可以。Mesos可以理解成一個分布式的Kernel,只分配集群計算資源,不負責任務調度。基于Mesos之上可以運行不同的分布式計算平臺,如Spark、Storm、Hadoop、Marathon和Chronos等。Spark、Storm和Hadoop這樣的計算平臺有任務調度功能,可以直接使用Mesos SDK跟Mesos請求資源,然后自行調度計算任務,并對硬件容錯。Marathon針對服務型分布式應用提供任務調度,比如企業網站等這類需要長時間運行的服務。通常網站應用程序沒有任務調度和容錯能力,因為網站程序不太會處理某個后臺實例掛掉以后要在哪臺機器上重新恢復等這類復雜問題。這類沒有任務調度能力的服務型分布式應用,可以由Marathon來負責調度。比如,Marathon調度執行了網站服務的一百個后臺實例,如果某個實例掛掉了,Marathon會在其他服務器上把這個實例恢復起來。Chronos是針對分布式批處理應用提供任務調度,比如定期處理日志或者定期調Hadoop等離線任務。
Mesos最大的好處是能夠對分布式集群做細粒度資源分配。如圖2所示,左邊是粗粒的資源分配,右邊是細粒的資源分配。
圖2 Mesos資源調度的兩種方式
圖2左邊有三個集群,每個集群三臺服務器,分別裝三種分布式計算平臺,比如上面裝三臺Hadoop,中間三臺是Spark,下面三臺是Storm,三個不同的框架分別進行管理。右邊是Mesos集群統一管理9臺服務器,所有來自Spark、Hadoop或Storm的任務都在9臺服務器上混合運行。Mesos首先提高了資源冗余率。粗粒資源管理肯定帶來一定的浪費,細粒的資源提高資源管理能力。Hadoop機器很清閑,Spark沒有安裝,但Mesos可以只要任何一個調度馬上響應。最后一個還有數據穩定性,因為所有9臺都被Mesos統一管理,假如說裝的Hadoop,Mesos會集群調度。這個計算資源都不共享,存儲之間也不好共享。如果這上面跑了Spark做網絡數據遷移,顯然很影響速度。然后資源分配的方法就是resource offers,是在窗口的可調度的資源自己去選,Mesos是Spark或者是Hadoop等等。這種方法,Mesos的分配邏輯就很簡單,只要不停地報告哪些是可用資源就可以了。Mesos資源分配方法也有一個潛在的缺點,就是無中心化的分配方式,所以有可能不會帶來全局最優的方式。但這個數據資源缺點對目前來講并不是很嚴重。現在一個計算中心資源貢獻率很難達到50%,絕大部分計算中心都是很閑的狀態。
Mesos資源分配示例
下面具體舉例說明怎么用Mesos資源分配。如圖3所示,中間是Mesos Master,下面是Mesos Slave,上面是Spark和Hadoop運行在Mesos之上。Mesos Master把可用資源報告給Spark或Hadoop。假定Hadoop有一個任務想運行,Hadoop從Mesos Master上報的可用資源中選擇某個Mesos Slave節點,然后這個任務就會在這個Mesos Slave節點上執行,這是任務完成一次資源分配,接下來Mesos Master繼續進行資源分配。
圖3 Mesos資源分配示例
任務調度
Mesos只做一件事情,就是分布式集群資源分配,不管任務調度。Marathon和Chonos是基于Mesos來做任務調度。如圖4所示,Mesos集群混合運行來自Marathon和Chronos的不同類型的任務。Marathon和Chonos基于Mesos做任務調度時,一定是動態調度,也就是每個任務在執行之前是不知道它將來在哪一臺服務器上執行和綁定哪一個端口。如圖5所示,9臺服務器組成的Mesos集群上混合運行各種Marathon調度的任務,中間一臺服務器壞掉以后,這臺服務器上的兩個任務就受影響,然后Marathon把這兩個任務遷移到其他服務器上,這就是動態任務調度帶來的好處,非常容易實現容錯。
圖4 Mesos集群運行不同類型的任務
圖5 Marathon動態任務調度
為了減少硬件故障對應用服務的影響,應用程序要盡量做到無狀態。無狀態的好處是在程序受到影響時不需要進行任何恢復,這樣這個程序只要重新調度起來就可以。無狀態要求把狀態數據放到存儲服務器或者是消息隊列里面,這樣的好處是容錯時恢復起來會變得很方便。
服務類的高可靠性
對于服務類型的任務,分布式環境保證服務的高可靠性,這需要負載均衡和服務發現。在分布式環境下做負載均衡有一個難點就是后臺這些實例有可能發生動態變化,比如說某一個節點壞掉了,這個節點上的實例會受到影響,然后遷移到其他節點上。然而傳統負載均衡器的后臺實例地址端口都是靜態的。所以在分布式環境下,為了做負載均衡一定要做服務發現。比如,某個服務之前有四個事例,現在新添加了兩個實例,需要告訴負載均衡器新增加的實例的地址和端口。服務發現的過程是由幾個模塊配合完成,比如說Marathon給某個服務增加了新的實例,把新調度的實例地址端口寫到Zookeeper,然后Bamboo把Zookeeper里存放的該服務新的實例的地址端口信息告訴負載均衡器,這樣負載均衡器就知道新的實例地址端口,完成了服務發現。
數據類的高可靠性
對于服務類型的應用,分布式系統用負載均衡器和服務發現來保證高可靠性的服務。對于數據類型的應用,分布式系統同樣要保證高可靠的數據服務。首先要做數據分片,一臺服務器存不下所有數據就分成多份來存,但對數據進行分片必須按照某個規則來進行分片,后面查找時要按照同樣的規則來進行分片查找,就是一致性。假定最原始的方案我們用Hash計算做成方法,在線性空間上分了三份以后,我要在數據分成三塊機器來存,三臺機器都存滿了時,再把數據進行分配的時候不再把它分配到直線線性空間上,而是把它分配到環狀空間上,把起點和終點連接起來,連成一個數據環,如圖6所示,這樣相應的數據點就放在這一塊。如果要添加一個新的數據中心就在環上新切出來這塊,這樣很方便,切出來這一部分代表這一部分數據都應該放到新的芯片上,所以把原來子數據分片挪到嵌入式的分片上。
圖6 數據分片
還有可能刪除數據,我們把黃色的數據放到紅色的數據上,這是環的好處。實際為了做到高可靠性,任何一個數據可能假定映射到黃色部分以后,這些黃色的部分只要映射到任何一個黃色的區域都會存在同一片機器上,同一片機器底層會有多個副本和做數據的備份,這是實際數據分片的一個實例。這是怎么做數據的高可靠性。這些數據分片,還有負載均衡,都是為了對應分布式分片硬件帶來的不可靠和失效,這是我們用分布式系統最大的特點。
基于Docker的分布式計算平臺
Docker工作流
我們主要用Docker來做分布式環境下的進程管理。Docker工作流如圖7所示,我們不僅把Docker應用到生產階段,也應用到開發階段,所以我們每天編輯Dockerfile,提升Docker Images,測試上線,發Docker鏡像,在我們內部私有Docker regis里面,再調到我們Docker集群生產環境里面,這和其他的Docker工作流沒有什么區別。
圖7 Docker工作流
在Mesos提交Docker任務
因為Mesos和Docker已經是無縫結合起來。通過Marathon和Chronos提交服務型應用和批處理型應用。Marathon和Chronos通過RESTful的方式提交任務,用JSON腳本設定應用的后臺實例個數、應用的參數、以及Docker Images的路徑等等。
分布式環境下的進程通信
在分布式環境下應用服務之間通信,是用分布式消息隊列來做,我們用的是RabbitMQ。RabbitMQ也是一個分布式系統,它也要保證高可靠性、解決容錯的問題。首先RabbitMQ也有集群,如圖8所示,六個節點組成了一個RabbitMQ的集群,每個節點之間是互為備份的關系,任何一個壞掉,其他五個還可以提供服務,通過冗余來保證RabbitMQ的高可靠性。
圖8 RabbitMQ集群
其次,RabbitMQ也有數據分片機制。因為消息隊列有可能很長,長到所有的消息不可能都放到一個節點上,這時就要用分片,把很長的消息隊列分為幾段,分別放到不同的節點上。如圖9所示是RabbitMQ的聯盟機制,把一個消息隊列打成兩段,一段放在上游一段放在下游,假定下游消息隊列的消息被消費完了就自動把上游消息隊列里的消息移到下游,這樣一個消息隊列變成非常長的時候也不怕,分片到多個節點上即可。
圖9 消息隊列分片
分布式文件系統
最后講一下分布式文件系統HDFS和Ceph。Hadoop文件系統HDFS,如圖10所示,每個數據塊有三個備份,必須放在不同的服務器上,而且三個備份里面每個機架最多放兩份,這么做也是為了容錯。Ceph是另一種流行的開源分布式文件系統。Ceph把網絡存儲設備抽象成一張邏輯硬盤,然后“掛載”到分布式集群的每臺服務器上,原理上非常像是Linux操作系統Mount一塊物理硬盤。這樣一來,用戶程序訪問Ceph的文件系統就跟訪問Linux本地路徑一樣,非常方便。
圖10 分布式文件系統
分布式環境下的監控
分布式環境下,程序不是運行在本地,而是在集群上面,沒有監控就等于程序運行在黑盒子下,無法調優,必須要有監控。分布式環境下的監控分為兩個部分,一是性能監控,另一個是報警。性能監控要知道每個應用程序運行狀態是什么樣,即每一個應用程序占了多少CPU內存、服務的請求處理延遲等。我們是用Graphite來做應用程序性能監控;還有其他系統,比如MongoDB、Hadoop等開源系統,我們用Ganglia來做性能監控,比如CPU內存硬盤的使用情況等。報警是要在關鍵服務出現故障時,通知開發運維人員及時排解故障,我們用Zabbix來做報警。(責編/周建丁)
作者簡介:王璞,先后在硅谷供職于StumbleUpon、Groupon和Google,擅長海量數據處理、分布式計算以及大規模機器學習。2014年回國創辦數人科技,基于Mesos和Docker構建分布式計算平臺,為企業客戶提供大數據分析處理一站式解決方案。