CDH6.0、6.1篇:8、CDH的 hive on spark配置及解析、優化

分三個章節

1、版本展示

2、CDH安裝spark

3、優化配置信息

----------------------分割線----------------------------------------

1、版本展示

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

1.所有版本:https://www.scala-lang.org/download/all.html

2.11.8版本:https://www.scala-lang.org/download/2.11.8.html
2.12.8版本:

tar -zxvf scala-2.12.8.tgz
mv scala-2.12.8 scala
scp -r /root/scala root@node2:/root
scp -r /root/scala root@node3:/root

2.配置環境變量,將scala加入到PATH中:

vim /etc/profile
主要添加藍色字體處 
export PATH=$PATH:$JAVA_HOME/bin:/root/scala/bin
或者
PATH=$JAVA_HOME/bin:$PATH:/root/scala/bin
export JAVA_HOME CLASSPATH PATH
source /etc/profile

3.scala的命令行模式:

輸入 scala ,執行1+1,輸出結果2

2、CDH 安裝 spark

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

1.spark的命令行模式

1.第一種進入方式:執行 pyspark進入,執行exit()退出
	1.注意報錯信息:java.lang.IllegalArgumentException: 
	Required executor memory (1024+384 MB) is above the (最大閾值)max threshold (1024 MB) of this cluster! 
	表示 執行器的內存(1024+384 MB) 大於 最大閾值(1024 MB)
	Please check the values of 'yarn.scheduler.maximum-allocation-mb' and/or'yarn.nodemanager.resource.memory-mb'

在這裏插入圖片描述在這裏插入圖片描述

2.初始化RDD的方法

		本地內存中已經有一份序列數據(比如python的list),可以通過sc.parallelize去初始化一個RDD。
		當執行這個操作以後,list中的元素將被自動分塊(partitioned),並且把每一塊送到集羣上的不同機器上。

1.第一種進入方式:

import pyspark from pyspark 
import SparkContext as sc from pyspark 
import SparkConf
conf=SparkConf().setAppName("miniProject").setMaster("local[*]")
#任何Spark程序都是SparkContext開始的,SparkContext的初始化需要一個SparkConf對象,SparkConf包含了Spark集羣配置的各種參數(比如主節點的URL)。
#初始化後,就可以使用SparkContext對象所包含的各種方法來創建和操作RDD和共享變量。
#Spark shell會自動初始化一個SparkContext(在Scala和Python下可以,但不支持Java)。
#getOrCreate表明可以視情況新建session或利用已有的session
sc=SparkContext.getOrCreate(conf) 

# 利用list創建一個RDD;使用sc.parallelize可以把Python list,NumPy array或者Pandas Series,Pandas DataFrame轉成Spark RDD。
rdd = sc.parallelize([1,2,3,4,5])
rdd  打印 ParallelCollectionRDD[0] at parallelize at PythonRDD.scala:195

# getNumPartitions() 方法查看list被分成了幾部分
rdd.getNumPartitions()  打印結果:2
# glom().collect()查看分區狀況
rdd.glom().collect() 打印結果: [[1, 2], [3, 4, 5]] 

2.第二種進入方式:
可直接執行 spark-shell,也可以執行 spark-shell --master local[2]
多線程方式:運行 spark-shell --master local[N] 讀取 linux本地文件數據
通過本地 N 個線程跑任務,只運行一個 SparkSubmit 進程
利用 spark-shell --master local[N] 讀取本地數據文件實現單詞計數
master local[N]:採用本地單機版的來進行任務的計算,N是一個正整數,它表示本地採用N個線程來進行任務的計算,會生成一個SparkSubmit進程
3.需求:
讀取本地文件,實現文件內的單詞計數。
本地文件 /root/scala/words.txt 內容如下:
hello me
hello you
hello her
4.編寫 scala 代碼:
此處應使用spark-shell --master local[2]進行操作,如果使用spark-shell會報錯

