Tachyon是Spark生態系統內快速崛起的一個新項目。 本質上, Tachyon是個分佈式的內存文件系統, 它在減輕Spark內存壓力的同時,也賦予了Spark內存快速大量數據讀寫的能力。Tachyon把內存存儲的功能從Spark中分離出來, 使Spark能夠更專一計算的自己, 以求經過更細的分工達到更高的執行效率。 本文將先向讀者介紹Tachyon在Spark生態系統中的使用, 也將分享百度在大數據平臺上利用Tachyon取得的性能改善的用例,以及在實際使用Tachyon過程當中遇到的一些問題和解決方案。最後咱們將介紹一下Tachyon的一些新功能。 node
Spark平臺以分佈式內存計算的模式達到更高的計算性能,在最近引發了業界的普遍關注,其開源社區也十分活躍。以百度爲例,在百度內部計算平臺已經搭建並運行了千臺規模的Spark計算集羣,百度也經過其BMR的開放雲平臺對外提供Spark計算平臺服務。然而,分佈式內存計算的模式也是一柄雙刃劍,在提升性能的同時不得不面對分佈式數據存儲所產生的問題,具體問題主要有如下幾個:算法
當兩個Spark做業須要共享數據時,必須經過寫磁盤操做。好比:做業1要先把生成的數據寫入HDFS,而後做業2再從HDFS把數據讀出來。在此,磁盤的讀寫可能形成性能瓶頸。緩存
因爲Spark會利用自身的JVM對數據進行緩存,當Spark程序崩潰時,JVM進程退出,所緩存數據也隨之丟失,所以在工做重啓時又須要從HDFS把數據再次讀出。服務器
當兩個Spark做業需操做相同的數據時,每一個做業的JVM都須要緩存一份數據,不但形成資源浪費,也極易引起頻繁的垃圾收集,形成性能的下降。網絡
仔細分析這些問題後,能夠確認問題的根源來自於數據存儲,因爲計算平臺嘗試自行進行存儲管理,以致於Spark不能專一於計算自己,形成總體執行效率的下降。Tachyon的提出就是爲了解決這些問題:本質上,Tachyon是個分佈式的內存文件系統,它在減輕Spark內存壓力的同時賦予了Spark內存快速大量數據讀寫的能力。Tachyon把存儲與數據讀寫的功能從Spark中分離,使得Spark更專一在計算的自己,以求經過更細的分工達到更高的執行效率。架構
圖1: Tachyon的部署app
圖1顯示了Tachyon的部署結構。Tachyon被部署在計算平臺(Spark,MR)之下以及存儲平臺(HDFS, S3)之上,經過全局地隔離計算平臺與存儲平臺, Tachyon能夠有效地解決上文列舉的幾個問題,:分佈式
當兩個Spark做業須要共享數據時,無需再經過寫磁盤,而是藉助Tachyon進行內存讀寫,從而提升計算效率。性能
在使用Tachyon對數據進行緩存後,即使在Spark程序崩潰JVM進程退出後,所緩存數據也不會丟失。這樣,Spark工做重啓時能夠直接從Tachyon內存讀取數據了。大數據
當兩個Spark做業須要操做相同的數據時,它們能夠直接從Tachyon獲取,並不須要各自緩存一份數據,從而下降JVM內存壓力,減小垃圾收集發生的頻率。
在上一章咱們介紹了Tachyon的設計,本章咱們來簡單看看Tachyon的系統架構以及實現。 圖2顯示了Tachyon在Spark平臺的部署:總的來講,Tachyon有三個主要的部件:Master, Client,與Worker。在每一個Spark Worker節點上,都部署了一個Tachyon Worker,Spark Worker經過Tachyon Client訪問Tachyon進行數據讀寫。全部的Tachyon Worker都被Tachyon Master所管理,Tachyon Master經過Tachyon Worker定時發出的心跳來判斷Worker是否已經崩潰以及每一個Worker剩餘的內存空間量。
圖2: Tachyon在Spark平臺的部署
圖3顯示了Tachyon Master的結構,其主要功能以下:首先,Tachyon Master是個主管理器,處理從各個Client發出的請求,這一系列的工做由Service Handler來完成。這些請求包括:獲取Worker的信息,讀取File的Block信息, 建立File等等;其次,Tachyon Master是個Name Node,存放着全部文件的信息,每一個文件的信息都被封裝成一個Inode,每一個Inode都記錄着屬於這個文件的全部Block信息。在Tachyon中,Block是文件系統存儲的最小單位,假設每一個Block是256MB,若是有一個文件的大小是1GB,那麼這個文件會被切爲4個Block。每一個Block可能存在多個副本,被存儲在多個Tachyon Worker中,所以Master裏面也必須記錄每一個Block被存儲的Worker地址;第三,Tachyon Master同時管理着全部的Worker,Worker會定時向Master發送心跳通知本次活躍狀態以及剩餘存儲空間。Master是經過Master Worker Info去記錄每一個Worker的上次心跳時間,已使用的內存空間,以及總存儲空間等信息。
圖3: Tachyon的Master設計
圖4顯示了Tachyon Worker的結構,它主要負責存儲管理:首先,Tachyon Worker的Service Handler處理來自Client發來的請求,這些請求包括:讀取某個Block的信息,緩存某個Block,鎖住某個Block,向本地內存存儲要求空間等等。第二,Tachyon Worker的主要部件是Worker Storage,其做用是管理Local Data(本地的內存文件系統)以及Under File System(Tachyon如下的磁盤文件系統,好比HDFS)。第三,Tachyon Worker還有個Data Server以便處理其餘的Client對其發起的數據讀寫請求。當由請求達到時,Tachyon會先在本地的內存存儲找數據,若是沒有找到則會嘗試去其餘的Tachyon Worker的內存存儲中進行查找。若是數據徹底不在Tachyon裏,則須要經過Under File System的接口去磁盤文件系統(HDFS)中讀取。
圖4: Tachyon的Worker設計
圖5顯示了Tachyon Client的結構,它主要功能是向用戶抽象一個文件系統接口以屏蔽掉底層實現細節。首先,Tachyon Client會經過Master Client部件跟Tachyon Master交互,好比能夠向Tachyon Master查詢某個文件的某個Block在哪裏。Tachyon Client也會經過Worker Client部件跟Tachyon Worker交互, 好比向某個Tachyon Worker請求存儲空間。在Tachyon Client實現中最主要的是Tachyon File這個部件。在Tachyon File下實現了Block Out Stream,其主要用於寫本地內存文件;實現了Block In Stream主要負責讀內存文件。在Block In Stream內包含了兩個不一樣的實現:Local Block In Stream主要是用來讀本地的內存文件,而Remote Block In Stream主要是讀非本地的內存文件。請注意,非本地能夠是在其它的Tachyon Worker的內存文件裏,也能夠是在Under File System的文件裏。
圖5: Tachyon的Client設計
如今咱們經過一個簡單的場景把各個部件都串起來:假設一個Spark做業發起了一個讀請求,它首先會經過Tachyon Client去Tachyon Master查詢所須要的Block所在的位置。若是所在的Block不在本地的Tachyon Worker裏,此Client則會經過Remote Block In Stream向別的Tachyon Worker發出讀請求,同時在Block讀入的過程當中,Client也會經過Block Out Stream把Block寫入到本地的內存存儲裏,這樣就能夠保證下次一樣的請求能夠由本機完成。
在百度內部,咱們使用Spark SQL進行大數據分析工做, 因爲Spark是個基於內存的計算平臺,咱們預計絕大部分的數據查詢應該在幾秒或者十幾秒完成以達到互動查詢的目的。但是在Spark計算平臺的運行中,咱們卻發現查詢都須要上百秒才能完成,其緣由如圖6所示:咱們的計算資源(Data Center 1)與數據倉庫(Data Center 2)可能並不在同一個數據中內心面,在這種狀況下,咱們每一次數據查詢均可能須要從遠端的數據中心讀取數據,因爲數據中心間的網絡帶寬以及延時的問題,致使每次查詢都須要較長的時間(>100秒)才能完成。更糟糕的是,不少查詢的重複性很高,一樣的數據極可能會被查詢屢次,若是每次都從遠端的數據中心讀取,必然形成資源浪費。
爲了解決這個問題,咱們藉助Tachyon把數據緩存在本地,儘可能避免跨數據中心調數據。當Tachyon被部署到Spark所在的數據中心後,每次數據冷查詢時,咱們仍是從遠端數據倉庫拉數據,可是當數據再次被查詢時,Spark將從同一數據中心的Tachyon中讀取數據,從而提升查詢性能。實驗代表:若是從非本機的Tachyon讀取數據,耗時降到10到15秒,比原來的性能提升了10倍;最好的狀況下,若是從本機的Tachyon讀數據,查詢僅需5秒,比原來的性能提升了30倍,效果至關明顯。
在使用了這個優化後,熱查詢性能達到了互動查詢的要求,但是冷查詢的用戶體驗仍是不好。分析了用戶行爲後,咱們發現用戶查詢的模式比較固定:好比不少用戶天天都會跑同一個查詢,只是所使用過濾數據的日期會發生改變。藉助此次特性,咱們能夠根據用戶的需求進行線下預查詢,提早把所須要的數據導入Tachyon,從而避免用戶冷查詢。
圖6: Tachyon在百度大數據平臺的部署
在使用Tachyon過程當中,咱們也遇到了一些問題:在剛開始部署Tachyon的時候, 咱們發現數據徹底不能被緩存,第一次與後續的查詢耗時是同樣的。如圖7的源代碼所示:只有整個數據Block被讀取後,這個Block纔會被緩存住;不然緩存的操做會被取消。好比一個Block是256MB,若是你讀了其中的255MB,這個Block仍是不會被緩存,由於它只需讀取整個block中的部分數據。在百度內部,咱們不少數據是用行列式存儲的,好比ORC與Parquet文件,每次查詢只會讀其中的某幾列, 所以不會讀取完整的Block, 以至block緩存失敗。爲了解決這個問題,咱們對Tachyon進行了修改,若是數據Block不是太大的話,冷查詢時即便用戶請求的只是其中幾列,咱們也會把整個Block都讀進來,保證整個Block能被緩存住,而後再次查詢的話就能夠直接從Tachyon讀取了。在使用了修改的版本後,Tachyon達到了咱們期待的效果,大部分查詢能夠在10秒內完成。
圖7: Tachyon緩存數據邏輯
咱們把Tachyon看成緩存來使用,可是每臺機器的內存有限,內存很快會被用完。 若是咱們有50臺機器,每臺分配20GB的內存給Tachyon,那麼總共也只有1TB的緩存空間,遠遠不能知足咱們的須要。在Tachyon最新版本有一個新的功能: Hierarchical Storage,即便用不一樣的存儲媒介對數據分層次緩存。如圖8所示,它類於CPU的緩存設計:內存的讀寫速度最快因此能夠用於第0級緩存,而後SSD能夠用於第1級緩存,最後本地磁盤能夠做爲底層緩存。這樣的設計能夠爲咱們提供更大的緩存空間,一樣50臺機器,如今咱們每臺可貢獻出20TB的緩存空間,使總緩存空間達到1PB,基本能夠知足咱們的儲存需求。與CPU緩存相似,若是Tachyon的block Replacement Policy設計得當,99%的請求能夠被第0級緩存(內存)所知足,從而在絕大部分時間能夠作到秒級響應。
圖8: Tachyon Hierarchical Storage
當Tachyon收到讀請求時,它首先檢查數據是否在第0層,若是命中,直接返回數據,不然它會查詢下一層緩存,直到找到被請求的數據爲止。數據找到後會直接返回給用戶,同時也會被Promote到第0層緩存,而後第0層被替換的數據Block會被LRU算法置換到下一層緩存。如此一來,若是用戶再次請求相同的數據就會直接從第0層快速獲得,從而充分發揮緩存的Locality特性。
當Tachyon收到寫請求時,它首先檢查第0層是否有足夠空間,若是有,則直接寫入數據後返回。不然它會查詢下一層緩存,直到找到一層緩存有足夠空間,而後把上一層的一個Block用LRU算法推到下一層,如此類推,直到把第0層有足夠空間以寫入新的數據,而後再返回。這麼作的目的是保證數據被寫入第0層,若是讀請求立刻發生在寫請求後,數據能夠快速被讀取。但是,這樣作的話寫的性能有可能變的不好:好比頭兩層緩存都滿的話,它須要把一個Block從第1層丟到第2層,再把一個Block從第0層丟到第1層,而後才能寫數據到第0層,再返回給用戶。
對此咱們作了個優化, 與其層層類推騰出空間,咱們的算法直接把數據寫入有足夠空間的緩存層,而後快速返回給用戶。若是緩存全滿,則把底層的一個Block置換掉,而後把數據寫入底層緩存後返回。通過實驗,咱們發現優化後的作法會把寫延時下降約50%,大大的提升了寫的效率。可是讀的效率又如何呢,因爲在TACHYON裏,寫是經過Memory-Mapped File進行的,因此是先寫入內存,再Flush到磁盤,若是讀是立刻發生在寫以後的話,其實會從操做系統的Buffer,也就是內存裏讀數據,所以讀的性能也不會降低。
Hierarchical Storage很好地解決了咱們緩存不夠用的問題,下一步咱們將繼續對其進行優化。好比,如今它只有LRU一種置換算法,並不能知足全部的應用場景, 咱們將針對不一樣的場景設計更高效的置換算法,儘可能提升緩存命中率。
我我的相信更細的分工會達到更高的效率,Spark做爲一個內存計算平臺,若是使用過多的資源去緩存數據,會引起頻繁的垃圾收集,形成系統的不穩定,或者影響性能。在咱們使用Spark的初期,系統不穩定是咱們面臨的最大挑戰,而頻繁的垃圾收集正是引發系統不穩定最大的緣由。好比當一次垃圾收集耗時過長時,Spark Worker變的響應很是不及時,很容易被誤認爲已經崩潰,致使任務從新執行。Tachyon經過把內存存儲的功能從Spark中分離出來,讓Spark更專一在計算自己,從而很好的解決了這個問題。隨着內存變的愈來愈便宜,咱們能夠預期將來一段時間裏,咱們的服務器裏可以使用的內存會不斷增加,Tachyon會在大數據平臺中發揮愈來愈重要的做用。如今仍是Tachyon發展的初期,在本文完成時Tachyon才準備發佈0.6版,還有不少功能亟需完善,這也是一個好機遇,有興趣的同窗們能夠多關注Tachyon,到社區裏進行技術討論以及功能開發。
劉少山
百度美國硅谷研發中心高級架構師,主要研究方向分佈式系統以及大數據計算與存儲平臺。