<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>简单之美 &#187; Tag &#187; Spark</title>
	<atom:link href="http://shiyanjun.cn/archives/tag/spark/feed" rel="self" type="application/rss+xml" />
	<link>http://shiyanjun.cn</link>
	<description>简单之美，难得简单，享受简单的唯美。</description>
	<lastBuildDate>Wed, 04 Mar 2026 07:04:53 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.2</generator>
	<item>
		<title>Spark Join 处理流程分析</title>
		<link>http://shiyanjun.cn/archives/1816.html</link>
		<comments>http://shiyanjun.cn/archives/1816.html#comments</comments>
		<pubDate>Tue, 27 Mar 2018 00:04:04 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1816</guid>
		<description><![CDATA[<p>为了更好的分析 Spark Join 处理流程，我们选择具有 Shuffle 操作的示例来进行说明，这比没有 Shuffle 操作的处理流程要复杂一些。本文主要通过实现一个 Join 操作的 Spark 程序，提交运行该程序，并通过 Spark UI 上的各种运行信息来讨论 Spark Join 处理流程。
Spark Join 示例程序
我们先给出一个简单的 Spark Application 程序代码，这里处理的数据使用了 MovieLens 数据集。其中，小表 movies（约 1.4m）、大表 genome-scores（约 323.5m），对这两个表进行 Join 操作。具体的实现代码，如下所示：
上面代码，我们直接将两个表进行 Join 操作（实际更优的做法是：将小表进行 Broadcast 后，再进行连接操作，能够避免昂贵低效的 Shuffle 操作）。我们这么做，主要是为了使程序处理过程中能够进行 Shuffle 操作，从而更深入地理解 Join 操作的内部处理流程。
我们通过如下命令，查看一下输入数据表 genome-scores 表在 HDFS 上存储的 Block 情况，执行如下命令：
可以看到输入数据集的存储情况，如下所示：
通过 RDD 的 toDebugString() 方法，打印调试信息：
上</p>]]></description>
	<p>为了更好的分析 Spark Join 处理流程，我们选择具有 Shuffle 操作的示例来进行说明，这比没有 Shuffle 操作的处理流程要复杂一些。本文主要通过实现一个 Join 操作的 Spark 程序，提交运行该程序，并通过 Spark UI 上的各种运行信息来讨论 Spark Join 处理流程。
