之前分析了spark任务提交以及计算的流程,本文将分析在计算过程中数据的读写过程。我们知道:spark抽象出了RDD,在物理上RDD通常由多个Partition组成,一个partition对应一个block。在driver和每个executor端,都有一个Blockmanager。Blockmanager是spark在计算过程中对block进行读写的入口,它屏蔽了在读取数据时涉及到的内存分配,从其他executor端远程获取等具体细节。接下来,本文将以读写block为主线,分析spark在计算过程中读写实际数据的流程。

1,计算数据写流程

1.1,从计算上来说, RDD中的一个Partition对应一个Task。在Task在taskRunner的run方法中调用task.run方法,然后根据计算结果的大小,以不同形式(直接发送或者通过blockManager)将数据发送给driver。

val value = try {
val res = task.run(
taskAttemptId = taskId,
attemptNumber = attemptNumber,
metricsSystem = env.metricsSystem)
threwException = false
res
}

...

// directSend = sending directly back to the driver
val serializedResult: ByteBuffer = {
if (maxResultSize > 0 && resultSize > maxResultSize) {
logWarning(s"Finished $taskName (TID $taskId). Result is larger than maxResultSize " +
s"(${Utils.bytesToString(resultSize)} > ${Utils.bytesToString(maxResultSize)}), " +
s"dropping it.")
ser.serialize(new IndirectTaskResult[Any](TaskResultBlockId(taskId), resultSize))
} else if (resultSize > maxDirectResultSize) {
val blockId = TaskResultBlockId(taskId)
env.blockManager.putBytes(
blockId,
new ChunkedByteBuffer(serializedDirectResult.duplicate()),
StorageLevel.MEMORY_AND_DISK_SER)
logInfo(
s"Finished $taskName (TID $taskId). $resultSize bytes result sent via BlockManager)")
ser.serialize(new IndirectTaskResult[Any](blockId, resultSize))
} else {
logInfo(s"Finished $taskName (TID $taskId). $resultSize bytes result sent to driver")
serializedDirectResult
}
}

1.2,在使用block形式的时候,可以看到调用了blockManager的putBytes方法,在核心实现doPutBytes中,根据存储级别和是否序列化使用memstore和diskstore中不同的不方法进行存储。顾名思义,memstore和diskstore主要就是根据存储级别将对应的block储存到内存或者磁盘。

1.3,memstore的putBytes实现如下。可以看到首先需要通过memoryManager申请存储保存当前block的内存,申请到内存后改block的数据,会以BlockId和SerializeMemoryEntry的键值对,保存在memstore的entries的对象中。关于memoryManager,当前有StaticMemoryManager和UnifiedMemoryManager两种实现。StaticMemoryManager是之前老的实现,将spark计算过程使用的存储内存和计算内存按照总大小的固定比例进行分配。UnifiedMemoryManager是2.x的默认实现,相对StaticMemoryManager,UnifiedMemoryManager中存储和计算的内存是可以动态调整的。也就是说,当计算内存紧张,储存内存空闲的时候,计算内存可以借用存储内存。反之类似。

1.4,在1.3完成当前executor机器完成当前block存储以后,当需要告诉driver时(tellMaster参数),会将该block的状态汇报给driver(reportBlockStatus),通过向dirver发送UpdateBlockInfo消息。driver接收到UpdateBlockInfo消息后,将汇报过来的相关信息保存在BlockManagerMasterEndpoint的blockManagerInfo和blockLocations中。

至此,计算过程写数据的流程完成。

2,计算数据读流程

2.1,话说在TaskRunner运行结束以后,会调用execBackend.statusUpdate,会将该任务的结束的状态通过StatusUpdate的信息发送给driver。

2.2,driver端接收到StatusUpdate消息后,最终将调用TaskResultGetter的enqueueSuccessfulTask方法。在该方法中,对于使用block(即IndirectTaskResult),最终将调用blockManager的getRemoteBytes获取该blockId对应的数据。

2.3,在blockManager的getRemoteBytes方法中,主要逻辑是获取该blockId对应的存储该blockId数据的所有机器位置,通过调用blockTransferService的fetchBlockSync获取具体数据,一旦从一个指定的位置获取到数据,则立即返回。

2.4,fetchBlockSync接着会调用具体实现NettyBlockTransferService中的fetchBlocks方法,在该方法中,将通过OneForOneBlockFetcher发送OpenBlocks消息给指定目标的blockManager,从而对应的streamId等信息,然后通过

client.fetchChunk一次获取每块的数据。

2.5,在提供数据的blockManager端(即server端),接受到消息OpenBlocks消息后,首先根据blockId通过blockManager的getBlockData方法获取对应的数据,然后将该数据和一个streamId奖励对应关系(通过streamManager调用进行)

