總是學了就忘記,spark都學了幾遍了 總是深入不進去 唉 頭疼 這裏再次學習一遍 誰有更好的深入學習spark的方法給推薦推薦
面試了大數據,盤點幾個被問到的問題:
spark一定會把中間結果放在內存嗎?當然不是 可以是內存,也可以是磁盤
spark包括work和master work和master之間的溝通通過網絡RPC進行交流溝通
拷貝到其他節點 for i in {5..7}; do scp -r /bigdata/spark/conf/spark-env.sh node-$i:$PWD; done
spark是移動計算,而不移動數據 因爲大量數據移動成本大
spark是Scala 編寫 spark包本身有Scala編譯器和庫 但spark是運行在jvm上的 需要安裝jdk
利用zookeeper實現高可用集羣 zookeeper用來1選舉 2保存活躍的master信息 3 保存worker的資源信息和資源使用情況(爲了故障切換轉移) 在env.sh中添加export SPARK_DAEMON_JAVA_OPTS="-Dspark .deploy.recoveryMode=ZOOKEEPER xxxzookeeper相關信息" 高可用的spark需要手動啓動另一個(standby)spark-master 並不會隨着spark-all.sh 啓動master
一直搞不懂spark進程之間的關係 下面來理一下:
提交任務的機器(Driver)(spark-submit提交jar包的那個) 有SparkSubmit進程,有CoarseGrainedExecutorBackend(這個是executor,即worker的哦哦用來執行任務的進程),Worker進程(worker機器所在) 任務執行完成後 Executor進程會釋放 jps不在擁有Executor進程
在沒有集羣的時候 master會負責資源調度 保存worker資源情況 根據客戶端submit要求分配資源,即master和worker進行rpc通信,然後worker進程啓動executor(CoarseGrainedExecutorBackend),將分區參數傳遞過去
真正的計算邏輯是在driver端(submit端),生成task,然後通過網絡發送給各個executor進行執行。executor啓動後會主動連接driver,然後driver纔開始生成task。兩者之間的通信當然是通過master到worker進而知道的executor在哪裏
yarn和spark的stondalone對比
resourcemanager 對應 Master 都用來管理子節點和資源調度,接收任務請求
nodeManager 對應 Worker 管理當前節點,並管理子進程
yarnchild 對應 executor 用來運行真正的計算邏輯
applicationMaster用來管理yarnchild,,決定map reduce運行在哪一個yarnchild
yarn還有client用來提交任務 這兩個綜合起來相當於spark的SparkSubmit (提交app,管理度任務的executor並將task提交到executor)
RDD是彈性分佈式數據集,rdd並不存儲真正的數據,只是一個抽象,對rdd操作,會在driver端轉換成task,下發到executor計算分在多臺集羣上的數據
rdd是一個代理,對代理進行操作,會生成task幫助你計算,操作這個代理就像操作本地集合一樣方便
RDD有分區,是通過內部進行指定 分區裏面記錄的是位置變量(以後要讀取哪部分數據),生成的task交給executor,每個分區交給一個task去執行 ,然後task讀取數據去執行相應的操作
aggregate方法,aggregate(0)(_+_ , _+_) 聚合操作,執行操作,每個分區分別執行,返回的順序不一定有序
aggregateByKey(0)(_+_ , _+_) 每個分區局部相加 再全部相加 假如說原RDD(pairRdd)有兩個分區,經過轉換後變成shuffledEdd(也有兩個分區,但分區內容是shuffle後的)
reduceByKey(_+_)
countByKey()
task在executor運算完成後,收集最終的數據到driver端 現在如果收集數據到redis mysql 或者hbase,那麼不應該先collect收集數據到driver端,因爲數據量過大,容易使得driver端崩潰
Rdd 的map方法,真正的在executor中執行的時候,是一條一條的將數據拿出來處理
foldByKey()
filter()
action:
rdd.collectAsMap()
foreach(e =>println(e*100)) 一條一條的拿(一條一條的執行function)
foreachPartition() 每個分區拿(一個分區執行一個function)
combineByKey(x=>x,(m:int,n:int)=>m+n, (a:Int,b:Int)=>a+b) (m+n 是分區聚合 a+b 是全局聚合,key 保持不變,對value操作,最後生成shuffledRdd)
Spark執行流程:
這個圖雖然是到處都有 但真的很重要 理解他 記住他 spark基礎就完全ok了
1構建DAG(所謂的DAG就是描述的一個個RDD的轉換過程)(開始通過SparkContext創建RDD,結束調用runJob(也就是觸發action)就是一個完整的DAG過程了)(有多少個DAG,取決於觸發了多少次action)
2將DAG切分成stage(DAGSheduler)(切分的依據是shuffle),將stage中生成的Task以taskset的形式給TaskSheduler 將多臺機器上具有相同屬性的數據聚合到一臺機器上:shuffle 如果有shuffle,那麼就意味着前面階段產生結果後,才能執行下一個階段,下一個階段要依賴上一個階段的數據,在同一個stage中,會有多個算子,我們稱其爲pipeline
shuffle的含義:父RDD的一個分區中的數據如果給了子RDD中的多個分區(只要存在這種可能,例如款依賴時候如groupbyKey,他也有可能前一個步驟分區全部到下一個步驟的一個分區,但他可能分配到分多個分區,那麼也是shuffle),就是shuffle
寬依賴(shuffle) 窄依賴
rdd1=sc.parallelize(List(("tom",1),("ketty",2),("tom",2))) 這個過程是把一個list shuffle到
不同分區的過程,所以也被分成一個stage
當然並不是所有的join都是寬依賴 如果前面的rdd數據比較規整 不需要shuffle到不同的分區 那麼就是窄依
然後執行完第一個階段後會執行第二個階段的task,同樣是driver端生產task 然後序列化,網絡傳輸到executor端進行反序列化,然後封裝成Runnable實現放到線程池進行處理
對RDD操作實際上是對分區進行操作 ,分區再生成task到executor執行操作