1.流批对比
Spark Streaming类似于Apache Storm,用于流式数据的处理。根据其官方文档介绍,Spark Streaming有高吞吐量和容错能力强等特点.
2.输入位置和输出位置
和Spark基于RDD的概念很相似,Spark Streaming使用离散化流(discretized stream)作为抽象表示,叫作DStream。DStream 是随时间推移而收到的数据的序列。在内部,每个时间区间收到的数据都作为 RDD 存在,而 DStream 是由这些 RDD 所组成的序列(因此 得名“离散化”)。
Spark Streaming的编程抽象是离散化流,也就是DStream。它是一个 RDD 序列,每个RDD代表数据流中一个时间片内的数据。
3.基于receiver的streaming作业执行流程
4.什么是DStreams
Discretized Stream是Spark Streaming的基础抽象,代表持续性的数据流和经过各种Spark原语操作后的结果数据流。在内部实现上,DStream是一系列连续的RDD来表示。每个RDD含有一段时间间隔内的数据,
Spark Streaming把一系列连续的批次称为Dstream。
5.Dstream的特点:
就是将流式计算分解成为一系列确定并且较小的批处理作业
可以将失败或者执行较慢的任务在其他节点上并行执行
有较强的的容错能力,基于lineage
Dstream内含high-level operations进行处理
Dstream内部实现为一个RDD序列
6.DStreams输入
Spark Streaming原生支持一些不同的数据源。一些“核心”数据源已经被打包到Spark Streaming 的 Maven 工件中,而其他的一些则可以通过 spark-streaming-kafka 等附加工件获取。
Steaming的数据源和接收器
数据源:基本数据源/高级数据源
基本数据源:socket、file,akka actoer。Steaming中自带了该数据源的读取API
高级数据源:kafka,flume,kinesis,Twitter等其他的数据。必须单独导入集成的JAR包spark-streaming-[projectname]_2.10
接收器:
Socket数据源,有一个接收器,用户接受Socket的数据。每一个接收器必须占用一个cores来接收数据。如果资源不足,那么任务就会处于等待状态。
CPU 核心:
每个接收器都以 Spark 执行器程序中一个长期运行的任务的形式运行,因此会占据分配给应用的 CPU 核心。此外,我们还需要有可用的 CPU 核心来处理数据。这意味着如果要运行多个接收器,就必须至少有和接收器数目相同的核心数,还要加上用来完成计算所需要的核心数。例如,如果我们想要在流计算应用中运行 10 个接收器,那么至少需要为应用分配 11 个 CPU 核心。所以如果在本地模式运行,不要使用local或者local[1]。
7.Receiver读取kafka数据特点
在spark的executor中,启动一个接收器,专门用于读取kafka的数据,然后存入到内存中,供sparkStreaming消费
1、为了保证数据0丢失,WAL,数据会保存2份,有冗余
2、Receiver是单点读数据,如果挂掉,程序不能运行
3、数据读到executor内存中,增大了内存使用的压力,如果消费不及时,会造成数据积压
如下图:
还有几个需要注意的点:
1、Kafka中topic的partition与Spark Streaming中生成的RDD的partition无关,因此,在KafkaUtils.createStream()中,增加某个topic的partition的数量,只会增加单个Receiver消费topic的线程数,也就是读取Kafka中topic partition的线程数量,它不会增加Spark在处理数据时的并行性。
2、可以使用不同的consumer group和topic创建多个Kafka输入DStream,以使用多个receiver并行接收数据。
3、如果已使用HDFS等复制文件系统启用了“预读日志”,则接收的数据已在日志中复制。因此,输入流的存储级别的存储级别StorageLevel.MEMORY_AND_DISK_SER(即,使用KafkaUtils.createStream(…, StorageLevel.MEMORY_AND_DISK_SER))。
8.Direct方式
Direct:直连模式,在spark1.3之后,引入了Direct方式。不同于Receiver的方式,Direct方式没有receiver这一层,其会周期性的获取Kafka中每个topic的每个partition中的最新offsets,并且相应的定义要在每个batch中处理偏移范围,当启动处理数据的作业时,kafka的简单的消费者api用于从kafka读取定义的偏移范围 。其形式如下图:
这种方法相较于Receiver方式的优势在于:
1、简化的并行:在Receiver的方式中我们提到创建多个Receiver之后利用union来合并成一个Dstream的方式提高数据传输并行度。而在Direct方式中,Kafka中的partition与RDD中的partition是一一对应的并行读取Kafka数据,这种映射关系也更利于理解和优化。
2、高效:在Receiver的方式中,为了达到0数据丢失需要将数据存入Write Ahead Log中,这样在Kafka和日志中就保存了两份数据,浪费!而第二种方式不存在这个问题,只要我们Kafka的数据保留时间足够长,我们都能够从Kafka进行数据恢复。
3、精确一次:在Receiver的方式中,使用的是Kafka的高阶API接口从Zookeeper中获取offset值,这也是传统的从Kafka中读取数据的方式,但由于Spark Streaming消费的数据和Zookeeper中记录的offset不同步,这种方式偶尔会造成数据重复消费。而第二种方式,直接使用了简单的低阶Kafka API,Offsets则利用Spark Streaming的checkpoints进行记录,消除了这种不一致性。
请注意,此方法的一个缺点是它不会更新Zookeeper中的偏移量,因此基于Zookeeper的Kafka监视工具将不会显示进度。但是,您可以在每个批处理中访问此方法处理的偏移量,并自行更新Zookeeper。
直连模式特点:tatch time 每隔一段时间,去kafka读取一批数据,然后消费
简化并行度,rdd的分区数量=topic的分区数量
数据存储于kafka中,没有数据冗余
不存在单点问题
效率高
可以实现仅消费一次的语义 exactly-once语义
代码入门
socket模拟实时不间断接收数据
/**
* SparkStreaming的入门案例
* 通过网络socket来模拟实时不断产生数据并处理
* linux的安装:
* yum -y installl nc
* nc -lk 9999启动端口发送数据
* StreamingContext剖析:
* local :是当前程序分配一个工作线程
* local[*] :给当前程序分配可以用工作线程(通常会>=2)
* 这个改动造成程序只接收数据,而不进行处理,那么也就意味着,streaming需要使用线程资源既要接收数据,还有消费数据,而且优先接收数据,接收数据要独占一个线程字段。
*
* 在本地模式下面,去处理receiver到的数据的时候,线程资源最好设置大于1。
*
*/
object Demo1 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("Demo1").setMaster("local[*]")
val batchDuration = Seconds(2)//每2s提交一次sparkstreaming的作业
val sc = new StreamingContext(conf,batchDuration)
//加载外部数据
val value:ReceiverInputDStream[String] = sc.socketTextStream("hadoop003", 9999, storageLevel = StorageLevel.MEMORY_AND_DISK_SER_2)
val ds:DStream[String] = value.flatMap(line => line.split("\\s+"))
val ds1:DStream[(String,Int)] = ds.map(word => (word, 1))
val ds2:DStream[(String,Int)] = ds1.reduceByKey(_ + _)
ds2.print()
/*
start操作,是用来启动streaming程序的计算,如果不执行start操作,程序压根儿不会执行
*/
sc.start()
/*
Adding new inputs, transformations, and output operations after starting a context is not supported
在程序启动之后,也就是start之后,不可以再添加任何的业务逻辑
*/
// ret.print()
/*
如果没有awaitTermination方法,程序不会持续不断的运行,说白就是把driver设置成为一个后台的守护线程
*/
sc.awaitTermination(