中文字幕日韩一区二区不卡,亚洲av永久无码精品天堂动漫,亚洲av无码国产精品麻豆天美,最新版天堂中文在线,中文字幕视频在线看

a&s專業(yè)的自動化&安全生態(tài)服務平臺
公眾號
安全自動化

安全自動化

安防知識網(wǎng)

安防知識網(wǎng)

手機站
手機站

手機站

大安防供需平臺
大安防供需平臺

大安防供需平臺

資訊頻道橫幅A1
首頁 > 資訊 > 正文

大數(shù)據(jù)計算平臺Spark內(nèi)核全面解讀

大數(shù)據(jù)計算平臺Spark內(nèi)核全面解讀及分析。
資訊頻道文章B
1、Spark介紹

      Spark是起源于美國加州大學伯克利分校AMPLab的大數(shù)據(jù)計算平臺,在2010年開源,目前是Apache軟件基金會的頂級項目。隨著 Spark在大數(shù)據(jù)計算領(lǐng)域的暫露頭角,越來越多的企業(yè)開始關(guān)注和使用。2014年11月,Spark在Daytona Gray Sort 100TB Benchmark競賽中打破了由Hadoop MapReduce保持的排序記錄。Spark利用1/10的節(jié)點數(shù),把100TB數(shù)據(jù)的排序時間從72分鐘提高到了23分鐘。

      Spark在架構(gòu)上包括內(nèi)核部分和4個官方子模塊--Spark SQL、Spark Streaming、機器學習庫MLlib和圖計算庫GraphX。圖1所示為Spark在伯克利的數(shù)據(jù)分析軟件棧BDAS(Berkeley Data Analytics Stack)中的位置??梢奡park專注于數(shù)據(jù)的計算,而數(shù)據(jù)的存儲在生產(chǎn)環(huán)境中往往還是由Hadoop分布式文件系統(tǒng)HDFS承擔。

圖1 Spark在BDAS中的位置 

      Spark被設(shè)計成支持多場景的通用大數(shù)據(jù)計算平臺,它可以解決大數(shù)據(jù)計算中的批處理,交互查詢及流式計算等核心問題。Spark可以從多數(shù)據(jù)源的 讀取數(shù)據(jù),并且擁有不斷發(fā)展的機器學習庫和圖計算庫供開發(fā)者使用。數(shù)據(jù)和計算在Spark內(nèi)核及Spark的子模塊中是打通的,這就意味著Spark內(nèi)核 和子模塊之間成為一個整體。Spark的各個子模塊以Spark內(nèi)核為基礎(chǔ),進一步支持更多的計算場景,例如使用Spark SQL讀入的數(shù)據(jù)可以作為機器學習庫MLlib的輸入。表1列舉了一些在Spark平臺上的計算場景。

表1 Spark的應用場景舉例

      在本文寫作是,Spark的最新版本為1.2.0,文中的示例代碼也來自于這個版本。

2、Spark內(nèi)核介紹 

      相信大數(shù)據(jù)工程師都非常了解Hadoop MapReduce一個最大的問題是在很多應用場景中速度非常慢,只適合離線的計算任務。這是由于MapReduce需要將任務劃分成map和 reduce兩個階段,map階段產(chǎn)生的中間結(jié)果要寫回磁盤,而在這兩個階段之間需要進行shuffle操作。Shuffle操作需要從網(wǎng)絡中的各個節(jié)點 進行數(shù)據(jù)拷貝,使其往往成為最為耗時的步驟,這也是Hadoop MapReduce慢的根本原因之一,大量的時間耗費在網(wǎng)絡磁盤IO中而不是用于計算。在一些特定的計算場景中,例如像邏輯回歸這樣的迭代式的計 算,MapReduce的弊端會顯得更加明顯。

      那Spark是如果設(shè)計分布式計算的呢?首先我們需要理解Spark中最重要的概念--彈性分布數(shù)據(jù)集(Resilient Distributed Dataset),也就是RDD。 

