RDD Share:Reusing Results of Spark RDD
最近在研究一些Spark成本優化的東西,看了一些論文稍微總結一下思路,方便思維拓寬和希望與大家交流!
本篇博文參考自:
2016 IEEE First International Conference on Data Science in Cyberspace:
《RDD Share:Reusing Results of Spark RDD》
文章概述及問題描述
Spark作為當下最受關注的分布式計算框架,以其在內存中迭代的特點而逐漸被工業界廣泛使用。對于單個用 戶,Spark所提供的cache功能(持久化)可以讓某些RDD的中間結果在同一個App中的不同jobs間進行共享,但是對于線上的應用,可能同時會用出現多個用戶同時發生操作或是前后發生不同操作但是可能會產生相同的中間數據,此時如何管理這些需要需要被重用的RDD使其能夠被不同用戶所訪問是當下Spark不提供的功能。
那么為何要進行這樣的工作呢
首先是為了提高資源的利用率并降低計算成本,相同RDD緩存后,其他app一旦遇到相同RDD的數據,就可以直接拿過來計算,并不需要重復計算;SQL的常用操作大多都是查詢、插入等基本指令,因此重復性的工作是需要避免的,這樣可以減輕數據倉庫的負債壓力。舉個小例子:臉書通常情況下會持久化這樣的RDD長達天之久。足可見,對于一個大型的分布式系統,這樣的考慮和改進是必不可少的。
本片論文就是基于Spark SQL(雖然目前主流的是Spark dataframe以及dataset)提出一種RDDShare系統來管理這些RDD并調度他們在不同用戶間進行重用。
論文中可能會涉及到一些基本的spark的原理等相關內容,在本篇博客中就不詳細解釋了,如果想要有所了解,Spark官網是比任何書籍都要通俗易懂的教程,之前自己看源碼學習spark的筆記會慢慢整理搬到線上的。請各位大佬多多支持。
論文牽扯到的Spark基礎
-
Spark SQL
Spark SQL(下文簡稱ssql)可以操作類似數據庫表或是表單格式的結構化數據,用戶提交查詢或其他請求給 ssql,ssql會將你的請求代碼轉化為RDD集合,RDD前后就會產生依賴關系,并最終講這樣的RDD集合提交給Spark Core(sc)來進行計算。sc的高層調度器DAGScheduler會首先將RDD集合轉化為DAG圖,然后將具體要執行的tasks信息由底層調度器TaskScheduler來分發到各個節點的Executor中去執行。在使用RDD的編程接口的時候,用戶可以使用持久化算子來將需要重復使用的RDD進行緩存,以提高作業執行的效率。
-
Catalyst
Spark SQL的Catalyst優化器將sql轉化為可執行的RDD需要經歷以下幾步(以查詢命令為例):
1> 將查詢語句轉化為未被解析的邏輯語法樹
2> 解析語法書
3> 基于規則來優化語法樹
4> 此時的語法數依然是邏輯的,為了能夠讓Spark讀懂,此時再轉換為許多的物理語法(即給各個操作綁定上應有的數據結構、表的位置等元數據信息)
5> 基于成本優化模型選擇最優執行
6> 將每一個物理語法轉換為RDDs
最后RDDs將在Spark Core中進行計算
方法概述
RDDShare系統能夠對多DAG中出現相同task的RDD進行管理,并能夠自動在多DAG中去識別相同的RDD,將其重用于其他DAG的計算。
相關已有研究成果
相關研究分為傳統數據庫的緩存技術以及云平臺下的緩存。
-
傳統數據庫
語義緩存: 緩存查詢結果及其相應的語義信息。
--->表緩存
--->動態試圖緩存
--->高速緩存
--->OLAP block cache參考:CAI Jian-yu, YANG Shu-qiang. A Survey of Semantic Caching in Relational Databases. COMPUTER ENGINEERING & SCIENCE. Vol.7, No.10, 2005
云平臺
--->Parag:base on mapreduce,掃描數據文件匹配到用戶指令,進行數據共享[1]
--->Tomasz:base on mapreduce,合并相同作業,另外還使用了成本模型[2]
--->Iman:保存歷史中間結果[3]
參考:
[1] P. Agrawal, D. Kifer, and C. Olston. Scheduling shared scans of large data files. Proc. VLDB Endow.(PVLDB), 1(1):958–969, 2008.
[2] T. Nykiel, M. Potamias, C. Mishra, G. Kollios, and N. Koudas. MRShare: sharing across multiple queries in MapReduce. Proc. VLDB Endow. (PVLDB), 3(1-2):494–505, 2010.
[3] Iman Elghandour, Ashraf Aboulnaga. ReStore: Reusing Results of MapReduce Jobs. Proc of the 38nd VLDB Conf[C], 2012. 2150-8097.
RDDShare System
- RDDShare System在下文簡稱 RSS。*
目的
可以對多張DAG進行分析,并自動發現相同的Task,實現跨DAG對RDD緩存數據進行重用。
舉例
下面主要以兩個例子來闡述RSS
Query1:返回年齡大于18的用戶信息以及網頁信息
val users = sqlContext.read.json("users.json")
val page_views = sqlContext.read.json(“page_views.json")
val rddjoin= users.filter("age > 18").join(page_views, page_views("user") ===
users("name"))
val result = rddjoin.show()
Query2:根據用戶名進行分組,并返回超過18歲的用戶的總體估計收入
val users = sqlContext.read.json("users.json")
val page_views = sqlContext.read.json(“page_views.json")
val rddjoin = users.filter("age > 18").join( page_views, page_views("user") === users("name"))
val rddgroup = rddjoin.groupBy(users("name"))
val rddagg=rddgroup.agg(sum(page_views.col("est_revenue" ) ) )
val result = rddagg.show()
我們都知道,由于Lazy特性,每個RDD并不會立即被執行,而是觸發了最后的action的算子才會向前回溯執行算子。執行開始后,最后一個RDD需要等待前面所有依賴的RDD執行完畢后才能開始執行,因此,RDDn的總時間=RDDn的結束時間。可以下面公示表達:
其中M是RDDn的全部依賴集合。
下面我們來對兩個例子的DAG圖進行分析:
不管是從圖中還是從代碼中我們都知道其中join算子是被兩次重復使用的,并且join的兩個表都是一樣的,那么如果我們在執行Query1的時候可以持久化join后的結果那么對于Query2的執行時間就會縮短至:
其中
假設目前有個子集N并沒有被緩存,并且
因此重點及難點是需要盡可能找到能夠被重復利用的RDD
因此文章提出第二種持久化模型: 緩存部分 RDD
例如Query1中的filter算子假如剛好也出現在另外一個DAG中,那么我們可以持久化這個filter算子的計算結果,并rewrite到Query1中,相當于Query1的代碼可以省略filter之前的一些依賴算子,只需要直接加載之前緩存到的數據即可。如果是這樣一種情況,那么Query1的DAG就會變成如下:
Query1的rewrite-DAG如下:
其中[42]的MapPartionRDD就是之前被緩存過的中間結果。
此時,該模型可用下面的公式來表達:
代表存儲結果所要花費的時間,一般情況下,也只有發生cache等持久化或是遇到Action級別算子(典型的saveAstextFile)的時候才會產生存儲的時間耗費。
RDDShare的組件
輸入輸出
輸入:DAGs
輸出:rewrite后的DAGs
核心組件
DAG Matcher:DAG的匹配器
RDD Cacher:RDD的緩存器
DAG Rewriter:DAG的復寫器
工作流程
先給出一副工作流程圖,基本上光看圖也能明白這三個核心組件是怎樣在工作的
根據圖中所展示的流程,簡要介紹一下RDDShare的工作機制:
- 首先我們需要知道Waiting Queus里面存放的是正在排隊的DAGs,也就是多個job在排隊,可能每一個job就是一個查詢語句或是一段復合代碼,這些都有可能,視Action算子的位置而定。
- 其次,這個等待隊列中有兩個重要區域,前n個DAG被存放在matching window,用于提交到Spark Core中去執行,超過n的n+m個DAG被放置于candidate window中。
- 首先對于第一個DAG(第一個job)會被直接送去計算,因為這個時候并沒有緩存的中間結果給他用,此時matching window中就空缺了一個位置,candidate中的DAG會挨個通過DAG Matcher與matching window總的DAG進行匹配,匹配的目的是為了尋找到重復次數最高的RDD先進行緩存。
- 尋找這樣一個RDDMAX就是用matching中的每一個DAG拿去給candidate中的DAG重復去比,尋找到兩兩間重復次數最高的那個DAG,一有重復的就記錄一個 $Repeat_j$,最后找到重復次數最高的那個
,其對應一個DAGMAX以及RDDMAX,與之對應的原有的candidate window 中的DAG可能會有多個,記作以及
5.此時RDD Cacher會持久化這個RDDMAX到內存或者磁盤,隨后,立馬通過DAG Rewriter將持久化后的RDD直接復寫到 DAG_imax中,并依次將 DAG_imax 壓入matching window中。
驗證用例
因為本文注重SQL-RDD方面,因此選用了伯克利AMPLab實驗室的big data benchmark來作為基準測試平臺。
至此,整個系統的工作原理介紹完畢。
總結與延伸
這篇文章篇幅較短,基本上精度一遍也花不了太多時間。雖然這樣的研究是基于Spark-1.5,但是對于目前的版本仍能夠提供很好的思路。后續自己將做一下延伸,個人感覺本片論文的對于處理結構化數據時候的復用思路是值得推廣并有很大使用價值和效益意義。
如果對這方面有感興趣的童鞋歡迎評論或私信討論哈。
我的博客 : https://NingSM.github.io
轉載請注明原址,謝謝。