`
冰糖葫芦
  • 浏览: 293917 次
社区版块
存档分类
最新评论

Spark架构

阅读更多

声明:本文中所将的spark内存模型是1.6+的版本,新的内存模型会在新的文章中讲到。

 

不久前我在StackOverflow上回答了一系列关于Apache Spark架构相关的问题。这似乎是由于网上缺乏好的Spark整体架构的文章。甚至是官网指导中也没有很多详细的介绍,当然也缺少好的架构图。“Learning Spark”这本书和官方资料中也一样没有。

本文我将尝试解决这个问题并在整体上提供Spark架构相关以及经常被提及的先关概念一些问题的一站式指导。这篇文章并不完全是针对Spark初学者的:文中不会提供Spark主要抽象编程的深入讲解(如RDD和DGA),但是需要大家具备这方面的知识。

下面我们先看看官方的架构图(http://spark.apache.org/docs/1.3.0/cluster-overview.html):


 

如上图所示,它一次性介绍了很多概念:executor、task、Cache、Worker Node等等。我以前开始学习Spark概念的时候,这张图几乎就是网上所能看到的唯一样关于Spark架构的图了,但是目前这种情况依然没有改变。我个人并不喜欢这张图,因为它并没有展示一些重要概念或者并没有将它们以最好的形式展示出来。

让我们从头开始。任何工作在我们集群上或者本地机器上的Spark进程都是一个JVM进程;而对于任何JVM进程我们都可以通过JVM参数-Xmx和-Xms来配置堆栈大小。那么这个进程如何使用堆栈以及为什么需要堆栈?这里有一张Spark在JVM堆中的内存分布图:


 

默认情况下,Spark的启动是JVM堆内存大小为512M。从安全方面考虑以及避免OOM错误,Spark只允许利用堆内存的90%,这比例通过Spark的spark.storage.safetyFraction参数控制。好吧,我们可能还听说过Spark作为一个内存池工具可以让我们将一些数据放入缓存中。如果我们已经读过之前关于Spark误区的文章(译注:Spark误区)就会明白Spark并不是真正的内存工具,它只是使用内存作为它的LRU缓存(http://en.wikipedia.org/wiki/Cache_algorithms)。其中一些缓存作为保留用来保存正在处理的数据,这部分区域通常占安全区域(safe heap,译注:JVM对内存的90%那部分内存)的60%,这个比例可以通过spark.storage.memoryFraction参数控制。因此,如果我们想知道可以将多少数据放入Spark缓存中,我们需要减去所有executor所占的对内存总和,再乘以safetyFraction和storage.memoryFraction参数;默认情况下为0.9 * 0.6 = 0.54,也就是说我们有54%的堆内存供Spark使用。

接着我们稍微多讲下shufle内存。它通过堆大小 * spark.shuffle.safetyFraction *spark.shuffle.memoryFraction计算公式得出。spark.shuffle.safetyFraction的默认值为0.8或者80%,spark.shuffle.memoryFraction的默认值为0.2或者20%;因此,我们可以使用的shuffle内存大小为0.8 * 0.2 = 0.16,也就是JVM堆内存的16%。但是Spark如何使用这个内存?我们可以在这里看到更多细节https://github.com/apache/spark/blob/branch-1.3/core/src/main/scala/org/apache/spark/shuffle/ShuffleMemoryManager.scala,Spark使用这些内存来执行shuffle所需要的任务;当shuffle执行完成后,有时我们需要对数据进行排序;当我们排序时需要将排过序的数据放入缓存中(但是请谨记,我们不能修改这些在LRU缓存中的数据,因为它们会在随后被重用)。所以需要一些内存来存放已排序的数据块。那么如果没有足够的内存来存放这些排过序的数据时会怎么样?有一个广泛使用的算法叫做“外部排序”(http://en.wikipedia.org/wiki/External_sorting)可以让我们将数据一块一块的排序,然后将最终结果合并在一起。

内存中最后一部分还没有被提及的是“unroll”内存。这块可以被unroll进程使用的内存大小通过spark.storage.unrollFraction *spark.storage.memoryFraction * spark.storage.safetyFraction计算公式得出,默认大小为0.2 * 0.6 * 0.9 = 0.108或者是10.8%。这块内存就是将数据展开到内存中时可以使用的内存。究竟为何我们需要unroll数据?因为Spark可以让我们将数据以序列化或非序列化的形式存储;以序列化的形式存储的数据是不能直接使用的,所以我们需要在用它之前将其展开,这就是这块内存的作用;这块内存是和Spark存储数据所用的内存共享的,所以当我们展开数据的时候可能会引起LRU缓存中存储的一些数据被清理。

非常好,现在我们了解了Spark进程是怎么样的以及如何利用JVM进程的堆内存。接着我们来看看集群模式:当我们打开一个Spark集群时,它看起来到底是什么样的?我比较喜欢YARN,所以我将讲讲它是怎么在YARN中运行的,但其实这在其他集群中也都是一样的:


 

在YARN集群中,有一个YARN资源管理守护进程来管理集群中的资源(尤其是内存)、有一系列运行在集群节点上的YARN节点管理器以及控制节点上的资源利用。从YARN的角度上来看,每一个节点都代表一个我们可以控制的内存池。当我们从YARN资源管理器中请求一个资源时,它可以为我们调出executor容器;其中每个executor容器都是一个具有一定堆内存大小的JVM;而JVM得位置则由YARN资源管理器来决定我们不能直接控制选择哪个JVM----如果一个节点有64G的内存在YARN的控制之下(通过yarn-site.xml中yarn.nodemanager.resource.memory-mb参数配置),那么当我们发起10个执行请求每个4G时,如果有一个很大的集群,则这10个executor都可以很容易在单个YARN节点上执行。

当我们在YARN上构建Spark集群时,我们需要指定执行器的数量(-num-executors标记或spark.executor.instances参数)、每个executor的内存大小(-executor-memory标记或者spark.executor.memory参数)、每个executor所允许的核心数(-executor-cores标记或者spark.executor.cores参数)、为每个任务的执行分配的核心数(-spark.task.cpus参数)。同时我们还需要指定驱动程序所使用的内存大小(-driver-memory标记或者spark.driver.memory参数)。

当我们在Spark集群中发起执行命令时,我们的工作会被分为不同的阶段,每个阶段又会被拆分为task。每个task都会被单独调度,我们可以认为每个JVM都被用作执行器(executor)来作为task执行的任务池;每个executor又提供了spark.executor.cores 或spark.task.cpus参数来为每个task设置执行槽;并通过spark.executor.instances参数设置每个机器上所允许的executor数。这里有一个例子:有一个集群中有12个运行了YARN资源管理器的节点,每个节点64G内存、32核CPU(拥有超线程的16核物理CPU);这样的话每个节点可以启动两个executor,每个26G内存(因为要留一些内存给系统进程和YARN NM以及数据节点),每个executor分配12核CPU用来执行任务(因为要留一些内存给系统进程和YARN NM以及数据节点);因此这个集群可以处理12台机器 * 2个executor/机器 * 12个核心/executor * 1个核心/task = 288个任务槽,也就是说这个Spark集群可以最多并行执行288个任务并占满集群中的所有资源。而集群中可以被用来缓存数据的内存大小为 0.9 spark.storage.safetyFraction * 0.6 spark.storage.memoryFraction* 12台机器 * 2executor/每台机器 * 26G内存/executor = 336.96 GB。虽然不是很多,但大部分情况下就够用了。

目前一切顺利,我们Spark如何利用内存以及集群中执行槽是什么。但我们可能还注意到,我并没停留在有关细节上来解释“task”到底是什么。这是下一篇文章里要讲到的,但是基本上task是Spark进行作业的最小执行单位,并且作为executor JVM中的一个线程来执行;这就是Spark下job启动延迟低的秘密----在JVM内部fork一个额外的线程远比在Hadoop启动MapReduce作业时重新启动一个完整的虚拟机要快的多。

下面我们来关注Spark的另一个抽象“分区(partition)”。我们在Spark中使用的所有数据都会被拆分为分区。什么是分区?它是由什么决定的?分区的大小完全是由我们所使用的数据源大小决定的。在Spark大多数读取数据的方法中我们都可以指定想要在RDD中生成的分区数。当我们从HDFS中读取一个文件时,可以使用Hadoop的InputFormat来实现,默认情况下被InputFormat拆分出来的输入块在RDD中都会被封装为分区。对于HDFS中的大多数文件来说每个输入分片都会生成对应的块(block)存储在HDFS系统中,每个块大约在64M到128M。这里用大约是因为HDFS是使用字节来准确切分块,但处理的时候是根据记录来切分的;对于文本文件来说是通过换行符切换的,而对于序列文件又是根据块切分的等等。这里唯一个列外就是压缩文件----如果我们将整个文本文件压缩,那么它就不能按记录来切分,那么整个文件就会作为一个单一的切分从而导致Spark只会为其生成单个分区,这种情况下我们只能手动来切分。

接下来事情就变得很简单了----将每个分区中的数据通过离数据位置(这里指Hadoop中块的位置或者Spark中缓存的分区的位置)最近的任务槽中通过task来处理。

这篇文章中已经讲了很多信息了。下篇文章将讲讲Spark如何将执行进程拆分为不同阶段并将每阶段放入task中执行?Spark如何在集群中shuffle数据?以及其他一些有用的东西。

 

1. 本文由程序员学架构翻译

2.原文链接:http://0x0fff.com/spark-architecture/

2. 转载请务必注明本文出自:程序员学架构(微信号:archleaner)

3. 更多文章请扫码:

  • 大小: 44.2 KB
  • 大小: 92.5 KB
  • 大小: 139.6 KB
  • 大小: 32.5 KB
分享到:
评论

相关推荐

    发卡系统源码无授权版 带十多套模板

    发卡系统源码无授权版 带十多套模板

    STM32F103系列PWM输出应用之纸短情长音乐——无源蜂鸣器.rar

    STM32F103系列PWM输出应用之纸短情长音乐——无源蜂鸣器

    基于matlab开发的rvm回归预测 RVM采取是与支持向量机相同的函数形式稀疏概率模型,对未知函数进行预测或分类.rar

    基于matlab开发的rvm回归预测 RVM采取是与支持向量机相同的函数形式稀疏概率模型,对未知函数进行预测或分类.rar

    STM32 CubeMX FreeRtos系统 基于lwRB通用环形缓冲区的串口非阻塞发送

    STM32工具 CubeMX 使用FreeRtos系统 基于lwRB通用环形缓冲区的串口非阻塞发送,程序使用printf,通过重定向fputc函数,将发送数据保存在FIFO中,可以在中断中调用printf,保证了系统的线程安全和中断安全,将发送任务放在线程中。LwRB有两个指针一个r读指,一个w写指针,底层采用原子操作,不需要用到锁,保证了线程安全,最大的好处是它是支持DMA的,为CPU减负。

    整站程序EasyJF官网全站源码-easyjfcom-src.rar

    EasyJF官网全站源码_easyjfcom_src.rar是一个针对计算机专业的JSP源码资料包,它包含了丰富的内容和功能,旨在帮助开发人员快速构建和管理网站。这个源码包基于Java技术栈,使用JSP(JavaServer Pages)作为前端页面渲染技术,结合了Servlet、JavaBean等后端组件,为开发者提供了一个稳定、高效的开发环境。通过使用这个源码包,开发者可以快速搭建一个具有基本功能的网站建设平台。它提供了用户注册、登录、权限管理等基本功能,同时也支持文章发布、分类管理、评论互动等常见内容管理操作。此外,源码包还包含了一些实用的辅助工具,如文件上传、数据导出等,方便开发者进行网站的维护和管理。在界面设计方面,EasyJF官网全站源码采用了简洁、易用的设计风格,使得用户可以轻松上手并进行个性化定制。同时,它还提供了一些可扩展的插件和模板,开发者可以根据自己的需求进行修改和扩展,实现更多的功能和效果。总之,EasyJF官网全站源码_easyjfcom_src.rar是一个功能强大、易于使用的计算机专业JSP源码资料包,适用于各类网站建设项目。无论是初学者还是有经验的开发者

    node-v11.13.0-x86.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v12.10.0-win-x86.zip

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v10.2.1-x86.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于matlab实现此压缩包包含语音信号处理中的语音变声代码加音频.rar

    基于matlab实现此压缩包包含语音信号处理中的语音变声代码加音频.rar

    node-v6.10.2.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    Java 中将 UUID 存储为 Base64 字符串

    使用 Base64 编码来对 UUID(Universally Unique Identifiers) 存储在一些特定的场合被广泛的使用。使用 Base64 对比直接使用 UUID 进行存储来说能够更多的节约空间。 本文对这方面的相关内容和问题进行探讨。 在这里,使用 Base64 来对 UUID 进行存储,涉及到一些类型的转换的。Base64 是编码算法,在实际使用的时候我们更多会用到 Byte 数组的方式来进行编码的。这样我们就比较明确在对其进行 Base64 转换之前,我们应该要先干什么了。

    Java网络爬虫(蜘蛛)源码.zip

    Java网络爬虫(蜘蛛)源码.zip

    pandas数据分析学习

    这是Pandas基础学习

    毕业设计基于STM32的桌面电子时钟的设计与实现硬件端系统源码.zip

    架构 主微控制器采用 STM32F103C8T6。 目前外设部分包括: 显示模块:0.96寸4针IIC通信协议的OLED模块 温湿度采集模块:DHT11 网络通信模块:ESP8266 报警模块:高电平触发的有缘蜂鸣器 其他:若干LED灯珠以及若干贴片按键 硬件端系统使用C语言编写

    新版PHP无陌然在线云加密平台系统源码 带安装说明.rar

    新版PHP无陌然在线云加密平台系统源码 带安装说明.rar新版PHP无陌然在线云加密平台系统源码 带安装说明.rar

    记账管理系统的设计与实现

    近年来由于生活节奏的加快,好像每个人都被很多难以启齿的问题困惑,然而关于随意消费是大多数人头疼的问题,没有任何计划和筹备的情况下随意消费,导致现实生活中我们所称为的“月光族”。 当你逐渐了解自己的财务状况,就可以学着做简单的收支规划。大部分月光族的根源其实是缺乏规划,想买什么的时候就买了。并不是说规划不能随意买东西,规划的价值在于让你使用资金的效率最高。无论你用金钱换取的必需品,满足感或者快乐,都可以通过规划获得比较高的效率。 本记账系统是一个基于国内外电子商务网站的发展现状,采用B2C(Business to Consumers)模式开发的电子商务平台,它的价值所在对于那些随意消费性的人群能起到一个很大的警示作用,而且系统扩张性很强,能根据客户的不同需求进行快速改进。该系统采用B/S三层结构,服务器是Tomcat同时运用JSp技术进行动态页面设计,后台数据库是Oracle。

    最新微信文章编辑器排版工具程序源码.rar

    最新微信文章编辑器排版工具程序源码.rar最新微信文章编辑器排版工具程序源码.rar最新微信文章编辑器排版工具程序源码.rar

    249ssm-mysql-jsp 疫情冷链追溯系统.zip(可运行源码+数据库文件+文档)

    前台方面(经营者用户): 系统首页:是用这户端的系统首页,首页的最上方有投诉建议、进入后台等选项,页面下方可以根据商品编号进行商品状态的实时查询,十分方便快捷。 投诉建议:用户可以在这个系统的这个板块给系统开发者留言,向开发者反应系统使用者的疑难问题,并提出自己相应的改进建议。 商品入库:生鲜商品经营者可以在商品入库界面,对一定数量的生鲜商品进行入库操作,确保库房内的每一件商品都能追根溯源,保障产品质量安全。 商品出库:用户在商品出库界面,可以对指定的商品进行出库操作,输入出库数量,点击提交即可。 商品列表:用户还可以在商品列表的界面中,对自己旗下生鲜商品的入库、出库情况进行实时查看。 后台方面(管理者用户): 商品管理:商品管理是系统后台的核心功能,在这个功能模块中,系统管理员可以对平台内生鲜商品的出入库指令进行严格的审核,并且可以对商品的归属地追根溯源。 经营者管理:拥有最高管理权限的系统管理员,可以连接到数据库,对经营者类别、名称、经营许可证编号等基础信息进行审核。 投诉建议管理:管理员还可以对所有注册用户的投诉建议,进行删除或者回复操作,通过这种方式,与注册用户进行线上交流。

    MyBatis 动态 SQL 示例

    MyBatis 是一个持久层框架,它允许用户在 XML 文件中编写动态 SQL 语句。MyBatis 的动态 SQL 功能非常强大,它允许开发者根据运行时的条件动态地生成 SQL 语句。这使得 MyBatis 能够灵活地处理各种复杂的查询需求。 MyBatis 动态 SQL 通过使用 <if>、<choose>、<when>、<otherwise>、<trim>、<set> 等标签来实现。附件中是一些常见的动态 SQL 标签及其用法,通过组合使用这些标签,可以编写出非常灵活和强大的 SQL 语句,以适应不同的查询和更新需求

Global site tag (gtag.js) - Google Analytics