Spark Streaming处理kafka的数据落地HDFS

Spark Streaming处理kafka的数据落地HDFS

背景

生产上项目的数据从上游kafka topic下发过来,经过spark Streaming简单清洗处理后,下发到下一个kafka topic中,目前需要将清洗处理好的数据,按小时分区落地到HDFS上。
要求,如果当前落地HDFS的程序断了,能按照消息下发kafka topic 的时间进行分区。

实现思路

1:在下发的kafka topic中加入一个consumer group专门用于落地HDFS的数据。
2:在spark streaming中使用spark sql将数据写入HDFS上,并按topic下发kafka的时间分区。
3:写入后Hive需要能查到数据
4: 需要适当减小小文件的数量,避免namenode压力过大。

代码

需要将hive-site.xml放入resource目录下。
如果是将数据落HDFS需要跨集群,则需要加入core-site.xml和hdfs-site.xml文件

 val messages = KafkaUtils.createDirectStream[String, String](
      sparkStreaming,
      PreferConsistent,
      Subscribe[String, String](topics, kafkaParams)
    )

    messages.foreachRDD{rdd=> {
     val spark = SparkSessionSingleton.getInstance(rdd.sparkContext.getConf)
     val offsetRanges2 = rdd.asInstanceOf[HasOffsetRanges].offsetRanges

      val nowDate =  DateUtils.parseMillisToMinute(System.currentTimeMillis().toString)
      val nowMDH =  (DateUtils.getMon(nowDate),DateUtils.getDay(nowDate),DateUtils.getHour(nowDate))

      val hiveTableLocaton =fileSystem.getUri + "/user/hive/warehouse/kafka.db/hn_location/"
      val isFileAlreadyExsist = fileSystem.exists(new Path(s"${hiveTableLocaton}p_month=${nowMDH._1}/p_day=${nowMDH._2}/p_hour=${nowMDH._3}"))

      spark.createDataFrame(
        rdd.map(x=>{s"${x.value()}@${x.timestamp()}"})
          .map(x => LogUtils.parseLog(x)), LogUtils.getSchema()
      ).coalesce(1).write.format("text").mode(SaveMode.Append) //spark默认的存储格式为parquet
        .partitionBy("p_month","p_day","p_hour").save(hiveTableLocaton)
      //刷分区
      if(!isFileAlreadyExsist) {
        spark.sql(s"ALTER TABLE kafka.hn_location add if not exists partition(p_month='${nowMDH._1}',p_day='${nowMDH._2}',p_hour='${nowMDH._3}')")
      }
      messages.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges2)
    }}

Spark session的获取,其中需要开启对hive的支持,否则在执行语句ALTER TABLE kafka.hn_location add if 会报错显示找不到hn_location这个库的。因为此时并没有正确的加载hive-site.xml,说明当前的spark sql并没有真的接到hive的metaserver上。而是使用的spark默认的metaserver,只有default库。所以必须要开启对hive的支持也就是加上.enableHiveSupport()这句。

object SparkSessionSingleton {
  @transient private var instance: SparkSession = _

  def getInstance(sparkConf: SparkConf): SparkSession = {
    if (instance == null) {
      instance = SparkSession
        .builder
        .config(sparkConf)
        .enableHiveSupport() //开启对hive的支持
        .getOrCreate()
    }
    instance
  }
}

你可能感兴趣的:(Spark,hive,HDFS)