一、代码优化
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格式,之前公司中用的也是这种格式。
三、集群压缩格式选择
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.不必要的情况下,关闭分区字段类型自动推导