使用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,导致无法启动
本人是个菜鸟只是简单的实现,如果有不正确的地方请指出