Spark写HFile不太建议:
1)一般写HFile是因为数据量很大,才使用这种方式,不然一般的API就可以满足;
2)用Spark写大量数据,中途需要去做排序,需要很大的内存与CPU,这种资源的使用是巨大的。
3)因为Executor内存的限制,CPU的限制,每次能写的数据量是有限的,并不能像MR一样可以写2T的数据或者更多。
4)Spark代码还是很费时的,在排序的时候。MR3个月的数据5个小时可以搞定。Spark一天的数据需要一个小时。可能还会有 GC时长过长,内存不足等问题。算子的优化也很难解决。
注:代码中很多注释是中途遇到的问题以及改善方式。
package com.xxx
import java.text.SimpleDateFormat
import com.xxx.HDFSUtil
import com.xxx.HFileUtil.COLUMN_FAMILY_NAME_LIST
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.Path
import org.apache.hadoop.hbase.{HBaseConfiguration, KeyValue, TableName}
import org.apache.hadoop.hbase.client.{ConnectionFactory, Put}
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.mapred.TableOutputFormat
import org.apache.hadoop.hbase.mapreduce.{HFileOutputFormat2, LoadIncrementalHFiles}
import org.apache.hadoop.hbase.util.Bytes
import org.apache.hadoop.mapreduce.Job
import org.apache.spark.sql.{DataFrame, SparkSession}
import scala.collection.mutable.ListBuffer
/**
* 需求:把历史通用数据,所有Qu ID每五分钟汇总最后一个ID数据为一条,保存于HBase
* 例如: 1573149159 0000000001.... 1573149229 0000000001...
* 1573149160 00000002...
* 汇总:2019/11/08 01:55:00 0000000001...00000002...
* 本代码:
* 1.把所有已配ID统计列出,保存于HDFS
* 2.把ID读于哈希表中,对照数据,分类统计
* 3.按分区读Hive表的HDFS文件,统计每个ID最后一条数据,汇总成一条,存于HBase
*
* @author wang.nengjie
*
*/
object HFileQuFiveMinV2 {
def main(args: Array[String]): Unit = {
// val format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
// //本地模式
// System.setProperty("hadoop.home.dir", "D:\\D\\softs\\hadoop-2.8.1\\hadoop-common-2.2.0-bin-master")
// val warehouseLocation = "/spark-warehouse"
// val spark = SparkSession.builder()
// .appName("QuFiveMin")
// .config("hadoop.home.dir", "D:\\D\\softs\\hadoop-2.8.1\\hadoop-common-2.2.0-bin-master")
// .config("spark.sql.warehouse.dir", warehouseLocation)
// .config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
// .enableHiveSupport() //orc file must be hive support 本地Hive使用调试
// .master("local[*]")
// .getOrCreate()
//集群环境
val instances: Int = args(0).toInt
val cores: Int = args(1).toInt
val spark = SparkSession.builder()
.appName("spark-QuFiveMin-hfile" + "-" + args.mkString("-"))
.config("spark.executor.instances", instances) //executor个数
.config("spark.default.parallelism", 10 * instances * cores) //该参数用于设置每个stage的默认task数量
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.enableHiveSupport()
.getOrCreate()
spark.sparkContext.setLogLevel("ERROR")
// val path = "hdfs://10.44.200.101:8020/user/wang.nengjie/output/output_hdfs_path_charged_today/"
// val path = "hdfs://10.44.200.101:8020/user/xxx/xxx/xxx/funct=007/years=2018/months=01/days=01"
// println("获取目录下的一级文件和目录")
// HDFSUtil.getFilesAndDirs(path).foreach(println)
// println("获取目录下的一级文件")
// HDFSUtil.getFiles(path).foreach(println)
// println("获取目录下的一级目录")
// HDFSUtil.getDirs(path).foreach(println)
// println("获取目录下所有文件")//通过HDFS读数据
// HDFSUtil.getAllFiles(path).foreach(println)
//因为读HDFS,文件比较多,一个个读比较繁琐
//直接Hive SQL 方式,比较方便处理数据
val columFamilyNamePath = "/user/wang.nengjie/input/five_min_qu_data_column_family_name" //有子ID的数据,QuID+子ID作为列名
// val columCommonNamePath =