1 Spark Streaming
Spark Streaming is an extension of the core Spark API(spark core的拓展) that enables scalable(高可用),
high-throughput(高吞吐), fault-tolerant(容错的) stream processing of live data streams(实时数据流).
Spark Streaming主要是把不同数据源的数据实时处理以后落地到外部文件系统。
特点:
低延时
能从错误中高效的恢复:fault-tolerant
能够运行在成百上千的节点
能够将批处理、机器学习、图计算等子框架和Spark Streaming综合起来使用
Spark Streaming不需要独立安装 One stack to rule them all
spark-submit的使用
使用spark-submit来提交我们的spark应用程序运行的脚本(生产)
./spark-submit --master local[2] \
--class org.apache.spark.examples.streaming.NetworkWordCount \
--name NetworkWordCount \
/home/hadoop/app/spark-2.2.0-bin-2.6.0-cdh5.7.0/examples/jars/spark-examples_2.11-2.2.0.jar hadoop000 9999
如何使用spark-shell来提交(测试)
./spark-shell --master local[2] (写成脚本)
/opt/spark/bin/spark-shell --master local[2] (直接运行)
local[2]中为的线程数为2,因为如果使用Receiver本身要占一个线程,所以不能使用local或者local[1]
运行以下代码即可
import org.apache.spark.streaming.{Seconds, StreamingContext}
val ssc = new StreamingContext(sc, Seconds(1))
val lines = ssc.socketTextStream("hadoop000", 9999)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.print()
ssc.start()
ssc.awaitTermination()
工作原理:粗粒度
Spark Streaming接收到实时数据流,把数据按照指定的时间段切成一片片小的数据块,
然后把小的数据块传给Spark Engine处理。
2 StreamingContext
核心概念:
StreamingContext
def this(sparkContext: SparkContext, batchDuration: Duration) = {
this(sparkContext, null, batchDuration)
}
def this(conf: SparkConf, batchDuration: Duration) = {
this(StreamingContext.createNewSparkContext(conf), null, batchDuration)
}
batch interval可以根据你的应用程序需求的延迟要求以及集群可用的资源情况来设置
StreamingContext设置好以后,可以做以下事情:
1.Define the input sources by creating input DStreams.通过创建输入的DStreams来定义输入源
2.Define the streaming computations by applying transformation and output operations to DStreams.
通过对DStreams使用转换和输出操作来定义流计算。
3.Start receiving data and processing it using streamingContext.start().
开始接收数据并处理,使用streamingContext.start()。
4.Wait for the processing to be stopped (manually or due to any error) using streamingContext.awaitTermination().
使用streamingcontext.awaitterminate()来等待停止处理(手动或由于任何错误)。
5.The processing can be manually stopped using streamingContext.stop().
可以使用streamingContext.stop()手动停止处理。
注意点:
1.Once a context has been started, no new streaming computations can be set up or added to it.
一旦context启动以后,流计算的的设置就被定义好了,无法添加新的流计算
2.Once a context has been stopped, it cannot be restarted.
一旦context被停止,不能被重启(stop以后不能start,start方法不能写在stop方法之后)
3.Only one StreamingContext can be active in a JVM at the same time.
在同一时段,一个StreamingContext只能存在于一个JVM中
4.stop() on StreamingContext also stops the SparkContext. To stop only the StreamingContext, set the optional parameter of stop() called stopSparkContext to false.
stop方法可以停止sparkContent,如果仅仅想停止streamingContext而不想停止sparkContent,可以设置stop中的一个参数stopSparkContext为false
5.A SparkContext can be re-used to create multiple StreamingContexts, as long as the previous StreamingContext is stopped (without stopping the SparkContext) before the next StreamingContext is created.
一个SparkContext可以创建多个StreamingContext。
Discretized Streams (DStreams)
持续化的数据流(一系列的rdd)
对DStreams操作算子,其实底层会对DStreams中的每个rdd做相同的操作。
Input Dstreams and Receivers
除了文件系统(file stream)以外,每一个input Dstream都需要关联一个Receiver,Receiver用来从源头接收数据存在
file stream可以直接处理,不需要receiver,例如hdfs中的数据,可以直接用api读取。
注意点:
如果使用Receiver,不要使用local或者local[1](1代表一个线程),因为Receiver会占用一个线程,接收了数据以后就无法处理了。所以如果使用本地模式,设置为local[n],且n要大于receiver的数量。
spark Streaming处理socket数据
词频统计测试:
先在终端机输入:
hostname -f
获取hostname
再输入
nc -lk 9999
再在spark-shell中运行以下代码
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.SparkConf
val sc = new SparkConf()
val ssc = new StreamingContext(sc, Seconds(20)) //Seconds(1)数据按照1秒钟一个批次一次
//args(0)对应主机名即hostname,args(1)对应端口号
//val lines = ssc.socketTextStream(args(0), args(1).toInt)
val lines = ssc.socketTextStream("yjd-dn-50-163.meizu.mz", 9999)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.print()
ssc.start()
ssc.awaitTermination()
在终端机传入参数:
spark spark aaaaaaa aaaaaa
得到结果:
3.sparkstreaming接收kafka数据存入hive(搬运)
object KafkaToHive{
def main(args: Array[String]){
val sparkConf = new SparkConf().setAppName("KafkaToHive")
val sc = new SparkContext(sparkConf)
val ssc = new StringContext(sc,Seconds(60))
// 创建kafka参数
val kafkaParams = Map[String,Object](
//ip为kafka集群ip,端口为集群端口
"bootstrap.servers" -> "ip1:port1,ip2:port2,ip:port3",
"group.id" -> "KafkaToHive_group1", //自定义组名称
"auto.offset.reset" -> "earliest",
"enable.auto.commit" -> "false")
val topics = Array("test1")
val stream = KafkaUtils.createDirectStreaming[String,String](
ssc,PreferConsistent,
Subscribe[String,String](topics,kafkaParms)
stream.foreachRDD(rdd=>{
if(rdd.count>0){
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
//TODO 具体处理逻辑
//写入Hive
//value为实际操作中的结果集,即是//TODO返回的结果集
val subRdd = rdd.sparkContext.parallelize(value)
val sqlContext : SQLContext = new HiveContext(rdd.sparkContext)
sqlContext.setConf("hive.exec.dynamic.partition.mode","nonstrict")
sqlContext.setConf("hive.exec.dynamic.partition","true") sqlContext.sql("use database1")
val tempTable = sqlContext
.read
.format("json")
.json(subRdd)
.select(cols.map(new Column(_)): _*)
.coalesce(1)
.write
.mode(SaveMode.Append)
.insertInto("task_exec_time")
//提交offset
stream.asInstanceOf[CanCommitOffsets].commotAsync(offsetRanges)
}
})
}
Reference
https://blog.csdn.net/weixin_44278340/article/details/85260073