一、代碼優化
1.在數據統計的時候選擇高性能算子。
例如Dataframe使用foreachPartitions將數據寫入數據庫,不要每個record都去拿一次數據庫連接。通常寫法是每個partition拿一次數據庫連接。
/**
* 將統計結果寫入MySQL中
* 代碼優化:
* 在進行數據庫操作的時候,不要每個record都去操作一次數據庫
* 通常寫法是每個partition操作一次數據庫
**/
try {
videoLogTopNDF.foreachPartition(partitionOfRecords => {
val list = new ListBuffer[DayVideoAccessStat]
partitionOfRecords.foreach(info => {
val day = info.getAs[String]("day")
val cmsId = info.getAs[Long]("cmsId")
val times = info.getAs[Long]("times")
list.append(DayVideoAccessStat(day, cmsId, times))
})
StatDao.insertDayVideoTopN(list)
})
}catch{
case e:Exception =>e.printStackTrace()
}
2.寫數據庫的時候,關閉自動提交,不要每條提交一次,自己手動每個批次提交一次。
var connection:Connection = null
var pstmt : PreparedStatement = null
try{
connection = MySQLUtils.getConnection()
connection.setAutoCommit(false)//關閉自動提交
val sql = "insert into day_video_access_topn_stat(day,cms_id,times) values(?,?,?)"
pstmt = connection.prepareStatement(sql)
for(ele <- list){
pstmt.setString(1,ele.day)
pstmt.setLong(2,ele.cmsId)
pstmt.setLong(3,ele.times)
//加入到批次中,後續再執行批量處理 這樣性能會好很多
pstmt.addBatch()
}
//執行批量處理
pstmt.executeBatch()
connection.commit() //手工提交
}catch {
case e :Exception =>e.printStackTrace()
}finally {
MySQLUtils.release(connection,pstmt)
}
3.複用已有的數據。
三個統計方法都是隻要當天的視頻數據,所以在調用方法前過濾出當天視頻數據,緩存到內存中。
然後傳到三個統計方法中使用。
不要在每個統計方法都去做一次相同的過濾。
val logDF = spark.read.format("parquet")
.load("file:///F:\\mc\\SparkSQL\\data\\afterclean")
val day = "20170511"
/**
* 代碼優化:複用已有數據
* 既然每次統計都是統計的當天的視頻,
* 先把該數據拿出來,然後直接傳到每個具體的統計方法中
* 不要在每個具體的統計方法中都執行一次同樣的過濾
*
* 用$列名得到列值,需要隱式轉換 import spark.implicits._
* */
import spark.implicits._
val dayVideoDF = logDF.filter($"day" ===day&&$"cmsType"==="video")
/**
* 將這個在後文中會複用多次的dataframe緩存到內存中
* 這樣後文在複用的時候會快很多
*
* default storage level (`MEMORY_AND_DISK`).
* */
dayVideoDF.cache()
//logDF.printSchema()
//logDF.show()
StatDao.deletaDataByDay(day)
//統計每天最受歡迎(訪問次數)的TopN視頻產品
videoAccessTopNStatDFAPI(spark,dayVideoDF)
//按照地勢統計每天最受歡迎(訪問次數)TopN視頻產品 每個地市只要最後歡迎的前三個
cityAccessTopNStat(spark,dayVideoDF)
//統計每天最受歡迎(流量)TopN視頻產品
videoTrafficsTopNStat(spark,dayVideoDF)
//清除緩存
dayVideoDF.unpersist(true)
二、集羣存儲格式選擇
列式/行式存儲簡介
這裏建議選擇用parquet格式,之前公司中用的也是這種格式。
三、集羣壓縮格式選擇
Hadoop壓縮實現分析
Spark中選擇用哪個方式壓縮文件
SparkSession.builder().config("spark.sql.parquet.compression.codec",snappy).getOrCreate()默認是snappy。
四、參數優化
1.並行度:spark.sql.shuffle.partitions
一個partitions相當於一個task。這是配置當shuffle數據去join或者聚合的時候的partitions的數量。200一般情況下在生產上是不夠的,需要做相應的調整。
調整並行度的方式
bin/spark-submit --class XXX.XXX.XX --name XXX --master local[2] --conf spark.sql.shuffle.partitions=230 XXX.jar
2.不必要的情況下,關閉分區字段類型自動推導