参考官网:http://spark.apache.org/streaming/
Spark Streaming特点
Spark Streaming makes it easy to build scalable fault-tolerant streaming applications.
Spark Streaming使得 去构建可扩展的能容错的流式应用程序 变得容易。
(RDD容错体现在哪些方面?)
特点:
- Ease of Use易用性
可以通过高级别的API操作进行构建应用程序,可以像写批处理(离线处理)的job那样去写Streaming job,比如你会core、sql,在这里很相似。 - Fault Tolerance容错机制
Spark Streaming不需要额外的代码,就可以恢复挂掉的工作流以及操作的状态。 - Spark Integration Spark集成
能够把Streaming和批处理和交互式查询综合起来使用。通过在Spark上运行,Spark流允许您重用相同的代码进行批处理、根据历史数据连接流,或者对流状态运行即席查询。构建强大的交互式应用程序,而不仅仅是分析。比如假如你之前用的是批处理,现在要修改成流式处理,什么业务逻辑代码都不需要改变,那么只要把代码稍微修改一下,改一下输入输出即可。 - 运行模式多种多样,可以从HDFS, Flume, Kafka, Twitter and ZeroMQ上读取数据,也可以自定义数据源,可以跑在standalone上,yarn上等等。
常用的模式是:Flume→消息队列(比如Kafka)→Spark Streaming
Spark Streaming概览
参考官网:http://spark.apache.org/docs/latest/streaming-programming-guide.html
Spark Streaming是Spark core API的扩展,它的底层还是Spark RDD来实现的,它支持对实时数据流进行可横向扩展、高吞吐量、容错的流处理。
既然是数据流,肯定有输入、处理和输出。
输入:Spark Streaming数据可以有很多数据源:Kafka, Flume, Kinesis, or TCP sockets,工作中用的比较多的是Kafka、TCP 。
处理:数据进来后可以被Spark Streaming的引擎处理,这些进来的数据可以被复杂的算法去处理,这些算法是用高级别的函数来表达的,比如: map, reduce, join and window这些函数。
输出:最后被处理后的数据,可以被吐到文件系统、数据库、实时dashboards上去。
另外:在Spark Streaming纸上可以使用机器学习和图计算的处理算法。这也验证了Spark Streaming可以和Spark生态圈里的框架做很好的集成,可以混合起来使用。
源可以分为有receiver和没有receiver,后面会讲到。
实质上,Spark Streaming的工作原理如下:Spark Streaming接收实时输入数据流,并将数据分为批(把数据切开,切成一个一个的批次),然后由Spark engine进行处理,最后也是以批次(一批一批的)的形式,产生最终的结果流。(其实就是mini batch微批处理)
这说明Spark Streaming并不是真正的实时处理的框架,它会每隔多少时间比如10秒,批处理一次,微批处理。
对于Spark,可以这样说:Spark是以批处理为准,使用微批来解决实时问题。
而Flink,以Stream实时为主,来解决批处理/离线问题。
上图:一个持续的数据流(就是一个DStream)输入进来,通过Spark Streaming进行设置,比如几秒钟读一次,把数据流按照时间划分为一个一个的批次(就是一个一个的RDD),由Spark engine进行处理,最后以一批一批的输出。
Internally, a DStream is represented as a sequence of RDDs.
Spark Streaming提供了一种高级抽象,它叫做discretized stream 或者 DStream,它是Spark Streaming进行开发的时候一个顶级的接口,DStream代表了持续的数据流(数据会源源不断的过来)。DStreams可以从数据源进行创建,比如 Kafka, Flume, and Kinesis,在其它DStreams上面作用于一个高级别的操作来产生一个DStreams。实质上,一个DStream代表了一个RDD的sequence,就是说一个DStream是由n多个RDD的sequence所构成的。
Spark Streaming:不同的数据源经过Spark Streaming处理之后,将结果输出到某个地方上去。
小知识点:部署了Spark就不需要再单独部署Spark Streaming,Spark Streaming是Spark里的一个模块。
面试:有了storm,你为什么还要去使用Spark Streaming?
Spark Streaming应用场景
比如电商上面,淘宝、京东、天猫等,上面推荐等(也可以使用storm等)。
再比如:公司的系统有很多,系统会采用log4j这样的日志框架,把日志输出,输出的日志分布在各个节点之上,节点有很多很多,整个是个大集群。那么如何把这些日志采集过来,用流处理进行分析?比如从log里面,把error的信息给搜集过来,error又分为好多种,这个时候可以为error打个标签,什么样的error做什么样的处理,根据error发送短信或者邮件,a error发送给这些人,b error发送给那些人。
流处理过程
一般用Flume采集来的数据,可以分为两个方向:
前面Flume通过Kafka sink到Kafka topic是属于Flume,后面Kafka到SparkStreaming,是属于SparkStreaming的内容。
Spark Streaming案例
数据源为TCP socket(演示一下,生产上很少用这种方式),数据内容为word,统计word的数量,然后打印出来。
①
需要添加依赖:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
②
先导入相关的类、隐式转换。
导入包:
import org.apache.spark._
import org.apache.spark.streaming._
import org.apache.spark.streaming.StreamingContext._
③
Spark core RDD里面要有一个SparkContext,SparkSQL DF/DS里面有SparkSession,在Spark Streaming里面要有StreamingContext。
StreamingContext是所有streaming功能的入口点,创建一个StreamingContext,设置成两个执行线程、每秒一个批次。
(spark2.x之后,可以使用统一的SparkSession)
object ExampleStreamingApp {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[2]").setAppName("ExampleStreamingApp")
val ssc = new StreamingContext(conf, Seconds(1))
//TODO业务逻辑。。。。
ssc.start()
ssc.awaitTermination()
}
}
④业务逻辑
package com.ruozedata.spark.com.ruozedata.spark.streaming
import org.apache.spark._
import org.apache.spark.streaming._
import org.apache.spark.streaming.StreamingContext._
//这个作业是一直在跑的,一直在运行的,这个不是离线的,离线是跑完作业就没了,就会停下来
//这个作业要是停掉了,数据就接收不了,就会丢的
object ExampleStreamingApp {
def main(args: Array[String]): Unit = {
//这个master要是2个core
val conf = new SparkConf().setMaster("local[2]").setAppName("ExampleStreamingApp")
val ssc = new StreamingContext(conf, Seconds(10))
//批次的时间是10秒,10秒处理一次
//这个是把server数据源转换成了DStream
val lines = ssc.socketTextStream("hadoop001",9999)
//下面就是之前的wordcount代码
val words = lines.flatMap(_.split(" "))
val pairs = words.map(word => (word, 1))
val wordCounts = pairs.reduceByKey(_ + _)
//把这个DStream产生的每个RDD的前10个元素打印到控制台上
wordCounts.print()
//开始计算
ssc.start()
//等待计算结束
ssc.awaitTermination()
}
}
小知识点:
def socketTextStream(
hostname: String,
port: Int,
//默认存储级别为:内存、磁盘序列化 2 ,这个和Spark core里面不一样
storageLevel: StorageLevel = StorageLevel.MEMORY_AND_DISK_SER_2
): ReceiverInputDStream[String] = withNamedScope("socket text stream") {
socketStream[String](hostname, port, SocketReceiver.bytesToLines, storageLevel)
}
上面运行起来之后,要在命令行启动Netcat,在控制台输入:
//如果没有nc命令,需要yum install 安装一下
[root@hadoop001 ~]# nc -lk 9999
aaa bbb aaa bbb
aaa
bb cc aaa
//这个是时间戳,可以转换为我们平时看到的时间的
-------------------------------------------
Time: 1564322940000 ms
-------------------------------------------
-------------------------------------------
Time: 1564322960000 ms
-------------------------------------------
-------------------------------------------
Time: 1564323020000 ms
-------------------------------------------
(bbb,2)
(,3)
(bb,1)
(cc,1)
(aaa,4)
看页面:http://localhost:4040
下面这个Streaming在调优的时候必须要用到的
Streaming Statistics 流处理统计信息
Running batches of 10 seconds for 9 minutes 32 seconds since 2019/07/28 22:05:09 (58 completed batches, 11 records)
从什么时候开始运行了多少个批次。
从下面可以看到, Input Rate、SocketReceiver-0、Scheduling Delay、Processing Time、Total Delay信息。这些信息很重要的。
在生产上面,如果kafka过来的数据太多,可能会有很大的延迟。在生产上面,想办法要去保证一个批次的作业在一个批次里把它完成。如果保证不了,就是说,这个批次没有完成,那么下个批次又来了,那么后面会越积越多。(可以是kafka限速,或者Spark Streaming限流与背压原理)