2.6,在2.4中获取到对应的streamId后,将通过ChunkFetchRequest分块获取数据。server端接受到该消息以后,streamManager将根据streamId和chunkIndex获取对应数据,然后返回给客户端。

至此,计算过程获取block数据的流程结束。

spark block读写流程分析的更多相关文章

  1. S3C6410 SPI全双工读写流程分析(原创)【转】

    转自:http://blog.csdn.net/hustyangju/article/details/21165721 原创博文,知识共享!转载请注明出处:http://blog.csdn.net/h ...

  2. Spark修炼之道(高级篇)——Spark源代码阅读:第十二节 Spark SQL 处理流程分析

    作者:周志湖 以下的代码演示了通过Case Class进行表Schema定义的样例: // sc is an existing SparkContext. val sqlContext = new o ...

  3. hbase读写流程分析

    前言 最近被大佬问到一个问题,hbase查询数据在最坏的场景下需要进行几次rpc,当时就懵了..下面主要对client端代码进行分析.阅读文章和看源码更配~ 读数据 流程总览 1. 从zookeepe ...

  4. spark 启动job的流程分析

    从WordCount開始分析 编写一个样例程序 编写一个从HDFS中读取并计算wordcount的样例程序: packageorg.apache.spark.examples importorg.ap ...

  5. 第一篇:Spark SQL源码分析之核心流程

    /** Spark SQL源码分析系列文章*/ 自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几人 ...

  6. 10.Spark Streaming源码分析:Receiver数据接收全过程详解

    原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/)   在上一篇中介绍了Receiver的整体架构和设计原理,本篇内容主要介绍Receiver在 ...

  7. 【转】HDFS读写流程

    概述开始之前先看看其基本属性,HDFS(Hadoop Distributed File System)是GFS的开源实现. 特点如下: 能够运行在廉价机器上,硬件出错常态,需要具备高容错性流式数据访问 ...

  8. HDFS读写流程(转载)

    概述开始之前先看看其基本属性,HDFS(Hadoop Distributed File System)是GFS的开源实现.特点如下:    能够运行在廉价机器上,硬件出错常态,需要具备高容错性    ...

  9. 如何在spark中读写cassandra数据 ---- 分布式计算框架spark学习之六

    由于预处理的数据都存储在cassandra里面,所以想要用spark进行数据分析的话,需要读取cassandra数据,并把分析结果也一并存回到cassandra:因此需要研究一下spark如何读写ca ...

随机推荐

  1. bash shell和进程

    1 exec builtin 不创建子shell,在原进程的上启动新的脚本,但是它会把老shell的环境清理掉,所以,它从原shell中什么也不继承,在一个干净的环境中执行新的脚本.执行完之后退出当前 ...

  2. 求a + aa + aaa + aaaa + aaaaa ...的值,例如:1 + 11 + 111,2 + 22 + 222 + 2222 + 22222

    #include <stdio.h> unsigned superposition(unsigned m, unsigned n); int main() { printf("1 ...

  3. vmware Ubuntu忘记登录密码

    VMware Workstation 上的Ubuntu 11.10 登录时,用户密码忘记了,以下是我对此问题解决的方法: 1)重新启动Ubtuntu 16 系统,同时长时间按住(或连续点击)esc键进 ...

  4. golang---信号signal

    golang中os/signal包的使用 chenbaoke · 2015-06-17 20:03:59 · 2748 次点击 · 预计阅读时间 1 分钟 · 不到1分钟之前 开始浏览 这是一个创建于 ...

  5. vue实现单选多选反选全选全不选

    单选 当我们用v-for渲染一组数据的时候,我们可以带上index以便区分他们我们这里利用这个index来简单地实现单选 <li v-for="(item,index) in radi ...

  6. HDU1358 Period —— KMP 最小循环节

    题目链接:https://vjudge.net/problem/HDU-1358 Period Time Limit: 2000/1000 MS (Java/Others)    Memory Lim ...

  7. [置顶] SQL Server 2005 双机热备的实现

    [置顶] SQL Server 2005 双机热备的实现 分类: SQLSERVER2011-08-24 21:25 901人阅读 评论(0) 收藏 举报 sql servermicrosoftsql ...

  8. Asp与Asp.Net

    1.Asp是什么? ASP是动态服务器页面(Active Server Page)的英文缩写.是微软公司开发的代替CGI脚本程序的一种应用,它可以与数据库和其它程序进行交互,是一种简单.方便的编程工具 ...

  9. golang OOP面向对象

    摘自:http://www.01happy.com/golang-oop/ golang中并没有明确的面向对象的说法,实在要扯上的话,可以将struct比作其它语言中的class. 类声明 1 2 3 ...

  10. 【摘抄】u3d|unity学习教程与方法

    小编,因为下面这句话,还是决定,只摘链接地址(来自百度经验): http://jingyan.baidu.com/article/19192ad820f17be53e570715.html 经验内容仅 ...