使用SparkStreaming+Kafka+Flume的实现wordcount一个简单的小项目

使用SparkStreaming+Kafka+Flume的一个简单的小项目

整体架构用Flume采集数据源下沉到Kafak中,再用SparkStreamming对数据做一个简单的WordCount;
下面是具体代码:
1.Flume的conf的配置

#为我们的source channel sink起名
a1.sources=r1
a1.channels=c1
a1.sinks=k1
#指定我们的source收集到数据发送到哪个管道
a1.sources.r1.channels=c1
#指定source的收集策略#exec表示可以执行linux的command命令
a1.sources.r1.type=exec
a1.sources.r1.command=tail -F /root/flume/logs
a1.sources.r1.inputCharset=utf-8
#指定下沉地kafak
a1.sinks.k1.channel = c1
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
#指定topic的
a1.sinks.k1.kafka.topic = wordcount
#指定kafak的集群
a1.sinks.k1.kafka.bootstrap.servers = node-01:9092,node-02:9092,node-03:9092
#指定一批中要处理的数据大小
a1.sinks.k1.kafka.flumeBatchSize = 20
#开启ack机制
a1.sinks.k1.kafka.producer.acks = 1
#指定管道是memory
a1.channels.c1.type=memory

2启动命令:bin/flume-ng agent -c conf -f conf/tailfile_kafak.conf -n a1 -Dflume.root.logger=INFO,console 或者后台启动nohup bin/flume-agent -c conf -f conf/tailfile_kafak.conf -n a1 -Dflume.root.logger=INFO,console >/dev/null 2>&1 &
3执行脚本 while true;do echo ‘word name’ >> logs ; sleep 1 ;done;
4.启动kafak集群 nohup bin/kafka-server-start.sh config/server.properties > /dev/null 2>&1 &
5.编写SparkStreaming的具体代码

package cn.kafka

import kafka.serializer.{Decoder, StringDecoder}
import org.apache.spark.streaming.dstream.{DStream, InputDStream}
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}

import scala.reflect.ClassTag

object Sparkstreamn {
  def main(args: Array[String]): Unit = {
    //指定checkpoint目录,程序挂掉以后第二次启动可以恢复之前的数据
    val checkPointPath="hdfs://node-01:9000/sparkStreamming"
    val streamingContext: StreamingContext = StreamingContext.getOrCreate(checkPointPath, () => {
      val ssc: StreamingContext = createSparkStreamming(checkPointPath,args);
      ssc;
    })
    streamingContext
    //8开启计算
    streamingContext.start()
    streamingContext.awaitTermination()
  }
  /**
    * 创建sparkStreamming
    * @param checkPointPath
    * @return
    */
  def createSparkStreamming(checkPointPath: String,args:Array[String]): StreamingContext = {
    //1.创建sparkconf
    val conf: SparkConf = new SparkConf()
      .setAppName("SparkStreammingKafka_Direct")
      .setMaster("local[2]")
    val sc:SparkContext=new SparkContext(conf)
    sc.setLogLevel("WARN")
    //2.创建streammmingcontext
    val ssc: StreamingContext = new StreamingContext(sc,Seconds(5))

    //3.设置保存点
    ssc.checkpoint(checkPointPath)
    //4.配置kafka的相关参数
    val kafakparams: Map[String, String] =
      Map("metadata.broker.list"->"node-01:9092,node-02:9092,node-03:9092","group.id"->"Kafka_Direct")
    val topics :Set[String]=Set("wordcount")
    //5.创建dstream
    val dstream: InputDStream[(String, String)] = KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder](ssc,kafakparams,topics)
    //6.取出value进行操作s
    val rdd= dstream.map(_._2).flatMap(_.split(" ")).map((_,1))
    val result: DStream[(String, Int)] = rdd.updateStateByKey(updateFunc)
    //7.打印结果
   if(args.length>0){
     result.saveAsTextFiles(args(0))
   }
    else{
      result.print()
    }

    ssc
  }
  /**
    *
    * @param newValue 表示当前正在运行的单词出现的次数
    * @param oldValue 表示当前单词历史出现的次数
    * @return
    */

  def updateFunc (newValue :Seq[Int], oldValue:Option[Int]) :Option[Int] = {
    //getOrElse表示有的话使用历史单词的个数,没有的话给默认值0
    val newCount =oldValue.getOrElse(0)+newValue.sum
    Some(newCount)

  }


}

6.将程序打成jar包提交到spark中执行:bin/spark-submit --master spark://node-01:7077,node-02:7077,node-03:7077 --executor-memory 1g --total-executor-cores 1 --class cn.kafka.Sparkstreamn /root/sparkStreming-1.0-SNAPSHOT.jar /sparkstreamming
7.通过webui界面访问:node-01:4040,结果如图所示
在这里插入图片描述

总结:
1.kafka和sparkStreamming整合
kafka作为一个实时的分布式消息队列,实时的生产和消费消息,这里我们可以利用SparkStreaming实时地读取kafka中的数据,然后进行相关计算。
在Spark1.3版本后,KafkaUtils里面提供了两个创建dstream的方法,一种为KafkaUtils.createDstream,另一种为KafkaUtils.createDirectStream。
(1)KafkaUtils.createDstream(ssc, [zk], [group id], [per-topic,partitions] ) 使用了receivers接收器来接收数据,利用的是Kafka高层次的消费者api,对于所有的receivers接收到的数据将会保存在Spark executors中,然后通过Spark Streaming启动job来处理这些数据,默认会丢失,可启用WAL日志,它同步将接受到数据保存到分布式文件系统上比如HDFS。 所以数据在出错的情况下可以恢复出来 。
(2)KafkaUtils.createDirectStream方式
这种方式不同于Receiver接收数据,它定期地从kafka的topic下对应的partition中查询最新的偏移量,再根据偏移量范围在每个batch里面处理数据,Spark通过调用kafka简单的消费者Api(低级api)读取一定范围的数据。
2.遇到的问题在向spark提交任务时没有开启hdfs,导致无法启动

本人是个菜鸟只是简单的实现,如果有不正确的地方请指出

猜你喜欢

转载自blog.csdn.net/qq_43227570/article/details/82817882
今日推荐