通过源码呈现 Spark Streaming 的底层机制。

  1. 初始化与接收数据
  Spark Streaming 通过分布在各个节点上的接收器,缓存接收到的流数据,并将流数 据 包 装 成 Spark 能 够 处 理 的 RDD 的 格 式, 输 入 到 Spark Streaming, 之 后 由 Spark
Streaming 将作业提交到 Spark 集群进行执行,如图 1 所示。
  

            图 1  Spark Streaming 执行模型

  初始化的过程主要可以概括为两点:
  1)调度器的初始化。
  调度器调度 Spark Streaming 的运行,用户可以通过配置相关参数进行调优。
  2)将输入流的接收器转化为 RDD 在集群进行分布式分配,然后启动接收器集合中的每个接收器。
  针对不同的数据源, Spark Streaming 提供了不同的数据接收器,分布在各个节点上的每个接收器可以认为是一个特定的进程,接收一部分流数据作为输入。
  用户也可以针对自身生产环境状况,自定义开发相应的数据接收器。
  如图 2 所示,接收器分布在各个节点上。通过下面代码,创建并行的、在不同Worker 节点分布的 receiver 集合。

val tempRDD =
if (hasLocationPreferences) {
val receiversWithPreferences = receivers.map(r => (r,
Seq(r.preferredLocation.get)))
ssc.sc.makeRDD[Receiver[_]](receiversWithPreferences)
} else {
// 在这里创造 RDD 相当于进入 SparkContext.makeRDD
// 此处将 receivers 的集合作为一个 RDD 进行分区 RDD[Receiver]
// 即使是只有一个输入流,按照这个分布式也是流的输入端在 worker 而不再 Master

// 将 receivers 的集合打散,然后启动它们

ssc.sparkContext.runJob(tempRDD, startReceiver)

}

              图  2 Spark Streaming 接收器

  2. 数据接收与转化
  在上面的“初始化与接收数据”部分中已经介绍过, receiver 集合转换为 RDD,在集群上分布式地接收数据流。那么每个 receiver 是怎样接收并处理数据流的呢?读者可以通过图 3,对输入流的处理有一个全面的了解。图 3为 Spark Streaming 数据接收与转化的示意图。
  图 3 的主要流程如下。
  1)数据缓冲:在 receiver 的 receive 函数中接收流数据,将接收到的数据源源不断地放入到 BlockGenerator.currentBuffer。
  2)缓冲数据转化为数据块:在 BlockGenerator 中有一个定时器(RecurringTimer),将 当 前 缓 冲 区 中 的 数 据 以 用 户 定 义 的 时 间 间 隔 封 装 为 一 个 数 据 块 Block, 放 入 到
BlockGenerator 的 blocksForPush 队列中(这个队列)。
  3)数据块转化为 Spark 数据块:在 BlockGenerator 中有一个 BlockPushingThread线程,不断地将 blocksForPush 队列中的块传递给 BlockManager,让 BlockManager 将
数据存储为块。 BlockManager 负责 Spark 中的块管理。
  4)元数据存储:在 pushArrayBuffer 方法中还会将已经由 BlockManager 存储的元数据信息(例如: Block 的 id 号)传递给 ReceiverTracker, ReceiverTracker 会将存储的
blockId 放到对应 StreamId 的队列中。

                  图 3 Spark Streaming 数据接收与转化

  图中部分组件的作用如下:
‰   KeepPushingBlocks:调用此方法持续写入和保持数据块。
‰   pushArrayBuffer:调用 pushArrayBuffer 方法将数据块存储到 BlockManager 中。
‰   reportPushedBlock:存储完成后汇报数据块信息到主节点。
‰   receivedBlockInfo( Meta Data):已经接收到的数据块元数据记录。
‰   streamId:数据流 Id。
‰   BlockInfo:数据块元数据信息。
‰   BlockManager.put:数据块存储器写入备份数据块到其他节点。
‰   Receiver :数据块接收器,接收数据块。
‰   BlockGenerator:数据块生成器,将数据缓存生成 Spark 能处理的数据块。
‰   BlockGenerator.currentBuffer :缓存网络接收的数据记录,等待之后转换为 Spark的数据块。
‰   BlockGenerator.blocksForPushing :将一块连续数据记录暂存为数据块,待后续转换为 Spark 能够处理的 BlockManager 中的数据块(A Block As a BlockManager’s Block)。
‰   BlockGenerator.blockPushingThread:守护线程负责将数据块转换为 BlockManager中数据块。
‰   ReceiveTracker:输入数据块的元数据管理器,负责管理和记录数据块。
‰   BlockManager: Spark 数据块管理器,负责数据块在内存或磁盘的管理。
‰   RecurringTimer:时间触发器,每隔一定时间进行缓存数据的转换。

  上面的过程中涉及最多的类就是 BlockGenerator,在数据转化的过程中其扮演者不可或缺的角色。