sc.textFile("file:///root///scala///words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
輸出
 res0: Array[(String, Int)] = Array((hello,3), (me,1), (you,1), (her,1))

在hive中執行 select * from 表名;即能運行 hive on spark引擎進行計算,yarn的web UI頁面中,點擊對應運行的spark程序查看運行信息和報錯信息

如果再執行 hive on spark任務時出現以下錯誤信息(要看該yarn任務程序對應的日誌信息):

ERROR client.RemoteDriver: Failed to start SparkContext: java.lang.IllegalArgumentException: Executor memory 456340275 must be at least 471859200. 
	Please increase executor memory using the --executor-memory option or spark.executor.memory in Spark configuration

解決:在 Hive中 搜索 spark.executor.memory 進行配置到可使用的範圍大小
在這裏插入圖片描述

  • 1.運行hive on spark的sql語句進行計算時,報錯信息可在yarn的web UI頁面中,點擊對應運行的spark程序查看運行信息和報錯信息
  • 2.如果spark程序沒有成功運行結束而導致永遠卡在運行任務中而不結束時,可以使用 yarn application -kill 命令 加上 程序ID 進行結束某程序

在這裏插入圖片描述殺死程序的命令:yarn application -kill 程序的ID
因爲/usr/bin/yarn 已經存在,所以不需要執行下面的創建軟連接的操作
cd /opt/cloudera/parcels/CDH-6.0.0-1.cdh6.0.0.p0.537114/lib/hadoop-yarn/bin
ln -s /opt/cloudera/parcels/CDH-6.0.0-1.cdh6.0.0.p0.537114/lib/hadoop-yarn/bin/yarn /usr/bin/yarn
在這裏插入圖片描述

  • 3.在使用 yarn HA時,運行 hive on yarn 的任務無法得出結果時,並且出現以下錯誤

    Caused by:javax.servlet.ServletException: Could not determine the proxy server for redirection
    問題:無法確定用於重定向的代理服務器
    解決:禁用 YARN HA,即ResourceManager只使用一個主節點,其實一般yarn HA仍然能運行 hive on yarn 的任務並且能得出正常結果,但是還是會報出同樣錯誤
    在這裏插入圖片描述在這裏插入圖片描述

  • 4.當前運行的環境是 YARN HA(node1、node2均部署了ResourceManager)的情況下,執行 hive on spark 的程序,雖然能得出正常執行成功得出結果

但是對應該程序的日誌信息仍然報錯:無法確定用於重定向的代理服務器 Could not determine the proxy server for redirection。
select * from test_tb;
select count(*) from test_tb;
insert into test_tb values(2,‘ushionagisa’);
在這裏插入圖片描述

spark-sql命令操作的數據庫存儲在hdfs文件系統中

在這裏插入圖片描述在這裏插入圖片描述

  • 腳本中定義任務提交的命令:
Default Hive database:hdfs://nameservice1/user/hive/warehouse spark.master:spark://master:7077
/root/spark/bin/spark-sql --master spark://node1:7077 --executor-memory 1g --total-executor-cores 2 --conf spark.sql.warehouse.dir=hdfs://nameservice1/user/hive/warehouse

3、優化配置信息

yarn配置信息

  • 1.Hive默認使用的計算框架是MapReduce,在我們使用Hive的時候通過寫SQL語句,Hive會自動將SQL語句轉化成MapReduce作業去執行
    但是MapReduce的執行速度遠差與Spark。通過搭建一個Hive On
    Spark可以修改Hive底層的計算引擎,將MapReduce替換成Spark,從而大幅度提升計算速度。 接下來就如何搭建Hive
    On Spark展開描述。

  • 2.配置Yarn

    Yarn需要配置兩個參數:
    1.yarn.nodemanager.resource.cpu-vcores:
    可以爲container分配的CPU 內核的數量
    爲每個服務分配一個core,爲操作系統預留2個core,剩餘的可用的core分配給yarn。
    我使用的僞集羣(3個node,每個node8個核core)一共有24個core,留出3個給其他任務使用,剩餘的21個核core分配給yarn,每個節點提供7個核core。

在這裏插入圖片描述2.yarn.nodemanager.resource.memory-mb:
可分配給容器的物理內存大小
設置Yarn內存一共爲3G,每個節點提供1G,根據自己的電腦性能分配多少,應大於1G

在這裏插入圖片描述

  • 3.yarn.scheduler.maximum-allocation-mb:scheduler 調度程序所能申請的最大內存,根據自己的電腦性能分配多少,應大於1G

在這裏插入圖片描述

3.配置Spark以及對應參數解析

 參數項			默認值	參數解釋
spark.executor.instances	無	一個Application擁有的Executor數量。取決於spark.executor.memory + spark.yarn.executor.memoryOverhead
spark.executor.cores	1	單個Executor可用核心數
spark.executor.memory	512m	單個Executor最大內存。
計算大小的公式 yarn.nodemanager.resource.memory-mb *(spark.executor.cores / yarn.nodemanager.resource.cpu-vcores)


spark.executor.memory  		每個執行程序進程使用的內存量 
spark.executor.cores 		每個執行程序的核心數 
spark.yarn.executor.memoryOverhead  在Yarn上運行Spark時,每個執行程序要分配的堆外內存量(以兆字節爲單位)。
這是內存,可以解決諸如VM開銷,插入字符串,其他本機開銷等問題。
除了執行程序的內存之外,啓動執行程序的容器還需要一些額外的內存用於系統進程。
計算大小的公式:spark.executor.memory的15-20%
spark.executor.instances 		分配給每個應用程序的執行程序數 
spark.driver.memory 		分配給遠程Spark上下文(RSC)的內存量。我們建議4GB 
spark.yarn.driver.memoryOverhead 	我們建議400(MB) 

1.spark.executor.cores 單個Executor可用核心數

1.在某些情況下,HDFS客戶端沒有並行處理多個寫請求,在有多個請求競爭資源的時候會出現一個執行程序executor使用過多的core。
儘可能的減少空閒的core的個數,cloudera推薦設置spark.executor.cores爲456,這取決於給yarn分配的資源。
 比如說,因爲我們把21個核core分配給yarn,所以有21個核core可用,那麼我們可以設置爲3,這樣21/3餘數爲0,設置爲4的話會剩餘1個空閒。
設置3個可使得空閒的core儘可能的少。這樣配置之後我們可以最多同時運行7個執行程序executor,每個執行程序executor最多可以運行3個任務(每個核core爲1個任務)。

2.在YARN模式下,工作站上的所有可用內核都是獨立模式和Mesos粗粒度模式。每個執行程序使用的核心數。 

3.Executors Scheduling 執行程序調度
分配給每個執行程序的核心數是可配置的。當spark.executor.cores顯式設置時,如果worker具有足夠的內核和內存,則可以在同一工作程序上啓動來自同一應用程序的多個執行程序executor。否則,每個執行程序默認獲取worker上可用的所有核心,在這種情況下,每個應用程序 在一次調度迭代期間 只能啓動一個執行器executor 。

4.Executor和分區
Executor是一個獨立的JVM進程,每個任務會有獨立的線程來執行,Executor最大可併發任務數量與其擁有的核心數量相同,執行過程中的數據緩存放在Executor的全局空間中。
根據以上我們可以得出:
同一個Executor中執行的任務,可以共享同一個數據緩存。這也是Spark稱之爲Process local級別的數據本地性。
Executor可併發執行的任務數量,與其所擁有的核心數相同。
併發任務之間可能會產生相互干擾,如有些任務佔用內存較大會導致其他併發任務失敗。
Executor都需要註冊到Driver上並與其通信,過多的Executor數量會增加Driver負擔。
在階段劃分爲任務時,會得到與分區數相同的任務數量。減少分區的數量將減少任務數,同時每個任務所處理的計算量會增大。
考慮到任務本身的序列化,發送,運行環境準備,結果收集都需要佔用Driver資源和Executor資源,減少任務數能夠減少此類開銷。
在實踐中,每個Executor可以配置多個核心,從而降低Executor數量,還可以得到更好的數據本地性。
根據所配置的核心數量與分區數據量,可以估計出Executor所需最小內存 = 併發任務數 單分區大小 + 內存緩存分區數 單分區大小。
分區數的配置與具體業務邏輯相關,爲了將計算資源充分利用,可以參考:分區數 併發Job數 >= Executor數 Executor核心數。
其中併發Job數是RDD在調用動作(action)類型的操作時產生的Job,Job之間的階段是沒有依賴關係的因此可併發執行。

2.spark.executor.memory 單個Executor最大內存

在配置executor的內存大小的時候,需要考慮以下因素:
1.增加executor的內存可以優化map join。但是會增加GC的時間。
2.還有一點是要求 spark.executor.memory 
不能超過 yarn.scheduler.maximum-allocation-mb
(scheduler調度程序所能申請的最大內存) 設置的值。

3.配置Driver內存

JVM申請的memory不夠會導致無法啓動SparkContext
		1.spark.driver.memory 當hive運行在spark上時,driver端可用的最大Java堆內存。
		2.spark.yarn.driver.memoryOverhead 每個driver可以額外從yarn請求的堆內存大小。
			spark.yarn.driver.memoryOverhead 加上 spark.driver.memory 就是yarn爲driver端的JVM分配的總內存。
  			Spark在Driver端的內存不會直接影響性能,但是在沒有足夠內存的情況下在driver端強制運行Spark任務需要調整。
		3.SparkContext的重用
			1.有些場景需要一個SparkContext持續接收計算任務,這種場景往往對計算任務的時效性要求較高(秒級別),
			  並且可能會有併發的計算任務(如多用戶提交任務)。這種場景適合採用yarn-client模式,讓Driver位於應用內部,
			  應用可以不斷向Driver提交計算任務,並處理返回結果。這種模式的潛在風險在於Driver和Executor都會長時間持續運行,可能會有內存泄露的問題。
			2.在實踐中,在RDD被persist緩存到內存後,調用unpersist並不能立即釋放內存,而是會等待垃圾回收器對其進行回收。
			  在垃圾回收器的選擇上,建議使用CMS類型的垃圾回收器,用於避免垃圾回收過程中的頓卡現象。
			3.在Driver和Executor的垃圾回收不出問題的情況下,還是可以得到穩定的計算任務性能的。但如果某些情況下計算性能還是隨時間推移而下降,
			  則可以重啓SparkContext以解決問題。因爲重啓SparkContext後Driver和Executor都會全新創建,因此能回到最初的性能。
			  重啓的方法是在當前所有任務都完成後,在應用中調用SparkContext.stop()方法,並移除SparkContext引用,然後創建新的SparkContext。
			4.Driver在啓動時需要將Spark的Jar包上傳到集羣,用於啓動每個Executor。這個jar包的大小約130M。
			  Executor在接收任務時,會將任務所依賴的文件、Jar包傳輸到本地,這裏的jar包是應用包,一般包含了應用的各類依賴一般也得100M,
			  Jar包分發的耗時在10秒左右。在對計算任務時效性要求較高的場景,Jar包分發的10秒將是無法接受的。
			  在這裏可以採用預先分發的方式解決此問題。我們首先將Spark Jar和應用Jar上傳到各個節點的某個相同位置,例如/root/sparkjar。
			5.避免Driver啓動時分發Jar包:
				將Driver機上的SPARK_JAR環境變量設置爲空,避免Jar包上傳動作。
				在yarn-site.xml配置文件中,設置yarn.application.classpath爲spark jar的位置與此項默認值。
			6.避免Task啓動時分發依賴和Jar包:
				將spark.files和spark.jars中的路徑配置爲local:/root/sparkjar的模式,從而讓Executor從本地複製。

4.設置executor個數

1.集羣的executor個數設置由集羣中每個節點的executor個數和集羣的worker個數決定,
		  如果集羣中有3個worker,每個worker有8個核心,則Hive On Spark可以使用的executor最大個數是24個(3 * 8)。
		  Hive的性能受可用的executor的個數影響很明顯,一般情況下,性能和executor的個數成正比,4個executor的性能大約是2個executor性能的一倍,
		  但是性能在executor設置爲一定數量的時候會達到極值,達到這個極值之後再增加executor的個數不會增加性能,反而有可能會爲集羣增加負擔。

		2.動態分配executor:
			spark.executor.instances 一個Application擁有的Executor數量,默認值爲無
  				設置spark.executor.instances到最大值可以使得Spark集羣發揮最大性能。但是這樣有個問題是當集羣有多個用戶運行Hive查詢時會有問題,
				應避免爲每個用戶的會話分配固定數量的executor,因爲executor分配後不能回其他用戶的查詢使用,
				如果有空閒的executor,在生產環境中,計劃分配好executor可以更充分的利用Spark集羣資源。
				Spark允許動態的給Spark作業分配集羣資源,cloudera推薦開啓動態分配。

		3.設置並行度
  			爲了更加充分的利用executor,必須同時允許足夠多的並行任務。在大多數情況下,hive會自動決定並行度,但是有時候我們可能會手動的調整並行度。
			在輸入端,map task的個數等於輸入端按照一定格式切分的生成的數目,Hive On Spark的輸入格式是CombineHiveInputFormat,
			可以根據需要切分底層輸入格式。調整hive.exec.reducers.bytes.per.reducer控制每個reducer處理多少數據。
			但是實際情況下,Spark相比於MapReduce,對於指定的hive.exec.reducers.bytes.per.reducer不敏感。
			我們需要足夠的任務讓可用的executor保持工作不空閒,當Hive能夠生成足夠多的任務,儘可能的利用空閒的executor。

4.配置Hive

1.Hive on Spark的配置大部分即使不使用Hive,也可以對這些參數調優。
	  但是hive.auto.convert.join.noconditionaltask.size這個參數是將普通的join轉化成map join的閾值,這個參數調優對於性能有很大影響。
	  MapReduce和Spark都可以通過這個參數進行調優,但是這個參數在Hive On MR上的含義不同於Hive On Spark。
	2.數據的大小由兩個統計量標識:
		totalSize 磁盤上數據的大小
		rawDataSize 內存中數據的大小
	3.Hive On MapReduce使用的是totalSize,Spark使用rawDataSize。
		數據由於經過一系列壓縮、序列化等操作,即使是相同的數據集,也會有很大的不同,對於Hive On Spark,
		需要設置 hive.auto.convert.join.noconditionaltask.size,將普通的join操作轉化成map join來提升性能,
		集羣資源充足的情況下可以把這個參數的值適當調大,來更多的觸發map join。
		但是設置太高的話,小表的數據會佔用過多的內存導致整個任務因爲內存耗盡而失敗,所有這個參數需要根據集羣的資源來進行調整。
  	4.Cloudera推薦配置兩個額外的配置項:
		hive.stats.fetch.column.stats=true
		hive.optimize.index.filter=true

	5.以下還整理了一些配置項用於hive調優:
		hive.merge.mapfiles=true
		hive.merge.mapredfiles=false
		hive.merge.smallfiles.avgsize=16000000
		hive.merge.size.per.task=256000000
		hive.merge.sparkfiles=true
		hive.auto.convert.join=true
		hive.auto.convert.join.noconditionaltask=true
		hive.auto.convert.join.noconditionaltask.size=20M(might need to increase for Spark, 200M)
		hive.optimize.bucketmapjoin.sortedmerge=false
		hive.map.aggr.hash.percentmemory=0.5
		hive.map.aggr=true
		hive.optimize.sort.dynamic.partition=false
		hive.stats.autogather=true
		hive.stats.fetch.column.stats=true
		hive.compute.query.using.stats=true
		hive.limit.pushdown.memory.usage=0.4 (MR and Spark)
		hive.optimize.index.filter=true
		hive.exec.reducers.bytes.per.reducer=67108864
		hive.smbjoin.cache.rows=10000
		hive.fetch.task.conversion=more
		hive.fetch.task.conversion.threshold=1073741824
		hive.optimize.ppd=true

	6.官方的推薦配置 https://cwiki.apache.org/confluence/display/Hive/Hive+on+Spark%3A+Getting+Started
		mapreduce.input.fileinputformat.split.maxsize=750000000
		hive.vectorized.execution.enabled=true

		hive.cbo.enable=true
		hive.optimize.reducededuplication.min.reducer=4
		hive.optimize.reducededuplication=true
		hive.orc.splits.include.file.footer=false
		hive.merge.mapfiles=true
		hive.merge.sparkfiles=false
		hive.merge.smallfiles.avgsize=16000000
		hive.merge.size.per.task=256000000
		hive.merge.orcfile.stripe.level=true
		hive.auto.convert.join=true
		hive.auto.convert.join.noconditionaltask=true
		hive.auto.convert.join.noconditionaltask.size=894435328
		hive.optimize.bucketmapjoin.sortedmerge=false
		hive.map.aggr.hash.percentmemory=0.5
		hive.map.aggr=true
		hive.optimize.sort.dynamic.partition=false
		hive.stats.autogather=true
		hive.stats.fetch.column.stats=true
		hive.vectorized.execution.reduce.enabled=false
		hive.vectorized.groupby.checkinterval=4096
		hive.vectorized.groupby.flush.percent=0.1
		hive.compute.query.using.stats=true
		hive.limit.pushdown.memory.usage=0.4
		hive.optimize.index.filter=true
		hive.exec.reducers.bytes.per.reducer=67108864
		hive.smbjoin.cache.rows=10000
		hive.exec.orc.default.stripe.size=67108864
		hive.fetch.task.conversion=more
		hive.fetch.task.conversion.threshold=1073741824
		hive.fetch.task.aggr=false
		mapreduce.input.fileinputformat.list-status.num-threads=5
		spark.kryo.referenceTracking=false
		spark.kryo.classesToRegister=org.apache.hadoop.hive.ql.io.HiveKey,org.apache.hadoop.io.BytesWritable,org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch

	7.設置Pre-warming Yarn Container
  		我們使用Hive On Spark的時候,提交第一個查詢時,看到查詢結果可能會有比較長的延遲,但是再次運行相同的SQL查詢,完成速度要比第一個查詢快得多。
		當Spark使用yarn管理資源調度時,Spark executor需要額外的時間來啓動和初始化,在程序運行之前,Spark不會等待所有的executor準備好之後運行,
		所有在任務提交到集羣之後,仍有一些executor處於啓動狀態。在Spark上運行的作業運行速度與executor個數相關,
		當可用的executor的個數沒有達到最大值的時候,作業達不到最大的並行性,所有Hive上提交的第一個SQL查詢會慢。
		如果是在長時間會話這個應該問題影響很小,因爲只有執行第一個SQL的時候會慢,問題不大,但是很多時候我們寫的Hive腳本,
		需要用一些調度框架去啓動(如Oozie)。這時候我們需要考慮進行優化。
		爲了減少啓動時間,我們可以開啓container pre-warming機制,開啓後只有當任務請求的所有executor準備就緒,作業纔會開始運行。
		這樣會提升Spark作業的並行度。
	
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章