標籤:
史鳴飛:大家好,我是叫史鳴飛,來自英特爾公司,接下來我向大家介紹一下Tachyon。我事先想瞭解一下大家有沒有聽說過Tachyon,或者是對Tachyon有沒有一些瞭解?對Spark呢?
首先做一個介紹,我來自英特爾的大資料團隊,我們團隊主要是致力於各種大資料的軟體開發以及這些軟體在工業界的推廣和應用,我所在的團隊主要負責Spark及其軟體棧的開發和推廣。我們是國內最早參加Spark開發和推廣的團隊,我們在2012年就加入了Spark社區。在Spark和相關的項目中間投入了大量的人力,長期以來我們在Spark及相關項目中有超過10位活躍的貢獻者,在Spark項目中我們團隊代碼的貢獻量是排名前3的。
下面是我今天演講的內容的概要,首先我會向大家做一個Tachyon的介紹,包括為什麼會出現Tachyon,Tachyon的基本架構,Tachyon和現有系統的整合以及Tachyon一些基本的原理,接下來我會向大家介紹我們在使用Tachyon方面的經驗和一些應用的執行個體,最後會向大家介紹一下Tachyon的發展情況和英特爾在Tachyon上的工作。
Tachyon出現的背景是什嗎?首先記憶體為王這句話這兩年很流行,大資料處理對速度的追求是無止境的。記憶體的速度和磁碟的速度不是一個數量級的,另一方面記憶體的價格越來越低,記憶體的容量越來越低大,這就讓資料存在記憶體中間就有了可行性。伴隨著這種趨勢,大量的基於記憶體的計算架構也出來了,像Spark和SAP的HANA都是優秀的基於記憶體的計算架構,但是現有的計算架構還面臨一些挑戰。Tachyon的出現就是為瞭解決這些問題的,那麼當前基於記憶體的大資料計算架構到底遇到了那些問題呢?接下來我就以Spark為例,向大家分析一下。
第一個問題是資料共用問題,一個叢集可能運行著多個計算架構和多個應用,比如說一個叢集上有可能運行著Spark,同時還運行著Hadoop,在現在的情況下他們兩個之間的資料共用是通過HDFS的。也就是說如果一個Spark的應用結果的輸出是另外一個MapReduce任務輸入的話,中間結果就必須要通過寫入和讀取HDFS才能實現,大家知道HDFS的讀寫首先是一個磁碟的IO,另外由於它的備份策略,預設它有三份的備份,這樣又會引入網路的IO,這是一個很低效的過程。第二個問題是快取資料丟失的問題,像Spark這樣的計算架構它的記憶體管理模組和計算執行器是在同一個JVM裡面的,如果它的執行器發生一些異常導致執行出現錯誤,從而導致JVM退出的話,那麼緩衝在JVM堆空間中的資料就會同時丟失掉,這樣的話就會導致快取資料丟失。第三個問題是GC的問題,因為現在大部分的大資料的計算架構都是運行在JVM上的,GC的開銷就是一個不可避免的問題。對於像Spark這樣一個基於記憶體的計算架構而言,GC的問題尤其突出,它會把大量的資料緩衝在JVM堆空間裡面,這些資料是計算時需要用到的資料,GC是沒辦法清除掉的,每一次full GC都會對這些資料做一個全域的掃描,這是很耗時間的,而且隨著計算時間的增長和堆記憶體資料的增加,GC的開銷會越來越大。
解決方案是什麼呢?我們首先分析導致這個問題的根本原因是什麼,根本的原因就是現有的基於記憶體的計算架構缺乏脫離於JVM的記憶體管理模組。解決方案就是伴隨著Spark而產生的基於記憶體的分布式儲存系統Tachyon。Tachyon的設計思想主要有兩個,第一個是基於記憶體的OffHeap的分布式儲存,就是一定要把資料存放區在JVM堆空間之外,這樣的話能夠避免GC。第二個是通過在儲存層儲存資料的Lineage實現容錯,這是在Spark中引入的思想,Lineage記錄了來源資料以及來源資料經過什麼樣的計算得到的當前資料,Tachyon將這些本來是在計算層才關心的資訊放到了儲存層。Tachyon僅僅儲存一份資料在記憶體中,記憶體是很寶貴的資源。而HDFS它為了實現容錯在磁碟上預設儲存了三份,那麼如果Tachyon某一個節點是沒有這份資料的時候,它會通過網路去讀。因為在遠端的結點上資料也是在記憶體中間的,因此遠端讀取沒有磁碟的IO只有網路的開銷,所以說也是很高效的。當資料丟失的時候,Tachyon會根據資料的Lineage進行資料的恢複,這個過程有點像Spark中的資料重算,但是它比Spark走的更遠。因為Spark中的重算是在程式運行時的操作,當程式啟動並執行時候發現某個節點掛掉了,它會重新計算來管不著資料,問題是如果整個Job已經結束之後,資料再發生丟失就沒有辦法了,Tachyon可以解決這個問題。因為Tachyon在儲存層儲存了整個資料的依賴關係,包括了這個資料是由什麼樣的架構,通過什麼樣的執行過程產生的,當資料丟失的時候Tachyon會重新啟動這些應用然後生新成這些資料,實現資料恢複。
這是Tachyon設計的目標,Tachyon在整個大資料處理軟體棧中所處的位置,最下層是儲存層,像HDFS、S3。在上層有Spark、H2O,Tachyon相當於是在儲存層和計算層之間的cache層,Tachyon並不是要替代任何的儲存系統,它的作用是加快計算層對儲存層的訪問速度。這張是Tachyon的基本架構,從這張圖大家可以看到Tachyon和HDFS是很像的,有Master和Worker。Master用於管理整個叢集中間所有資料的中繼資料,包括資料的大小、資料的位置。Worker用於管理每個節點上的記憶體資料,所有的記憶體資料是儲存在Ramdisk上的,Ramdisk是把一段記憶體空間映射成一個block裝置,Tachyon就可以以記憶體的速度去讀寫檔案。Worker會定期與Master通訊,把Worker上的資料報告給Master,Master會根據Worker彙報的資訊給Worker發送命令。在圖的最左邊還有Zookeeper,它會選擇一個最可用的Master作為主節點。還有一個模組在這張圖上沒有的,那就是Client。它是提供應用程式的編程介面,應用程式通過Client向Tachyon中讀寫資料。
Tachyon中資料的容錯有兩種,一種是中繼資料的容錯,就是Master節點上的資料容錯,另外一種是記憶體資料容錯,是Worker上的資料容錯。中繼資料的容錯和HDFS是很像的,通過日誌實現的。Image儲存了中繼資料,Editlog記錄了最近對中繼資料的修改記錄。而記憶體資料容錯是Tachyon的特有的,例如:Fileset A通過一個Spark Job產生了Fileset B,Fileset C通過另一個Spark Job產生了Fileset D,同時File set C和File set D又通過一個Mapreduce Job產生了Fileset E,這樣一個資料產生的過程會在Tachyon中被儲存下來,如果Fileset E丟失了,而Fileset B和Fileset D都存在,那麼Tachyon就會重啟Mapreduce job通過Fileset B和Fileset D重建Fileset E,如果Fileset B和Fileset E也都不存在了,那麼Tachyon就會重新起用Spark Job產生 FilesetB 和 Fileset D, 最後再啟動Mapreduce Job由FilesetB和Fileset D產生Fileset E。
現在回顧一下我之前講的現有的基於記憶體的計算架構所面臨的三個問題,在有了Tachyon之後這個問題是怎麼得到解決的?資料共用問題,Spark和Hadoop可以通過Tachyon去儲存中間結果資料,如果MapReduce需要Spark的輸出結果,可以直接讀取Tachyon獲得,而不需要訪問HDFS。快取資料丟失的問題,Spark可以將RDD緩衝在Tachyon中,這樣當Spark的應用Crash的時候這些緩衝的資料是不會丟失的。第三個是GC的開銷,這個顯而易見的,由於資料在Tachyon中,GC不會管理這部分資料。
下面向大家介紹一下Tachyon怎麼和現有的大資料處理框架組成的,首先是Mapreduce,MapReduce是沒有和Tachyon做任何整合的,如果要在MapReduce裡面使用Tachyon的話,就要把Tachyon當做外來的包或者是庫來引用。第一種方法是把Tachyon的jar包放在Hadoop的Class path裡面,第二種是放在Hadoop的Lib的目錄裡,第三種是作為應用程式的一部分,分發出去。另外還需要對Hadoop做一些配置,需要配置Tachyon檔案系統,這樣MapReduce就可以直接通過Tachyon載入和寫入資料,使用方法和HDFS一樣。Spark已經整合了Tachyon,如果在Spark中間使用Tachyon的話,只需要對Spark做一些簡單的配置就可以了,在SparkConf裡面配置Tachyon Master的URI,這樣Spark就可以把所有的RDD的資料緩衝在Tachyon中,通過設定RDD的Storagelevel為OFF_HEAP,Spark就會自動的把RDD放在Tachyon裡面。如果Spark要通過Tachyon去載入和寫入資料的話,就需要在像在Mapreduce中一樣配置Tachyon的檔案系統,這樣的話Spark就可以像讀寫HDFS一樣從Tachyon裡面去讀寫資料。
下面我講一下Tachyon基本的工作原理,首先是它的通訊機制,Tachyon使用thrift進行通訊,可以通過配置Master Client和Worker之間的介面自動產生。還有就是Herabeat通訊,是為了在Tachyon各組件之間保持串連關係,Master和Worker也會通過Heartbeeat交換資訊,Worker會把自己節點上最近增加的資料或者是資料的改變提交給Master,Master會根據Worker提供的檔案資訊去修改Master上的中繼資料,Master也會返回給Worker一些資訊。如果Worker提供給Master的檔案資訊的中繼資料在Master已經沒有了,Master就會告訴Worker刪掉該檔案。如果Worker有一段時間沒有和Master通訊,Master就會認為Worker已經和他中斷連線,當Worker又和Master通訊的時候,Master就會告訴Worker需要重新註冊,把節點上所有的檔案資訊重新發給Master。Worker也有自檢措施,如果它檢測到和Master通訊逾時,會重新向Master註冊。Client和Master Worker之間都是有串連的,Client發送給Master的Heartbeat,Master暫時沒有處理。Client和Worker之間的通訊就是為了維持Client和Worker之間的關係,如果Worker檢查到Client連線逾時,Worker就會釋放掉分配給Client的資源。
Tachyon裡檔案的組織方式,首先介紹Worker上的組織方式,Worker有兩種檔案系統,一種是Ramdisk,即記憶體檔案系統,另一種是底層檔案系統,最常用的是HDFS。在記憶體檔案系統裡面,檔案是以Block的方式儲存的。在底層檔案系統上以整個檔案的方式儲存的。在記憶體檔案系統上檔案名稱是BlockID,而在底層檔案系統裡檔案名稱是FileID。Tachyon的中繼資料的組織,大家可以看到這是一個樹狀的結構,每個節點都是一個Inode,Inode記錄了檔案的資訊,所有的檔案都從根節點開始的,根據路徑的名字可以一步一步的找到。如果Inode代表一個目錄,它會記錄自己目錄裡面所有的子目錄和檔案,如果Inode代表一個檔案,它會記錄這個檔案所有的Block,以及這個檔案是不是在底層檔案系統上有一個備份,以及備份的檔案在的路徑。
應用通過Tachyon Client讀寫資料,讀資料時,Client向Master發送請求,從Master擷取要讀取的Block的資訊,包括Block的ID和位置資訊,拿到這個資訊之後Client首先請求Worker lock該block,表明該block正在被訪問,Lock之後Client就會讀取檔案,讀取完了之後再要求Worker去unlock這個檔案,最後還要求Worker更新該block的訪問時間,這是因為在寫資料的時候,如果空間不足Worker會根據訪問時間做基於LRU的檔案刪除操作。如果這個檔案並沒有在本地Worker上,Client就會去Remote Worker上去讀,Remote Worker在接受到請求之後會以通過網路將資料傳回給Client。
Tachyon在讀取資料的時候有兩種讀取方式,第一種是CACHE的方式,意思是說如果本地有資料那麼直接讀取,如果本地沒有資料從遠程讀數取時,讀完之後會在本地建立一個緩衝的副本。這個策略的目的是說,使用者認為資料會在接下來還會反覆被使用,與其說從遠程反覆去讀取資料還不如直接在本地建立一個副本,以節省開銷,如果是從底層檔案系統讀呢?CACHE策略也會在本地的記憶體中建立一個副本,而No-cache的策略是唯讀一次,使用者認為接下來不會再去訪問這個檔案了。
寫檔案時,Client向worker申請記憶體空間,Worker首先判斷自己的記憶體空間還夠不夠,如果不夠的話它就會根據某種特定的演算法,在當前是LRU的演算法,將最近沒有被訪問的block檔案直接的刪除掉,釋放空間。在分配好記憶體之後就會告訴給Client分配成功,Client就會要將他要的資料寫進本地的Ramdisk。Client寫完之後會通知Worker去cache這個檔案,cache的過程是從把資料從使用者目錄移動到資料目錄,而Worker在cache完之後會發給Master新的block檔案的資訊。在寫入方面也是有多種策略的,首先有一個MUST-CACHE,Client要求必須把檔案寫在記憶體中間,如果記憶體不夠沒辦法寫的話,Tachyon就會報錯。而TRY-CACHE就是說儘可能的把資料寫進記憶體中。而THROUGH是直接把檔案寫進底層的檔案系統,不會寫記憶體。而CACH而-THROUGH就是會儲存兩個拷貝,而ASYNC-THROUGH就是將檔案寫進本地記憶體直接就儲存了,Tachyon從記憶體備份到底盤檔案當中。前2種策略是對讀做了最佳化,如果這個檔案只是一個臨時檔案不需要做永久的儲存,而且它在寫之後可能馬上會被讀取甚至是反覆的讀取,要把它放在記憶體中間,並且由於它是一個臨時檔案不需要在底層檔案做永久的儲存。而THROUGH是只在底層的檔案系統寫入這個檔案,如果這個檔案是一個應用的輸出結果,而且在寫入之後在短時間之內是不會被訪問的,那麼就把這個檔案直接寫入到Tachyon管理的底層檔案系統的空間中。如果這個結果在將來被使用的話,那可以根據使用者的需要把檔案新放進Tachyon的記憶體中實現快速的訪問。而CACHE-THROUGH就兼顧了上面的兩種,而非同步THROUGH不保證儲存到底層檔案系統,它是為了提高響應的時間、減少延遲,但是它和CACHE-THROUGH的最終效果是一樣的。
Tachyon的使用者介面,Tachyon提供了兩種使用者介面,第一種介面是命令列。這和HDFS的命令列介面很像,提供一些基本的檔案系統操作命令,像cat、ls、mkdir、rm等,是為了方便使用者對Tachyon記憶體中間的檔案做一些最基本的操作。第二種介面是編程介面,在Tachyon中主要有兩個為使用者程式提供服務的介面,一個是TachyonFS,這是Tachyon提供的最基本的編程介面,這裡面涵蓋了所有Tachyon提供給使用者程式的功能,其中包括像delete、mkdir、rename等,通過對這些基本的功能編程,可以實現檔案系統的操作。另一個是TachyonFile,提供了一些更上層的介面。比如說擷取一個檔案的InStream 或者 OutStream。
我們在Tachyon上的使用經驗,第一個是我們團隊自己開發的日誌資料處理的原型系統。在github上可以找到這個項目,它的名字叫Thunderain。流式的資料首先會被放在Kafka裡面,它是一個訊息佇列,在Kafka裡面的資料經過SparkStraming處理後會被寫進Tachyon的In-memory Tables裡面,因為這些資料是儲存在In Memory Table裡面,它的訪問資料是很快的,所以可以支援在後台運行一些線上的分析或者是互動查詢,對回應時間延遲比較敏感的應用。圖下方的處理流程,Kafka中的資料還可以通過ETL的處理儲存在HDFS裡面,這些資料可以作為曆史的資料,曆史資料和Tachyon 記憶體資料可以做組合的查詢。比如說一個視頻網站,使用者對視頻點擊的日誌可以通過上面的串流,背景應用人員就可以很快速的會去查詢到,在最近的這段時間裡面什麼視頻被播放的次數最多,哪些視頻是最熱門的,而曆史資料的作用是,線上資料可以和曆史資料做一個對比,就是說在前一天或者是上一個小時,什麼視頻是最熱的。
另外一個Tachyon應用執行個體是OffHeap的儲存,這是我們做過國內某視頻網站的case,這個case的目的是做視頻內容的推薦,這是一個圖演算法N度級聯的問題。N度級聯的意思是計算一個圖中2個節點之間跳躍N次,經過N次的條約他們之間相關度是多少,就是說有N距離的相關度是多少,它的演算法在這裡。它的演算法大概是這個意思,假定兩個節點之間有M條長度都是N的路徑,那麼Weightk(X、Y)表示第K條路徑的權重?N度級聯要求的就是所有的M條路徑的權重的合,每一條路徑的權重等於整個路徑上所有邊的權重級,因為每條邊的權重都是一個0到1之間的數,權重積必定也是0到1的浮點數,而且隨著N的增大他們的相關度是減小的。在現實當中這個是可以在社交網路裡面計算不同使用者的相關性,電商網站的產品推薦等。在解決這個問題的時候,我們用了兩種圖的架構實現的,一種是bagel一種是Graphx。首先我講一講Bagel的實現, Spark在實現Bagel的時候,把每個superStep中產生的節點的新的資料和該節點發送給下一個superstep的各個節點的的訊息都放在了Spark的RDD中,我們發現隨著迭代次數的增加,GC的開銷是相當大的,因為資料量是很大的,每次迭代都會把這個資料cache起來。我們的解決方案就是用Tachyon去緩衝了這一部分的資料,相當於讓Bagel運行在Tachyon上,這樣的好處是能夠解決大量GC的問題。第二種實現是GraphX,它的計算過程是這樣子的,首先是收集階段,它會收集每個節點和邊的資料,然後產生發送給各個節點的訊息,在計算階段每個節點會根據收到的訊息產生新的節點資料,在這一步就相當於是從一箇舊的圖產生了一個新的圖。在這個階段Spark其實也是把這一部分的資料給緩衝起來了,我們在使用的時候也是把這個資料緩衝在Tachyon上,然後緩解GC的問題。
第三個使用者的case是遠端資料存取,使用者有多個叢集,其中有一個叢集是專門提供儲存服務的,還有若干個計算叢集,在這些叢集上有可能啟動並執行Spark或者Mapreduce。他們有這樣的需求,在某個計算叢集上,應用需要多次的去訪問提供儲存服務叢集上的資料,這個開銷是很大的,相當於在兩個叢集間做資料的讀取。我們提供的解決方案就是使用Tachyon,應用只需要從遠程提供儲存服務的叢集上讀取一次資料,把資料緩衝在本地Tachyon上,然後在Tachyon上對資料做反覆的訪問和計算,這樣的話就可以節省大量的資料讀取的開銷。
Tachyon適用的情境,第一個情境計算中間結果需要在不同的應用和計算架構中間共用的時候,也就是說中間結果有可能會被不同的後台應用所使用。第二個情境是需要快速響應對延遲比較敏感,比如背景使用者有可能會做一些線上的查詢,或者是一些互動式查詢的時候,使用Tachyon其實可以起到提高響應和降低延遲的效果。第三個是記憶體資料量比較大,並且擁有長時間和迭代式的計算需求,我們之前做過一個使用者的case裡面使用了Tachyon之後,在效能上也提高了30%以上。第四個情境是需要多次訪問大量的遠端資料,Tachyon的作用就是可以把遠端資料放在本地做多次的訪問,這樣可以減少遠端存取的開銷。但是Tachyon也是有局限的,第一個局限是CPU的負載會增加,因為Tachyon中資料是以檔案的方式存的,那麼就會有序列化和還原序列化的開銷,這是一個很消耗CPU的工作。第二個局限是Tachyon暫時只能使用記憶體做儲存空間,這個局限在接下來的版本就不會存在了,因為我們現在正在用其他的高速儲存空間像SSD去擴充Tachyon的儲存空間。
Tachyon當前的發展狀況,Tachyon是一個很新的項目,是2012年的夏天開始的,有5個發起者,最左邊的是李浩源,他是Tachyon的作者,是個中國人,現在UC Berkeley讀博士。Tachyon的現在最新的發行版本是0.5.0,主分支版本是0.6-SNAPSHOT,Tachyon在國內還很少有公司使用,國外已經有50多家公司在嘗試使用了。現有的Spark和MapReduce的程式可以不經過修改直接在Tachyon上運行,Spark將Tachyon作為預設的Offheap的儲存系統,上面的這些是對Tachyon有貢獻的一些組織,在國內有兩所大學在做Tachyon方面的工作,南京大學和清華大學。
最後講講英特爾的貢獻,我們有3位貢獻者,一共有100多個提交,這些提交裡面,我們做了重要的功能組件,也做了提高可用性和易用性的工作,還有一些BUG的修補,接下來我向大家介紹我們做的一個功能組件:多層級的本機存放區。它解決的問題就是我剛剛提到的,Tachyon現在只能使用記憶體作為它的儲存空間。我們使用SSD、HDD去擴充Tachyon的儲存空間,整個儲存結構是一個金字塔的結構,最上層空間比較小但是速度很快,中介層和下層是速度慢一點但是空間很大,我們通過設計一些策略,將最熱的資料放在最頂層,達到比較快的訪問速度,暫時不太熱的資料放在SSD或HDD上,當資料將來再次變熱的時候可以重新把它給放回記憶體中間。這樣的好處是當記憶體不夠的時候可以把資料放在SSD或HDD,而不是將資料丟掉,同時對效能沒有太大的影響。
最後希望大家能夠嘗試著使用Tachyon,因為從我瞭解的情況來看,國內的公司用Tachyon的很少,也希望大家能夠加入Tachyon的社區,Tachyon的項目發布在github上,大家在使用的時候發現有任何的問題可以給我們提一些意見。
《SPARK/TACHYON:基於記憶體的分布式儲存系統》-史鳴飛(英特爾亞太地區研發有限公司大資料軟體部工程師)