private[streaming] class BlockGenerator(
listener: BlockGeneratorListener,
receiverId: Int,
conf: SparkConf
) extends Logging

3. 生成 RDD 与提交 Spark Job
  Spark Streaming 根据时间段,将数据切分为 RDD,然后触发 RDD 的 Action 提交 Job, Job 被 提 交 到 Job Manager 中 的 Job Queue 中 由 Job Scheduler 调 度, 之 后
Job Scheduler 将 Job 提交到 Spark 的 Job 调度器,然后将 Job 转换为大量的任务分发给 Spark 集群执行,如图 4 所示。

                图 4    Spark Streaming 调度模型

  Job generator 中通过下面的方法生成 Job 进行调度和执行。
从下面的代码可以看出 job 是从 outputStream 中生成的,然后再触发反向回溯执行
整个 DStream DAG,类似 RDD 的机制。

private def generateJobs(time: Time) {
SparkEnv.set(ssc.env)
Try(graph.generateJobs(time)) match {
case Success(jobs) =>
// 获取输入数据块的元数据信息
val receivedBlockInfo = graph.getReceiverInputStreams.map { stream =>
. . .
}.toMap
jobScheduler.submitJobSet(JobSet(time, jobs, receivedBlockInfo))
case Failure(e) =>
jobScheduler.reportError("Error generating jobs for time " + time, e)
}
eventActor !DoCheckpoint(time)
}
// 下 面 进 入 JobScheduler 的 submitJobSet 方 法 一 探 究 竟, JobScheduler 是 整 个 Spark
Streaming 调度的核心组件
def submitJobSet(jobSet: JobSet) {
. . .
jobSets.put(jobSet.time, jobSet)
jobSet.jobs.foreach(job => jobExecutor.execute(new JobHandler(job)))
. . .
}
// 进入 Graph 生成 job 的方法, Graph 本质是 DStreamGraph 类生成的对象
final private[streaming] class DStreamGraph extends Serializable with