Spark Join 示例程序
我们先给出一个简单的 Spark Application 程序代码，这里处理的数据使用了 MovieLens 数据集。其中，小表 movies（约 1.4m）、大表 genome-scores（约 323.5m），对这两个表进行 Join 操作。具体的实现代码，如下所示：

  def main(args: Array[String]): Unit = {
    val sc = new SparkContext()
    // movieId,title,genres
    val movieRdd = sc.textFile(&quot;/data/ml-20m/movies.csv&quot;)
          .filter(line =&gt; !line.startsWith(&quot;movieId&quot;))
          .map(line =&gt;  line.split(&quot;,&quot;))
          .map(a =&gt; (a(0), a(1)))
    // movieId,tagId,relevance
    val scoreRdd = sc.textFile(&quot;/data/ml-20m/genome-sc</p>			<content:encoded><![CDATA[<p>为了更好的分析 Spark Join 处理流程，我们选择具有 Shuffle 操作的示例来进行说明，这比没有 Shuffle 操作的处理流程要复杂一些。本文主要通过实现一个 Join 操作的 Spark 程序，提交运行该程序，并通过 Spark UI 上的各种运行信息来讨论 Spark Join 处理流程。
Spark Join 示例程序
我们先给出一个简单的 Spark Application 程序代码，这里处理的数据使用了 MovieLens 数据集。其中，小表 movies（约 1.4m）、大表 genome-scores（约 323.5m），对这两个表进行 Join 操作。具体的实现代码，如下所示：
上面代码，我们直接将两个表进行 Join 操作（实际更优的做法是：将小表进行 Broadcast 后，再进行连接操作，能够避免昂贵低效的 Shuffle 操作）。我们这么做，主要是为了使程序处理过程中能够进行 Shuffle 操作，从而更深入地理解 Join 操作的内部处理流程。
我们通过如下命令，查看一下输入数据表 genome-scores 表在 HDFS 上存储的 Block 情况，执行如下命令：
可以看到输入数据集的存储情况，如下所示：
通过 RDD 的 toDebugString() 方法，打印调试信息：
上</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1816.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spark Shuffle过程分析：Reduce阶段处理流程</title>
		<link>http://shiyanjun.cn/archives/1804.html</link>
		<comments>http://shiyanjun.cn/archives/1804.html#comments</comments>
		<pubDate>Wed, 28 Feb 2018 14:58:46 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[Spark-2.0.0]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1804</guid>
		<description><![CDATA[<p>Spark在Map阶段调度运行的ShuffleMapTask，最后会生成.data和.index文件，可以通过我的这篇文章 Spark Shuffle过程分析：Map阶段处理流程 了解具体流程和详情。同时，在Executor上运行一个ShuffleMapTask，返回了一个MapStatus对象，下面是ShuffleMapTask执行后返回结果的相关代码片段：
如果ShuffleMapTask执行过程没有发生异常，则最后执行的调用为：
这里返回了一个MapStatus类型的对象，MapStatus的定义如下所示：
其中包含了运行ShuffleMapTask所在的BlockManager的地址，以及后续Reduce阶段每个ResultTask计算需要Map输出的大小（Size）。我们可以看下MapStatus如何创建的，在SortShuffleWriter的write()方法中，可以看到MapStatus的创建，如下代码所示：
继续跟踪可以看到，调用了MapStatus的伴生对象的apply()方法：
uncompressedSizes表示Partition的个数，如果大于2000则创建HighlyCompressedMapStatus对象，否则创建CompressedMapStatus对象，他们具体的实现可以参考源码。
含有Shuffle过程的Spark Application示例
我们先给出一个简单的Spark Applicati</p>]]></description>
	<p>Spark在Map阶段调度运行的ShuffleMapTask，最后会生成.data和.index文件，可以通过我的这篇文章 Spark Shuffle过程分析：Map阶段处理流程 了解具体流程和详情。同时，在Executor上运行一个ShuffleMapTask，返回了一个MapStatus对象，下面是ShuffleMapTask执行后返回结果的相关代码片段：

    var writer: ShuffleWriter[Any, Any] = null
    try {
      val manager = SparkEnv.get.shuffleManager
      writer = manager.getWriter[Any, Any](dep.shuffleHandle, partitionId, context)
      writer.write(rdd.iterator(partition, context).asInstanceOf[Iterator[_ &lt;: Product2[Any, Any]]])
      writer.stop(success = true).get
    } catch {
      case e: Exception =&gt;
        try {
          if (writer != null) {
            writer.stop(success = false)
          }
        } catch {
          case e: Exception =&gt;
            log.debug(&quot;Could not stop writer&quot;, e)
        }
        throw e</p>			<content:encoded><![CDATA[<p>Spark在Map阶段调度运行的ShuffleMapTask，最后会生成.data和.index文件，可以通过我的这篇文章 Spark Shuffle过程分析：Map阶段处理流程 了解具体流程和详情。同时，在Executor上运行一个ShuffleMapTask，返回了一个MapStatus对象，下面是ShuffleMapTask执行后返回结果的相关代码片段：
如果ShuffleMapTask执行过程没有发生异常，则最后执行的调用为：
这里返回了一个MapStatus类型的对象，MapStatus的定义如下所示：
其中包含了运行ShuffleMapTask所在的BlockManager的地址，以及后续Reduce阶段每个ResultTask计算需要Map输出的大小（Size）。我们可以看下MapStatus如何创建的，在SortShuffleWriter的write()方法中，可以看到MapStatus的创建，如下代码所示：
继续跟踪可以看到，调用了MapStatus的伴生对象的apply()方法：
uncompressedSizes表示Partition的个数，如果大于2000则创建HighlyCompressedMapStatus对象，否则创建CompressedMapStatus对象，他们具体的实现可以参考源码。
含有Shuffle过程的Spark Application示例
我们先给出一个简单的Spark Applicati</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1804.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>基于YARN集群构建运行PySpark Application</title>
		<link>http://shiyanjun.cn/archives/1738.html</link>
		<comments>http://shiyanjun.cn/archives/1738.html#comments</comments>
		<pubDate>Wed, 18 Oct 2017 00:40:03 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[人工智能]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[PySpark]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1738</guid>
		<description><![CDATA[<p>Spark Application可以直接运行在YARN集群上，这种运行模式，会将资源的管理与协调统一交给YARN集群去处理，这样能够实现构建于YARN集群之上Application的多样性，比如可以运行MapReduc程序，可以运行HBase集群，也可以运行Storm集群，还可以运行使用Python开发机器学习应用程序，等等。
我们知道，Spark on YARN又分为client模式和cluster模式：在client模式下，Spark Application运行的Driver会在提交程序的节点上，而该节点可能是YARN集群内部节点，也可能不是，一般来说提交Spark Application的客户端节点不是YARN集群内部的节点，那么在客户端节点上可以根据自己的需要安装各种需要的软件和环境，以支撑Spark Application正常运行。在cluster模式下，Spark Application运行时的所有进程都在YARN集群的NodeManager节点上，而且具体在哪些NodeManager上运行是由YARN的调度策略所决定的。
对比这两种模式，最关键的是Spark Application运行时Driver所在的节点不同，而且，如果想要对Driver所在节点的运行环境进行配置，区别很大，但这对于PySpark Application运行</p>]]></description>
	<p>Spark Application可以直接运行在YARN集群上，这种运行模式，会将资源的管理与协调统一交给YARN集群去处理，这样能够实现构建于YARN集群之上Application的多样性，比如可以运行MapReduc程序，可以运行HBase集群，也可以运行Storm集群，还可以运行使用Python开发机器学习应用程序，等等。
我们知道，Spark on YARN又分为client模式和cluster模式：在client模式下，Spark Application运行的Driver会在提交程序的节点上，而该节点可能是YARN集群内部节点，也可能不是，一般来说提交Spark Application的客户端节点不是YARN集群内部的节点，那么在客户端节点上可以根据自己的需要安装各种需要的软件和环境，以支撑Spark Application正常运行。在cluster模式下，Spark Application运行时的所有进程都在YARN集群的NodeManager节点上，而且具体在哪些NodeManager上运行是由YARN的调度策略所决定的。
对比这两种模式，最关键的是Spark Application运行时Driver所在的节点不同，而且，如果想要对Driver所在节点的运行环境进行配置，区别很大，但这对于PySpark Application运行</p>			<content:encoded><![CDATA[<p>Spark Application可以直接运行在YARN集群上，这种运行模式，会将资源的管理与协调统一交给YARN集群去处理，这样能够实现构建于YARN集群之上Application的多样性，比如可以运行MapReduc程序，可以运行HBase集群，也可以运行Storm集群，还可以运行使用Python开发机器学习应用程序，等等。
我们知道，Spark on YARN又分为client模式和cluster模式：在client模式下，Spark Application运行的Driver会在提交程序的节点上，而该节点可能是YARN集群内部节点，也可能不是，一般来说提交Spark Application的客户端节点不是YARN集群内部的节点，那么在客户端节点上可以根据自己的需要安装各种需要的软件和环境，以支撑Spark Application正常运行。在cluster模式下，Spark Application运行时的所有进程都在YARN集群的NodeManager节点上，而且具体在哪些NodeManager上运行是由YARN的调度策略所决定的。
对比这两种模式，最关键的是Spark Application运行时Driver所在的节点不同，而且，如果想要对Driver所在节点的运行环境进行配置，区别很大，但这对于PySpark Application运行</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1738.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>PB 级海量数据服务平台架构设计实践</title>
		<link>http://shiyanjun.cn/archives/1702.html</link>
		<comments>http://shiyanjun.cn/archives/1702.html#comments</comments>
		<pubDate>Tue, 29 Aug 2017 00:10:57 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[开源技术]]></category>
		<category><![CDATA[架构]]></category>
		<category><![CDATA[Hadoop]]></category>
		<category><![CDATA[Spark]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1702</guid>
		<description><![CDATA[<p>基于 PB 级海量数据实现数据服务平台，需要从各个不同的角度去权衡，主要包括实践背景、技术选型、架构设计，我们基于这三个方面进行了架构实践，下面分别从这三个方面进行详细分析讨论：
实践背景
该数据服务平台架构设计之初，实践的背景可以从三个维度来进行说明：当前现状、业务需求、架构需求，分别如下所示：
当前现状
收集了当前已有数据、分工、团队的一些基本情况，如下所示：

数据收集和基础数据加工有专门的 Team 在做，我们是基于收集后并进行过初步加工的基础数据，结合不同行业针对特定数据的需求进行二次加工的。
数据二次加工，会集成基础数据之外的其它有业务属性的数据，比如引入第三方 POI 数据等。
原始数据每天增量大约 30~40TB 左右。
计算集群采用 Spark on YARN 部署模式，大约 400 个节点。
所有数据各种属性、行为信息，都是围绕大约 40亿+ 的移动设备 ID 进行很多倍膨胀，比如每天使用微信 App 的设备的行为信息。
参与该平台的研发人员，对实际数据业务需求了解不会非常深入，因为跨多个行业及其不同数据需求的变化较快。

业务需求
另</p>]]></description>
	<p>基于 PB 级海量数据实现数据服务平台，需要从各个不同的角度去权衡，主要包括实践背景、技术选型、架构设计，我们基于这三个方面进行了架构实践，下面分别从这三个方面进行详细分析讨论：
实践背景
该数据服务平台架构设计之初，实践的背景可以从三个维度来进行说明：当前现状、业务需求、架构需求，分别如下所示：
当前现状
收集了当前已有数据、分工、团队的一些基本情况，如下所示：

数据收集和基础数据加工有专门的 Team 在做，我们是基于收集后并进行过初步加工的基础数据，结合不同行业针对特定数据的需求进行二次加工的。
数据二次加工，会集成基础数据之外的其它有业务属性的数据，比如引入第三方 POI 数据等。
原始数据每天增量大约 30~40TB 左右。
计算集群采用 Spark on YARN 部署模式，大约 400 个节点。
所有数据各种属性、行为信息，都是围绕大约 40亿+ 的移动设备 ID 进行很多倍膨胀，比如每天使用微信 App 的设备的行为信息。
参与该平台的研发人员，对实际数据业务需求了解不会非常深入，因为跨多个行业及其不同数据需求的变化较快。

业务需求
另</p>			<content:encoded><![CDATA[<p>基于 PB 级海量数据实现数据服务平台，需要从各个不同的角度去权衡，主要包括实践背景、技术选型、架构设计，我们基于这三个方面进行了架构实践，下面分别从这三个方面进行详细分析讨论：
实践背景
该数据服务平台架构设计之初，实践的背景可以从三个维度来进行说明：当前现状、业务需求、架构需求，分别如下所示：
当前现状
收集了当前已有数据、分工、团队的一些基本情况，如下所示：

数据收集和基础数据加工有专门的 Team 在做，我们是基于收集后并进行过初步加工的基础数据，结合不同行业针对特定数据的需求进行二次加工的。
数据二次加工，会集成基础数据之外的其它有业务属性的数据，比如引入第三方 POI 数据等。
原始数据每天增量大约 30~40TB 左右。
计算集群采用 Spark on YARN 部署模式，大约 400 个节点。
所有数据各种属性、行为信息，都是围绕大约 40亿+ 的移动设备 ID 进行很多倍膨胀，比如每天使用微信 App 的设备的行为信息。
参与该平台的研发人员，对实际数据业务需求了解不会非常深入，因为跨多个行业及其不同数据需求的变化较快。

业务需求
另</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1702.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spark Shuffle过程分析：Map阶段处理流程</title>
		<link>http://shiyanjun.cn/archives/1655.html</link>
		<comments>http://shiyanjun.cn/archives/1655.html#comments</comments>
		<pubDate>Fri, 26 May 2017 15:13:44 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[Spark-2.0.0]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1655</guid>
		<description><![CDATA[<p>默认配置情况下，Spark在Shuffle过程中会使用SortShuffleManager来管理Shuffle过程中需要的基本组件，以及对RDD各个Partition数据的计算。我们可以在Driver和Executor对应的SparkEnv对象创建过程中看到对应的配置，如下代码所示：
如果需要修改ShuffleManager实现，则只需要修改配置项spark.shuffle.manager即可，默认支持sort和 tungsten-sort，可以指定自己实现的ShuffleManager类。
因为Shuffle过程中需要将Map结果数据输出到文件，所以需要通过注册一个ShuffleHandle来获取到一个ShuffleWriter对象，通过它来控制Map阶段记录数据输出的行为。其中，ShuffleHandle包含了如下基本信息：

shuffleId：标识Shuffle过程的唯一ID
numMaps：RDD对应的Partitioner指定的Partition的个数，也就是ShuffleMapTask输出的Partition个数
dependency：RDD对应的依赖ShuffleDependency

下面我们看下，在SortShuffleManager中是如何注册Shuffle的，代码如下所示：
上面代码中，对应如下3种ShuffleHandle可以选择，说明如下：

BypassMergeSortShuffleHandle

如果dependency不需</p>]]></description>
	<p>默认配置情况下，Spark在Shuffle过程中会使用SortShuffleManager来管理Shuffle过程中需要的基本组件，以及对RDD各个Partition数据的计算。我们可以在Driver和Executor对应的SparkEnv对象创建过程中看到对应的配置，如下代码所示：

    // Let the user specify short names for shuffle managers
    val shortShuffleMgrNames = Map(
      &quot;sort&quot; -&gt; classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName,
      &quot;tungsten-sort&quot; -&gt; classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName)
    val shuffleMgrName = conf.get(&quot;spark.shuffle.manager&quot;, &quot;sort&quot;)
    val shuffleMgrClass = shortShuffleMgrNames.getOrElse(shuffleMgrName.toLowerCase, shuffleMgrName)
    val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)

如果需要修改ShuffleManager实现，则只需要修改配置项spark.shuffle.manager即可，默认支持sort和 tungsten-sort，可以指</p>			<content:encoded><![CDATA[<p>默认配置情况下，Spark在Shuffle过程中会使用SortShuffleManager来管理Shuffle过程中需要的基本组件，以及对RDD各个Partition数据的计算。我们可以在Driver和Executor对应的SparkEnv对象创建过程中看到对应的配置，如下代码所示：
如果需要修改ShuffleManager实现，则只需要修改配置项spark.shuffle.manager即可，默认支持sort和 tungsten-sort，可以指定自己实现的ShuffleManager类。
因为Shuffle过程中需要将Map结果数据输出到文件，所以需要通过注册一个ShuffleHandle来获取到一个ShuffleWriter对象，通过它来控制Map阶段记录数据输出的行为。其中，ShuffleHandle包含了如下基本信息：

shuffleId：标识Shuffle过程的唯一ID
numMaps：RDD对应的Partitioner指定的Partition的个数，也就是ShuffleMapTask输出的Partition个数
dependency：RDD对应的依赖ShuffleDependency

下面我们看下，在SortShuffleManager中是如何注册Shuffle的，代码如下所示：
上面代码中，对应如下3种ShuffleHandle可以选择，说明如下：

BypassMergeSortShuffleHandle

如果dependency不需</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1655.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spark Block 存储管理分析</title>
		<link>http://shiyanjun.cn/archives/1641.html</link>
		<comments>http://shiyanjun.cn/archives/1641.html#comments</comments>
		<pubDate>Sat, 29 Apr 2017 14:40:35 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[Spark-2.0.0]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1641</guid>
		<description><![CDATA[<p>Apache Spark 中，对 Block 的查询、存储管理，是通过唯一的 Block ID 来进行区分的。所以，了解 Block ID 的生成规则，能够帮助我们了解 Block 查询、存储过程中是如何定位 Block 以及如何处理互斥存储/读取同一个 Block 的。可以想到，同一个 Spark Application，以及多个运行的 Application 之间，对应的 Block 都具有唯一的 ID，通过代码可以看到，BlockID 包括：RDDBlockId、ShuffleBlockId、ShuffleDataBlockId、ShuffleIndexBlockId、BroadcastBlockId、TaskResultBlockId、TempLocalBlockId、TempShuffleBlockId 这 8 种 ID，可以详见如下代码定义：
我们以 RDDBlockId 的生成规则为例，它是以前缀字符串 “rdd_” 为前缀、分配的全局 RDD ID、下 划线 “_”、Partition ID 这 4 部分拼接而成，因为 RDD ID 是唯一的，所以最终构造好的 RDDBlockId 对应的字符串就是唯一的。如果该 Block 存在，查询可以唯一定位到该 Block，存储也不会出现覆盖其他 RDDBlockId 的问题。
下面，我们通过分析 MemoryStore、DiskStore、BlockManager、BlockInfoManager 这 4 个</p>]]></description>
	<p>Apache Spark 中，对 Block 的查询、存储管理，是通过唯一的 Block ID 来进行区分的。所以，了解 Block ID 的生成规则，能够帮助我们了解 Block 查询、存储过程中是如何定位 Block 以及如何处理互斥存储/读取同一个 Block 的。可以想到，同一个 Spark Application，以及多个运行的 Application 之间，对应的 Block 都具有唯一的 ID，通过代码可以看到，BlockID 包括：RDDBlockId、ShuffleBlockId、ShuffleDataBlockId、ShuffleIndexBlockId、BroadcastBlockId、TaskResultBlockId、TempLocalBlockId、TempShuffleBlockId 这 8 种 ID，可以详见如下代码定义：

@DeveloperApi
case class RDDBlockId(rddId: Int, splitIndex: Int) extends BlockId {
  override def name: String = &quot;rdd_&quot; + rddId + &quot;_&quot; + splitIndex
}

// Format of the shuffle block ids (including data and index) should be kept in sync with
// org.apache.spark.network.shuffle.ExternalShuffleBlockResolver#getBlockData().
@DeveloperApi
case class Sh</p>			<content:encoded><![CDATA[<p>Apache Spark 中，对 Block 的查询、存储管理，是通过唯一的 Block ID 来进行区分的。所以，了解 Block ID 的生成规则，能够帮助我们了解 Block 查询、存储过程中是如何定位 Block 以及如何处理互斥存储/读取同一个 Block 的。可以想到，同一个 Spark Application，以及多个运行的 Application 之间，对应的 Block 都具有唯一的 ID，通过代码可以看到，BlockID 包括：RDDBlockId、ShuffleBlockId、ShuffleDataBlockId、ShuffleIndexBlockId、BroadcastBlockId、TaskResultBlockId、TempLocalBlockId、TempShuffleBlockId 这 8 种 ID，可以详见如下代码定义：
我们以 RDDBlockId 的生成规则为例，它是以前缀字符串 “rdd_” 为前缀、分配的全局 RDD ID、下 划线 “_”、Partition ID 这 4 部分拼接而成，因为 RDD ID 是唯一的，所以最终构造好的 RDDBlockId 对应的字符串就是唯一的。如果该 Block 存在，查询可以唯一定位到该 Block，存储也不会出现覆盖其他 RDDBlockId 的问题。
下面，我们通过分析 MemoryStore、DiskStore、BlockManager、BlockInfoManager 这 4 个</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1641.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Spark UnifiedMemoryManager 内存管理模型分析</title>
		<link>http://shiyanjun.cn/archives/1585.html</link>
		<comments>http://shiyanjun.cn/archives/1585.html#comments</comments>
		<pubDate>Fri, 03 Feb 2017 12:59:57 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[Spark-2.0.0]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1585</guid>
		<description><![CDATA[<p>Spark 的内存使用，大体上可以分为两类：Execution 内存和 Storage 内存。在 Spark 1.5 版本之前，内存管理使用的是 StaticMemoryManager，该内存管理模型最大的特点就是，可以为 Execution 内存区与 Storage 内存区配置一个静态的 boundary，这种方式实现起来比较简单，但是存在一些问题：

没有一个合理的默认值能够适应不同计算场景下的 Workload
内存调优困难，需要对 Spark 内部原理非常熟悉才能做好
对不需要 Cache 的 Application 的计算场景，只能使用很少一部分内存

为了克服上述提到的问题，尽量提高 Spark 计算的通用性，降低内存调优难度，减少 OOM 导致的失败问题，从 Spark 1.6 版本开始，新增了 UnifiedMemoryManager（统一内存管理）内存管理模型的实现。UnifiedMemoryManager 依赖的一些组件类及其关系，如下类图所示：

从上图可以看出，最直接最核心的就是 StorageMemoryPool 和 ExecutionMemoryPool，它们实现了动态内存池（Memory Pool）的功能，能够动态调整 Storage 内存区与 Execution 内存区之间的 Soft boundary，使内存管理更加灵活。下</p>]]></description>
	<p>Spark 的内存使用，大体上可以分为两类：Execution 内存和 Storage 内存。在 Spark 1.5 版本之前，内存管理使用的是 StaticMemoryManager，该内存管理模型最大的特点就是，可以为 Execution 内存区与 Storage 内存区配置一个静态的 boundary，这种方式实现起来比较简单，但是存在一些问题：

没有一个合理的默认值能够适应不同计算场景下的 Workload
内存调优困难，需要对 Spark 内部原理非常熟悉才能做好
对不需要 Cache 的 Application 的计算场景，只能使用很少一部分内存

为了克服上述提到的问题，尽量提高 Spark 计算的通用性，降低内存调优难度，减少 OOM 导致的失败问题，从 Spark 1.6 版本开始，新增了 UnifiedMemoryManager（统一内存管理）内存管理模型的实现。UnifiedMemoryManager 依赖的一些组件类及其关系，如下类图所示：

从上图可以看出，最直接最核心的就是 StorageMemoryPool 和 ExecutionMemoryPool，它们实现了动态内存池（Memory Pool）的功能，能够动态调整 Storage 内存区与 Execution 内存区之间的 Soft boundary，使内存管理更加灵活。下</p>			<content:encoded><![CDATA[<p>Spark 的内存使用，大体上可以分为两类：Execution 内存和 Storage 内存。在 Spark 1.5 版本之前，内存管理使用的是 StaticMemoryManager，该内存管理模型最大的特点就是，可以为 Execution 内存区与 Storage 内存区配置一个静态的 boundary，这种方式实现起来比较简单，但是存在一些问题：

没有一个合理的默认值能够适应不同计算场景下的 Workload
内存调优困难，需要对 Spark 内部原理非常熟悉才能做好
对不需要 Cache 的 Application 的计算场景，只能使用很少一部分内存

为了克服上述提到的问题，尽量提高 Spark 计算的通用性，降低内存调优难度，减少 OOM 导致的失败问题，从 Spark 1.6 版本开始，新增了 UnifiedMemoryManager（统一内存管理）内存管理模型的实现。UnifiedMemoryManager 依赖的一些组件类及其关系，如下类图所示：

从上图可以看出，最直接最核心的就是 StorageMemoryPool 和 ExecutionMemoryPool，它们实现了动态内存池（Memory Pool）的功能，能够动态调整 Storage 内存区与 Execution 内存区之间的 Soft boundary，使内存管理更加灵活。下</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1585.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Spark Standalone架构设计要点分析</title>
		<link>http://shiyanjun.cn/archives/1545.html</link>
		<comments>http://shiyanjun.cn/archives/1545.html#comments</comments>
		<pubDate>Wed, 23 Nov 2016 06:59:20 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[Spark-2.0.0]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1545</guid>
		<description><![CDATA[<p>Apache Spark是一个开源的通用集群计算系统，它提供了High-level编程API，支持Scala、Java和Python三种编程语言。Spark内核使用Scala语言编写，通过基于Scala的函数式编程特性，在不同的计算层面进行抽象，代码设计非常优秀。
RDD抽象
RDD（Resilient Distributed Datasets），弹性分布式数据集，它是对分布式数据集的一种内存抽象，通过受限的共享内存方式来提供容错性，同时这种内存模型使得计算比传统的数据流模型要高效。RDD具有5个重要的特性，如下图所示：

上图展示了2个RDD进行JOIN操作，体现了RDD所具备的5个主要特性，如下所示：

一组分区
计算每一个数据分片的函数
RDD上的一组依赖
可选，对于键值对RDD，有一个Partitioner（通常是HashPartitioner）
可选，一组Preferred location信息（例如，HDFS文件的Block所在location信息）

有了上述特性，能够非常好地通过RDD来表达分布式数据集，并作为构建DAG图的基础：首先抽象一次分布式计算任务的逻辑表示，最终将任务在实际的物理计算环境中进行处理执行。
计算抽象
在描述Spark中的计算抽象，我们首先需</p>]]></description>
	<p>Apache Spark是一个开源的通用集群计算系统，它提供了High-level编程API，支持Scala、Java和Python三种编程语言。Spark内核使用Scala语言编写，通过基于Scala的函数式编程特性，在不同的计算层面进行抽象，代码设计非常优秀。
RDD抽象
RDD（Resilient Distributed Datasets），弹性分布式数据集，它是对分布式数据集的一种内存抽象，通过受限的共享内存方式来提供容错性，同时这种内存模型使得计算比传统的数据流模型要高效。RDD具有5个重要的特性，如下图所示：

上图展示了2个RDD进行JOIN操作，体现了RDD所具备的5个主要特性，如下所示：

一组分区
计算每一个数据分片的函数
RDD上的一组依赖
可选，对于键值对RDD，有一个Partitioner（通常是HashPartitioner）
可选，一组Preferred location信息（例如，HDFS文件的Block所在location信息）

有了上述特性，能够非常好地通过RDD来表达分布式数据集，并作为构建DAG图的基础：首先抽象一次分布式计算任务的逻辑表示，最终将任务在实际的物理计算环境中进行处理执行。
计算抽象
在描述Spark中的计算抽象，我们首先需</p>			<content:encoded><![CDATA[<p>Apache Spark是一个开源的通用集群计算系统，它提供了High-level编程API，支持Scala、Java和Python三种编程语言。Spark内核使用Scala语言编写，通过基于Scala的函数式编程特性，在不同的计算层面进行抽象，代码设计非常优秀。
RDD抽象
RDD（Resilient Distributed Datasets），弹性分布式数据集，它是对分布式数据集的一种内存抽象，通过受限的共享内存方式来提供容错性，同时这种内存模型使得计算比传统的数据流模型要高效。RDD具有5个重要的特性，如下图所示：

上图展示了2个RDD进行JOIN操作，体现了RDD所具备的5个主要特性，如下所示：

一组分区
计算每一个数据分片的函数
RDD上的一组依赖
可选，对于键值对RDD，有一个Partitioner（通常是HashPartitioner）
可选，一组Preferred location信息（例如，HDFS文件的Block所在location信息）

有了上述特性，能够非常好地通过RDD来表达分布式数据集，并作为构建DAG图的基础：首先抽象一次分布式计算任务的逻辑表示，最终将任务在实际的物理计算环境中进行处理执行。
计算抽象
在描述Spark中的计算抽象，我们首先需</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1545.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Spark RPC通信层设计原理分析</title>
		<link>http://shiyanjun.cn/archives/1536.html</link>
		<comments>http://shiyanjun.cn/archives/1536.html#comments</comments>
		<pubDate>Sat, 17 Sep 2016 14:49:58 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>
		<category><![CDATA[Spark-2.0.0]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1536</guid>
		<description><![CDATA[<p>Spark将RPC通信层设计的非常巧妙，融合了各种设计/架构模式，将一个分布式集群系统的通信层细节完全屏蔽，这样在上层的计算框架的设计中能够获得很好的灵活性。同时，如果上层想要增加各种新的特性，或者对来自不同企业或组织的程序员贡献的特性，也能够很容易地增加进来，可以避开复杂的通信层而将注意力集中在上层计算框架的处理和优化上，入手难度非常小。另外，对上层计算框架中的各个核心组件的开发、功能增强，以及Bug修复等都会变得更加容易。
Spark RPC层设计概览
Spark RPC层是基于优秀的网络通信框架Netty设计开发的，同时获得了Netty所具有的网络通信的可靠性和高效性。我们先把Spark中与RPC相关的一些类的关系梳理一下，为了能够更直观地表达RPC的设计，我们先从类的设计来看，如下图所示：

通过上图，可以清晰地将RPC设计分离出来，能够对RPC层有一个整体的印象。了解Spark RPC层的几个核心的概念（我们通过Spark源码中对应的类名来标识），能够更好地理解设计：

RpcEndpoint

RpcEndpoint定义了RPC通信过程中的通信端对象，除了具有管理一个RpcEndp</p>]]></description>
	<p>Spark将RPC通信层设计的非常巧妙，融合了各种设计/架构模式，将一个分布式集群系统的通信层细节完全屏蔽，这样在上层的计算框架的设计中能够获得很好的灵活性。同时，如果上层想要增加各种新的特性，或者对来自不同企业或组织的程序员贡献的特性，也能够很容易地增加进来，可以避开复杂的通信层而将注意力集中在上层计算框架的处理和优化上，入手难度非常小。另外，对上层计算框架中的各个核心组件的开发、功能增强，以及Bug修复等都会变得更加容易。
Spark RPC层设计概览
Spark RPC层是基于优秀的网络通信框架Netty设计开发的，同时获得了Netty所具有的网络通信的可靠性和高效性。我们先把Spark中与RPC相关的一些类的关系梳理一下，为了能够更直观地表达RPC的设计，我们先从类的设计来看，如下图所示：

通过上图，可以清晰地将RPC设计分离出来，能够对RPC层有一个整体的印象。了解Spark RPC层的几个核心的概念（我们通过Spark源码中对应的类名来标识），能够更好地理解设计：

RpcEndpoint

RpcEndpoint定义了RPC通信过程中的通信端对象，除了具有管理一个RpcEndp</p>			<content:encoded><![CDATA[<p>Spark将RPC通信层设计的非常巧妙，融合了各种设计/架构模式，将一个分布式集群系统的通信层细节完全屏蔽，这样在上层的计算框架的设计中能够获得很好的灵活性。同时，如果上层想要增加各种新的特性，或者对来自不同企业或组织的程序员贡献的特性，也能够很容易地增加进来，可以避开复杂的通信层而将注意力集中在上层计算框架的处理和优化上，入手难度非常小。另外，对上层计算框架中的各个核心组件的开发、功能增强，以及Bug修复等都会变得更加容易。
Spark RPC层设计概览
Spark RPC层是基于优秀的网络通信框架Netty设计开发的，同时获得了Netty所具有的网络通信的可靠性和高效性。我们先把Spark中与RPC相关的一些类的关系梳理一下，为了能够更直观地表达RPC的设计，我们先从类的设计来看，如下图所示：

通过上图，可以清晰地将RPC设计分离出来，能够对RPC层有一个整体的印象。了解Spark RPC层的几个核心的概念（我们通过Spark源码中对应的类名来标识），能够更好地理解设计：

RpcEndpoint

RpcEndpoint定义了RPC通信过程中的通信端对象，除了具有管理一个RpcEndp</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1536.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spark-1.3.1与Hive整合实现查询分析</title>
		<link>http://shiyanjun.cn/archives/1113.html</link>
		<comments>http://shiyanjun.cn/archives/1113.html#comments</comments>
		<pubDate>Thu, 14 May 2015 13:42:08 +0000</pubDate>
		<dc:creator><![CDATA[Yanjun]]></dc:creator>
				<category><![CDATA[Spark]]></category>
		<category><![CDATA[开源技术]]></category>

		<guid isPermaLink="false">http://shiyanjun.cn/?p=1113</guid>
		<description><![CDATA[<p>在大数据应用场景下，使用过Hive做查询统计分析的应该知道，计算的延迟性非常大，可能一个非常复杂的统计分析需求，需要运行1个小时以上，但是比之于使用MySQL之类关系数据库做分析，执行速度快很多很多。使用HiveQL写类似SQL的查询分析语句，最终经过Hive查询解析器，翻译成Hadoop平台上的MapReduce程序进行运行，这也是MapReduce计算引擎的特点带来的延迟问题：Map中间结果写文件。如果一个HiveQL语句非常复杂，会被翻译成多个MapReduce Job，那么就会有很多的Map输出中间结果数据到文件中，基本没有数据的共享。
如果使用Spark计算平台，基于Spark RDD数据集模型计算，可以减少计算过程中产生中间结果数据写文件的开销，Spark会把数据直接放到内存中供后续操作共享数据，减少了读写磁盘I/O操作带来的延时。另外，如果基于Spark on YARN部署模式，可以充分利用数据在Hadoop集群DataNode节点的本地性（Locality）特点，减少数据传输的通信开销。
软件准备
我把使用的相关软件的版本在这里列出来，以便测试验证，如下所示：

CentOS-6.6 (Final)
JDK-1.7.0_25
Maven</p>]]></description>
	<p>在大数据应用场景下，使用过Hive做查询统计分析的应该知道，计算的延迟性非常大，可能一个非常复杂的统计分析需求，需要运行1个小时以上，但是比之于使用MySQL之类关系数据库做分析，执行速度快很多很多。使用HiveQL写类似SQL的查询分析语句，最终经过Hive查询解析器，翻译成Hadoop平台上的MapReduce程序进行运行，这也是MapReduce计算引擎的特点带来的延迟问题：Map中间结果写文件。如果一个HiveQL语句非常复杂，会被翻译成多个MapReduce Job，那么就会有很多的Map输出中间结果数据到文件中，基本没有数据的共享。
如果使用Spark计算平台，基于Spark RDD数据集模型计算，可以减少计算过程中产生中间结果数据写文件的开销，Spark会把数据直接放到内存中供后续操作共享数据，减少了读写磁盘I/O操作带来的延时。另外，如果基于Spark on YARN部署模式，可以充分利用数据在Hadoop集群DataNode节点的本地性（Locality）特点，减少数据传输的通信开销。
软件准备
我把使用的相关软件的版本在这里列出来，以便测试验证，如下所示：

CentOS-6.6 (Final)
JDK-1.7.0_25
Maven</p>			<content:encoded><![CDATA[<p>在大数据应用场景下，使用过Hive做查询统计分析的应该知道，计算的延迟性非常大，可能一个非常复杂的统计分析需求，需要运行1个小时以上，但是比之于使用MySQL之类关系数据库做分析，执行速度快很多很多。使用HiveQL写类似SQL的查询分析语句，最终经过Hive查询解析器，翻译成Hadoop平台上的MapReduce程序进行运行，这也是MapReduce计算引擎的特点带来的延迟问题：Map中间结果写文件。如果一个HiveQL语句非常复杂，会被翻译成多个MapReduce Job，那么就会有很多的Map输出中间结果数据到文件中，基本没有数据的共享。
如果使用Spark计算平台，基于Spark RDD数据集模型计算，可以减少计算过程中产生中间结果数据写文件的开销，Spark会把数据直接放到内存中供后续操作共享数据，减少了读写磁盘I/O操作带来的延时。另外，如果基于Spark on YARN部署模式，可以充分利用数据在Hadoop集群DataNode节点的本地性（Locality）特点，减少数据传输的通信开销。
软件准备
我把使用的相关软件的版本在这里列出来，以便测试验证，如下所示：

CentOS-6.6 (Final)
JDK-1.7.0_25
Maven</p>]]></content:encoded>
			<wfw:commentRss>http://shiyanjun.cn/archives/1113.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