2.1 彈性分布數(shù)據(jù)集RDD

      RDD是Spark中對數(shù)據(jù)和計算的抽象,是Spark中最核心的概念,它表示已被分片(partition),不可變的并能夠被并行操作的數(shù)據(jù)集 合。對RDD的操作分為兩種transformation和action。Transformation操作是通過轉(zhuǎn)換從一個或多個RDD生成新的 RDD。Action操作是從RDD生成最后的計算結(jié)果。在Spark最新的版本中,提供豐富的transformation和action操作,比起 MapReduce計算模型中僅有的兩種操作,會大大簡化程序開發(fā)的難度。

      RDD的生成方式只有兩種,一是從數(shù)據(jù)源讀入,另一種就是從其它RDD通過transformation操作轉(zhuǎn)換。一個典型的Spark程序就是通 過Spark上下文環(huán)境(SparkContext)生成一個或多個RDD,在這些RDD上通過一系列的transformation操作生成最終的 RDD,最后通過調(diào)用最終RDD的action方法輸出結(jié)果。

      每個RDD都可以用下面5個特性來表示,其中后兩個為可選的:

  • 分片列表(數(shù)據(jù)塊列表)
  • 計算每個分片的函數(shù)
  • 對父RDD的依賴列表
  • 對key-value類型的RDD的分片器(Partitioner)(可選)
  • 每個數(shù)據(jù)分片的預定義地址列表(如HDFS上的數(shù)據(jù)塊的地址)(可選)

      雖然Spark是基于內(nèi)存的計算,但RDD不光可以存儲在內(nèi)存中,根據(jù)useDisk、useMemory、useOffHeap, deserialized、replication五個參數(shù)的組合Spark提供了12種存儲級別,在后面介紹RDD的容錯機制時,我們會進一步理解。值 得注意的是當StorageLevel設(shè)置成OFF_HEAP時,RDD實際被保存到Tachyon中。Tachyon是一個基于內(nèi)存的分布式文件系統(tǒng),目前正在快速發(fā)展,本文不做詳細介紹,可以通過其官方網(wǎng)站進一步了解。

  1. classStorageLevelprivate(
  2.     privatevar _useDisk:Boolean,
  3.     privatevar _useMemory:Boolean,
  4.     privatevar _useOffHeap:Boolean,
  5.     privatevar _deserialized:Boolean
  6.     privatevar _replication:Int=1)
  7.   extendsExternalizable{//… }
  8.  
  9. val NONE =newStorageLevel(false,false,false,false)
  10.   val DISK_ONLY =newStorageLevel(true,false,false,false)
  11.   val DISK_ONLY_2 =newStorageLevel(true,false,false,false,2)
  12.   val MEMORY_ONLY =newStorageLevel(false,true,false,true)
  13.   val MEMORY_ONLY_2 =newStorageLevel(false,true,false,true,2)
  14.   val MEMORY_ONLY_SER =newStorageLevel(false,true,false,false)
  15.   val MEMORY_ONLY_SER_2 =newStorageLevel(false,true,false,false,2)
  16.   val MEMORY_AND_DISK =newStorageLevel(true,true,false,true)
  17.   val MEMORY_AND_DISK_2 =newStorageLevel(true,true,false,true,2)
  18.   val MEMORY_AND_DISK_SER =newStorageLevel(true,true,false,false)
  19.   val MEMORY_AND_DISK_SER_2 =newStorageLevel(true,true,false,false,2)
  20.   val OFF_HEAP =newStorageLevel(false,false,true,false)

2.2 DAG、Stage與任務的生成

      Spark的計算發(fā)生在RDD的action操作,而對action之前的所有transformation,Spark只是記錄下RDD生成的軌跡,而不會觸發(fā)真正的計算。

      Spark內(nèi)核會在需要計算發(fā)生的時刻繪制一張關(guān)于計算路徑的有向無環(huán)圖,也就是DAG。舉個例子,在圖2中,從輸入中邏輯上生成A和C兩個 RDD,經(jīng)過一系列transformation操作,邏輯上生成了F,注意,我們說的是邏輯上,因為這時候計算沒有發(fā)生,Spark內(nèi)核做的事情只是記 錄了RDD的生成和依賴關(guān)系。當F要進行輸出時,也就是F進行了action操作,Spark會根據(jù)RDD的依賴生成DAG,并從起點開始真正的計算。

圖2 邏輯上的計算過程:DAG 

      有了計算的DAG圖,Spark內(nèi)核下一步的任務就是根據(jù)DAG圖將計算劃分成任務集,也就是Stage,這樣可以將任務提交到計算節(jié)點進行真正的 計算。Spark計算的中間結(jié)果默認是保存在內(nèi)存中的,Spark在劃分Stage的時候會充分考慮在分布式計算中可流水線計算(pipeline)的部 分來提高計算的效率,而在這個過程中,主要的根據(jù)就是RDD的依賴類型。根據(jù)不同的transformation操作,RDD的依賴可以分為窄依賴 (Narrow Dependency)和寬依賴(Wide Dependency,在代碼中為ShuffleDependency)兩種類型。窄依賴指的是生成的RDD中每個partition只依賴于父 RDD(s) 固定的partition。寬依賴指的是生成的RDD的每一個partition都依賴于父 RDD(s) 所有partition。窄依賴典型的操作有map, filter, union等,寬依賴典型的操作有g(shù)roupByKey, sortByKey等??梢钥吹?,寬依賴往往意味著shuffle操作,這也是Spark劃分stage的主要邊界。對于窄依賴,Spark會將其盡量劃 分在同一個stage中,因為它們可以進行流水線計算。

圖3 RDD的寬依賴和窄依賴

      我們再通過圖4詳細解釋一下Spark中的Stage劃分。我們從HDFS中讀入數(shù)據(jù)生成3個不同的RDD,通過一系列 transformation操作后再將計算結(jié)果保存回HDFS??梢钥吹竭@幅DAG中只有join操作是一個寬依賴,Spark內(nèi)核會以此為邊界將其前 后劃分成不同的Stage. 同時我們可以注意到,在圖中Stage2中,從map到union都是窄依賴,這兩步操作可以形成一個流水線操作,通過map操作生成的 partition可以不用等待整個RDD計算結(jié)束,而是繼續(xù)進行union操作,這樣大大提高了計算的效率。

圖4 Spark中的Stage劃分 

      Spark在運行時會把Stage包裝成任務提交,有父Stage的Spark會先提交父Stage。弄清楚了Spark劃分計算的原理,我們再結(jié) 合源碼看一看這其中的過程。下面的代碼是DAGScheduler中的得到一個RDD父Stage的函數(shù),可以看到寬依賴為劃分Stage的邊界。

  1. /**
  2.   * Get or create the list of parent stages for a given RDD. The stages will be assigned the
  3.   * provided jobId if they haven't already been created with a lower jobId.
  4.   */
  5.  
  6.   privatedef getParentStages(rdd: RDD[_], jobId:Int):List[Stage]={
  7.     val parents =newHashSet[Stage]
  8.     val visited =newHashSet[RDD[_]]
  9.     // We are manually maintaining a stack here to prevent StackOverflowError
  10.     // caused by recursively visiting
  11.     val waitingForVisit =newStack[RDD[_]]
  12.     def visit(r: RDD[_]){
  13.       if(!visited(r)){
  14.         visited += r
  15.         // Kind of ugly: need to register RDDs with the cache here since
  16.         // we can't do it in its constructor because # of partitions is unknown
  17.         for(dep <- r.dependencies){
  18.           dep match {
  19.             case shufDep:ShuffleDependency[_, _, _]=>
  20.               parents += getShuffleMapStage(shufDep, jobId)
  21.             case _ =>
  22.               waitingForVisit.push(dep.rdd)
  23.           }
  24.         }
  25.       }
  26.     }
  27.  
  28.     waitingForVisit.push(rdd)
  29.     while(!waitingForVisit.isEmpty){
  30.       visit(waitingForVisit.pop())
  31.     }
  32.     parents.toList
  33.   }

      上面提到Spark的計算是從RDD調(diào)用action操作時候觸發(fā)的,我們來看一個action的代碼

      RDD的collect方法是一個action操作,作用是將RDD中的數(shù)據(jù)返回到一個數(shù)組中??梢钥吹?,在此action中,會觸發(fā)Spark上下文環(huán)境SparkContext中的runJob方法,這是一系列計算的起點。

  1. abstractclass RDD[T:ClassTag](
  2.     @transientprivatevar sc:SparkContext,
  3.     @transientprivatevar deps:Seq[Dependency[_]]
  4.   )extendsSerializablewithLogging{
  5.   //….
  6. /**
  7.   * Return an array that contains all of the elements in this RDD.
  8.   */
  9.   def collect():Array[T]={
  10.     val results = sc.runJob(this,(iter:Iterator[T])=> iter.toArray)
  11.     Array.concat(results: _*)
  12.   }
  13. }

      SparkContext擁有DAGScheduler的實例,在runJob方法中會進一步調(diào)用DAGScheduler的runJob方法。在 此時,DAGScheduler會生成DAG和Stage,將Stage提交給TaskScheduler。TaskSchduler將Stage包裝成 TaskSet,發(fā)送到Worker節(jié)點進行真正的計算,同時還要監(jiān)測任務狀態(tài),重試失敗和長時間無返回的任務。整個過程如圖5所示。

圖5 Spark中任務的生成 

2.3 RDD的緩存與容錯

      上文提到,Spark的計算是從action開始觸發(fā)的,如果在action操作之前邏輯上很多transformation操作,一旦中間發(fā)生計 算失敗,Spark會重新提交任務,這在很多場景中代價過大。還有一些場景,如有些迭代算法,計算的中間結(jié)果會被重復使用,重復計算同樣增加計算時間和造 成資源浪費。因此,在提高計算效率和更好支持容錯,Spark提供了基于RDDcache機制和checkpoint機制。

      我們可以通過RDD的toDebugString來查看其遞歸的依賴信息,圖6展示了在spark shell中通過調(diào)用這個函數(shù)來查看wordCount RDD的依賴關(guān)系,也就是它的Lineage.

圖6 RDD wordCount的lineage 

      如果發(fā)現(xiàn)Lineage過長或者里面有被多次重復使用的RDD,我們就可以考慮使用cache機制或checkpoint機制了。

      我們可以通過在程序中直接調(diào)用RDD的cache方法將其保存在內(nèi)存中,這樣這個RDD就可以被多個任務共享,避免重復計算。另外,RDD還提供了 更為靈活的persist方法,可以指定存儲級別。從源碼中可以看到RDD.cache就是簡單的調(diào)用了 RDD.persist(StorageLevel.MEMORY_ONLY)。

  1. /** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
  2.   def persist():this.type = persist(StorageLevel.MEMORY_ONLY)
  3.   def cache():this.type = persist()

      同樣,我們可以調(diào)用RDD的checkpoint方法將其保存到磁盤。我們需要在SparkContext中設(shè)置checkpoint的目錄,否則 調(diào)用會拋出異常。值得注意的是,在調(diào)用checkpoint之前建議先調(diào)用cache方法將RDD放入內(nèi)存,否則將RDD保存到文件的時候需要重新計 算。 

  1.   /**
  2.   * Mark this RDD for checkpointing. It will be saved to a file inside the checkpoint
  3.   * directory set with SparkContext.setCheckpointDir() and all references to its parent
  4.   * RDDs will be removed. This function must be called before any job has been
  5.   * executed on this RDD. It is strongly recommended that this RDD is persisted in
  6.   * memory, otherwise saving it on a file will require recomputation.
  7.   */
  8.   def checkpoint(){
  9.     if(context.checkpointDir.isEmpty){
  10.       thrownewSparkException("Checkpoint directory has not been set in the SparkContext")
  11.     }elseif(checkpointData.isEmpty){
  12.       checkpointData =Some(newRDDCheckpointData(this))
  13.       checkpointData.get.markForCheckpoint()
  14.     }
  15.   }

      Cache機制和checkpoint機制的差別在于cache將RDD保存到內(nèi)存,并保留Lineage,如果緩存失效RDD還可以通過Lineage重建。而checkpoint將RDD落地到磁盤并切斷Lineage,由文件系統(tǒng)保證其重建。

2.4 Spark任務的部署

      Spark的集群部署分為Standalone、Mesos和Yarn三種模式,我們以Standalone模式為例,簡單介紹Spark程序的部 署。如圖7示,集群中的Spark程序運行時分為3種角色,driver, master和worker(slave)。在集群啟動前,首先要配置master和worker節(jié)點。啟動集群后,worker節(jié)點會向master節(jié) 點注冊自己,master節(jié)點會維護worker節(jié)點的心跳。Spark程序都需要先創(chuàng)建Spark上下文環(huán)境,也就是SparkContext。創(chuàng)建 SparkContext的進程就成為了driver角色,上一節(jié)提到的DAGScheduler和TaskScheduler都在driver中運行。 Spark程序在提交時要指定master的地址,這樣可以在程序啟動時向master申請worker的計算資源。Driver,master和 worker之間的通信由Akka支持。Akka 也使用 Scala 編寫,用于構(gòu)建可容錯的、高可伸縮性的Actor 模型應用。關(guān)于Akka,可以訪問其官方網(wǎng)站進行進一步了解,本文不做詳細介紹。

圖7 Spark任務部署

3、更深一步了解Spark內(nèi)核

      了解了Spark內(nèi)核的基本概念和實現(xiàn)后,更深一步理解其工作原理的最好方法就是閱讀源碼。最新的Spark源碼可以從Spark官方網(wǎng)站下載。 源碼推薦使用IntelliJ IDEA閱讀,會自動安裝Scala插件。讀者可以從core工程,也就是Spark內(nèi)核工程開始閱讀,更可以設(shè)置斷點嘗試跟蹤一個任務的執(zhí)行。另外,讀 者還可以通過分析Spark的日志來進一步理解Spark的運行機制,Spark使用log4j記錄日志,可以在啟動集群前修改log4j的配置文件來配 置日志輸出和格式。
 

延伸閱讀:大數(shù)據(jù)閃開,小數(shù)據(jù)到來

數(shù)據(jù)安全有救了!量子操控解決黑客問題

參與評論
回復:
0/300
文明上網(wǎng)理性發(fā)言,評論區(qū)僅供其表達個人看法,并不表明a&s觀點。
0
關(guān)于我們

a&s傳媒是全球知名展覽公司法蘭克福展覽集團旗下的專業(yè)媒體平臺,自1994年品牌成立以來,一直專注于安全&自動化產(chǎn)業(yè)前沿產(chǎn)品、技術(shù)及市場趨勢的專業(yè)媒體傳播和品牌服務。從安全管理到產(chǎn)業(yè)數(shù)字化,a&s傳媒擁有首屈一指的國際行業(yè)展覽會資源以及豐富的媒體經(jīng)驗,提供媒體、活動、展會等整合營銷服務。

免責聲明:本站所使用的字體和圖片文字等素材部分來源于互聯(lián)網(wǎng)共享平臺。如使用任何字體和圖片文字有冒犯其版權(quán)所有方的,皆為無意。如您是字體廠商、圖片文字廠商等版權(quán)方,且不允許本站使用您的字體和圖片文字等素材,請聯(lián)系我們,本站核實后將立即刪除!任何版權(quán)方從未通知聯(lián)系本站管理者停止使用,并索要賠償或上訴法院的,均視為新型網(wǎng)絡碰瓷及敲詐勒索,將不予任何的法律和經(jīng)濟賠償!敬請諒解!
? 2024 - 2030 Messe Frankfurt (Shenzhen) Co., Ltd, All rights reserved.
法蘭克福展覽(深圳)有限公司版權(quán)所有 粵ICP備12072668號 粵公網(wǎng)安備 44030402000264號
用戶
反饋