Logging {
def generateJobs(time: Time): Seq[Job] = {
. . .
private val inputStreams = new ArrayBuffer[InputDStream[_]]()
private val outputStreams = new ArrayBuffer[DStream[_]]()
. . .
val jobs = this.synchronized {
outputStreams.flatMap(outputStream => outputStream.generateJob(time))
. . .
}
// outputStreams 中的对象是 DStream,下面进入 DStream 的 generateJob 一探究竟
private[streaming] def generateJob(time: Time): Option[Job] = {
getOrCompute(time) match {
case Some(rdd) => {
val jobFunc = () => {
val emptyFunc = { (iterator: Iterator[T]) => {} }
// 此处相当于针对每个时间段生成的一个 RDD,会调用 SparkContext 的方法 runJob 提交 Spark 的一
个 Job
context.sparkContext.runJob(rdd, emptyFunc)
}
Some(new Job(time, jobFunc))
}
case None => None
}
}
// 在 DStream 算是父类,一些具体的 DStream 例如 SocketInputStream 等的类的父类可以通过
SocketInputDStream 看是如何通过上面的 getOrCompute 生成 RDD 的
private[streaming] def getOrCompute(time: Time): Option[RDD[T]] = {
generatedRDDs.get(time) match {
. . .
case None => {
if (isTimeValid(time)) {
// Dstream 是个父类,这里代表的是子类的 compute 方法, DStream 通过 compute 调用用户自定
义函数。当任务执行时,同一个 stage 中的 DStream 函数会串联依次执行
compute(time) match {
. . .
generatedRDDs.put(time, newRDD)
. . .
}
在 SocketInputDStream 的 compute 方法中生成了对应时间片的 RDD:
override def compute(validTime: Time): Option[RDD[T]] = {
if (validTime >= graph.startTime) {
val blockInfo = ssc.scheduler.receiverTracker.getReceivedBlockInfo(id)

receivedBlockInfo(validTime) = blockInfo
val blockIds = blockInfo.map(_.blockId.asInstanceOf[BlockId])
Some(new BlockRDD[T](ssc.sc, blockIds))
} else {
Some(new BlockRDD[T](ssc.sc, Array[BlockId]()))
}
}
  Spark Streaming 在保证实时处理的要求下还能够保证高吞吐与容错性。用户的数据分析中很多情况下也存在需要分析图数据,运行图算法,通过 GraphX 可以简便地开发分布式图分析算法。

Spark Streaming 原理剖析的更多相关文章

  1. .Spark Streaming(上)--实时流计算Spark Streaming原理介

    Spark入门实战系列--7.Spark Streaming(上)--实时流计算Spark Streaming原理介绍 http://www.cnblogs.com/shishanyuan/p/474 ...

  2. Spark入门实战系列--7.Spark Streaming(上)--实时流计算Spark Streaming原理介绍

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Spark Streaming简介 1.1 概述 Spark Streaming 是Spa ...

  3. 实时流计算Spark Streaming原理介绍

    1.Spark Streaming简介 1.1 概述 Spark Streaming 是Spark核心API的一个扩展,可以实现高吞吐量的.具备容错机制的实时流数据的处理.支持从多种数据源获取数据,包 ...

  4. Update(Stage4):Spark Streaming原理_运行过程_高级特性

    Spark Streaming 导读 介绍 入门 原理 操作 Table of Contents 1. Spark Streaming 介绍 2. Spark Streaming 入门 2. 原理 3 ...

  5. Spark Streaming原理简析

    执行流程 数据的接收 StreamingContext实例化的时候,需要传入一个SparkContext,然后指定要连接的spark matser url,即连接一个spark engine,用于获得 ...

  6. Spark 以及 spark streaming 核心原理及实践

    收录待用,修改转载已取得腾讯云授权 作者 | 蒋专 蒋专,现CDG事业群社交与效果广告部微信广告中心业务逻辑组员工,负责广告系统后台开发,2012年上海同济大学软件学院本科毕业,曾在百度凤巢工作三年, ...

  7. MapReduce/Hbase进阶提升(原理剖析、实战演练)

    什么是MapReduce? MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算.概念"Map(映射)"和"Reduce(归约)",和他们 ...

  8. Spark Streaming流式处理

    Spark Streaming介绍 Spark Streaming概述 Spark Streaming makes it easy to build scalable fault-tolerant s ...

  9. Spark集群基础概念 与 spark架构原理

    一.Spark集群基础概念 将DAG划分为多个stage阶段,遵循以下原则: 1.将尽可能多的窄依赖关系的RDD划为同一个stage阶段. 2.当遇到shuffle操作,就意味着上一个stage阶段结 ...

随机推荐

  1. cas单点登出

    由于项目需求要实现单点登出需要在网上找了N久终于实现单点登出. 使用cas-server-core-3.3.3.jar(CAS Server 3.3.3) 使用cas-client-core-3.1. ...

  2. Java基础——关键字

    volatile 用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值.volatile很容易被误用,用来进行原子性操作. 对于volatile修饰的变量,jvm虚拟机只 ...

  3. Effective C++学习笔记 条款07:为多态基类声明virtual析构函数

    一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...

  4. uva12034Race

    递推,组合. 考虑第一名有i个人,则f[n]=sum(C(n,i)*f[n-i]),递推即可.. #include<cstdio> #include<algorithm> #i ...

  5. UVa 10780 (质因数分解) Again Prime? No Time.

    求mk整除n!,求k的最大值. 现将m分解质因数,比如对于素数p1分解出来的指数为k1,那么n!中能分解出多少个p1出来呢? 考虑10!中2的个数c:1~10中有10/2个数是2的倍数,c += 5: ...

  6. 【 D3.js 高级系列 — 6.0 】 值域和颜色

    在[入门 - 第 10 章]作了一张中国地图,其中各省份的颜色值都是随意赋值的.如果要将一些值反映在地图上,可以利用颜色的变化来表示值的变化. 1. 思路 例如,有值域的范围为: [10, 500] ...

  7. rtp h264注意点(FU-A分包方式说明)

    前写过一篇文章,分析了h264使用rtp进行封包的格式介绍:RTP封装h264.但里面好像没有把拆分以及一些需要注意的情况说清楚,因此这里做补充,也作为自己的备忘(自己记性好像不太好). 关于时间戳, ...

  8. uestc 1722 吴神的表白

    // 这题做的我好难过 不是因为没有思路 而是因为超数据类型范围的事// ax+by=c a,b,c>0// 那么该直线经过 1 2 4三个象限// 2 4 象限的第一整数解肯定是该象限最优解/ ...

  9. 【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

    原文网址:http://blog.csdn.net/joonsheng/article/details/41362499 序 说到自定义UINavigetionController的返回按钮,iOS7 ...

  10. 【原】cocos2d-x 2.0.4 不支持https协议 CURLE_UNSUPPORTED_PROTOCOL

    我们项目组用的cocos2d-x版本还比较老,各种好的功能不能用. 今天就让我遇到一个问题,使用CCHttpClient发送http请求的时候,https协议的不支持,返回失败信息如下 errorco ...