首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spark利用Project Tungsten将硬件性能提升到极限

Spark利用Project Tungsten将硬件性能提升到极限

作者头像
用户1410343
发布于 2018-03-27 06:29:32
发布于 2018-03-27 06:29:32
1.2K0
举报
文章被收录于专栏:about云about云

我们将为你介绍性能提升的下一阶段——Tungsten。在2014年,我们目睹了Spark缔造大规模排序的新世界纪录,同时也看到了Spark整个引擎的大幅度提升——从Python到SQL再到机器学习

Tungsten项目将是Spark自诞生以来内核级别的最大改动,以大幅度提升Spark应用程序的内存和CPU利用率为目标,旨在最大程度上压榨新时代硬件性能。Project Tungsten包括了3个方面的努力:

  • Memory Management和Binary Processing:利用应用的语义(application semantics)来更明确地管理内存,同时消除JVM对象模型和垃圾回收开销。
  • Cache-aware computation(缓存友好的计算):使用算法和数据结构来实现内存分级结构(memory hierarchy)。
  • 代码生成(Code generation):使用代码生成来利用新型编译器和CPU。

之所以大幅度聚焦内存和CPU的利用,其主要原因就在于:对比IO和网络通信,Spark在CPU和内存上遭遇的瓶颈日益增多。详细信息可以查看最新的大数据负载性能研究(Ousterhout),而我们在为Databricks Cloud用户做优化调整时也得出了类似的结论。

为什么CPU会成为新的瓶颈?这里存在多个问题:首先,在硬件配置中,IO带宽提升的非常明显,比如10Gbps网络和SSD存储(或者做了条文化处理的HDD阵列)提供的高带宽;从软件的角度来看,通过Spark优化器基于业务对输入数据进行剪枝,当下许多类型的工作负载已经不会再需要使用大量的IO;在Spark Shuffle子系统中,对比底层硬件系统提供的原始吞吐量,序列化和哈希(CPU相关)成为主要瓶颈。从种种迹象来看,对比IO,Spark当下更受限于CPU效率和内存压力。

1. Memory Management和Binary Processing

在JVM上的应用程序通常依赖JVM的垃圾回收机制来管理内存。毫无疑问,JVM绝对是一个伟大的工程,为不同工作负载提供了一个通用的运行环境。然而,随着Spark应用程序性能的不断提升,JVM对象和GC开销产生的影响将非常致命。

一直以来,Java对象产生的开销都非常大。在UTF-8编码上,简单如“abcd”这样的字符串也需要4个字节进行储存。然而,到了JVM情况就更糟糕了。为了更加通用,它重新定制了自己的储存机制——使用UTF-16方式编码每个字符(2字节),与此同时,每个String对象还包含一个12字节的header,和一个8字节的哈希编码,我们可以从 Java Object Layout工具的输出上获得一个更清晰的理解:

  1. java.lang.String object internals:
  2. OFFSET SIZE TYPE DESCRIPTION VALUE
  3. 0 4 (object header) ...
  4. 4 4 (object header) ...
  5. 8 4 (object header) ...
  6. 12 4 char[] String.value []
  7. 16 4 int String.hash 0
  8. 20 4 int String.hash32 0
  9. Instance size: 24 bytes (reported by Instrumentation API)

毫无疑问,在JVM对象模型中,一个4字节的字符串需要48字节的空间来存储!

JVM对象带来的另一个问题是GC。从高等级上看,通常情况下GC会将对象划分成两种类型:第一种会有很高的allocation/deallocation(年轻代),另一种的状态非常稳定(年老代)。通过利用年轻代对象的瞬时特性,垃圾收集器可以更有效率地对其进行管理。在GC可以可靠地估算对象的生命周期时,这种机制可以良好运行,但是如果只是基于一个很短的时间,这个机制很显然会遭遇困境,比如对象忽然从年轻代进入到年老代。鉴于这种实现基于一个启发和估计的原理,性能可以通过GC调优的一些“黑魔法”来实现,因此你可能需要给JVM更多的参数让其弄清楚对象的生命周期。

然而,Spark追求的不仅仅是通用性。在计算上,Spark了解每个步骤的数据传输,以及每个作业和任务的范围。因此,对比JVM垃圾收集器,Spark知悉内存块生命周期的更多信息,从而在内存管理上拥有比JVM更具效率的可能。

为了扭转对象开销和无效率GC产生的影响,我们引入了一个显式的内存管理器让Spark操作可以直接针对二进制数据而不是Java对象。它基于sun.misc.Unsafe建立,由JVM提供,一个类似C的内存访问功能(比如explicit allocation、deallocation和pointer arithmetics)。此外,Unsafe方法是内置的,这意味着,每个方法都将由JIT编译成单一的机器指令。

在某些方面,Spark已经开始利用内存管理。2014年,Databricks引入了一个新的基于Netty的网络传输机制,它使用一个类jemalloc的内存管理器来管理所有网络缓冲。这个机制让Spark shuffle得到了非常大的改善,也帮助了Spark创造了新的世界纪录。

新内存管理的首次亮相将出现在Spark 1.4版本,它包含了一个由Spark管理,可以直接在内存中操作二进制数据的hashmap。对比标准的Java HashMap,该实现避免了很多中间环节开销,并且对垃圾收集器透明。

当下,这个功能仍然处于开发阶段,但是其展现的初始测试行能已然令人兴奋。如上图所示,我们在3个不同的途径中对比了聚合计算的吞吐量——开发中的新模型、offheap模型、以及java.util.HashMap。新的hashmap可以支撑每秒超过100万的聚合操作,大约是java.util.HashMap的两倍。更重要的是,在没有太多参数调优的情况下,随着内存利用增加,这个模式基本上不存在性能的衰弱,而使用JVM默认模式最终已被GC压垮。

在Spark 1.4中,这个hashmap可以为DataFracmes和SQL的聚合处理使用,而在1.5中,我们将为其他操作提供一个让其利用这个特性的数据结构,比如sort和join。毫无疑问,它将应用到大量需要调优GC以获得高性能的场景。

2. Cache-aware computation(缓存友好的计算)

在解释Cache-aware computation之前,我们首先回顾一下“内存计算”,也是Spark广为业内知晓的优势。对于Spark来说,它可以更好地利用集群中的内存资源,提供了比基于磁盘解决方案更快的速度。然而,Spark同样可以处理超过内存大小的数据,自动地外溢到磁盘,并执行额外的操作,比如排序和哈希。

类似的情况,Cache-aware computation通过使用 L1/ L2/L3 CPU缓存来提升速度,同样也可以处理超过寄存器大小的数据。在给用户Spark应用程序做性能分析时,我们发现大量的CPU时间因为等待从内存中读取数据而浪费。在 Tungsten项目中,我们设计了更加缓存友好的算法和数据结构,从而让Spark应用程序可以花费更少的时间等待CPU从内存中读取数据,也给有用工作提供了更多的计算时间。

我们不妨看向对记录排序的例子。一个标准的排序步骤需要为记录储存一组的指针,并使用quicksort 来互换指针直到所有记录被排序。基于顺序扫描的特性,排序通常能获得一个不错的缓存命中率。然而,排序一组指针的缓存命中率却很低,因为每个比较运算都需要对两个指针解引用,而这两个指针对应的却是内存中两个随机位置的数据。

那么,我们该如何提高排序中的缓存本地性?其中一个方法就是通过指针顺序地储存每个记录的sort key。举个例子,如果sort key是一个64位的整型,那么我们需要在指针阵列中使用128位(64位指针,64位sort key)来储存每条记录。这个途径下,每个quicksort对比操作只需要线性的查找每对pointer-key,从而不会产生任何的随机扫描。希望上述解释可以让你对我们提高缓存本地性的方法有一定的了解。

这样一来,我们又如何将这些优化应用到Spark?大多数分布式数据处理都可以归结为多个操作组成的一个小列表,比如聚合、排序和join。因此,通过提升这些操作的效率,我们可以从整体上提升Spark。我们已经为排序操作建立了一个新的版本,它比老版本的速度快5倍。这个新的sort将会被应用到sort-based shuffle、high cardinality aggregations和sort-merge join operator。在2015年底,所有Spark上的低等级算法都将升级为cache-aware,从而让所有应用程序的效率都得到提高——从机器学习到SQL。

3. 代码生成

大约在1年前,Spark引入代码生成用于SQL和DataFrames里的表达式求值(expression evaluation)。表达式求值的过程是在特定的记录上计算一个表达式的值(比如age > 35 && age < 40)。当然,这里是在运行时,而不是在一个缓慢的解释器中为每个行做单步调试。对比解释器,代码生成去掉了原始数据类型的封装,更重要的是,避免了昂贵的多态函数调度。

在之前的博文中,我们阐述了代码生成可以加速(接近一个量级)多种TPC-DS查询。当下,我们正在努力让代码生成可以应用到所有的内置表达式上。此外,我们计划提升代码生成的等级,从每次一条记录表达式求值到向量化表达式求值,使用JIT来开发更好的作用于新型CPU的指令流水线,从而在同时处理多条记录。

在通过表达式求值优化内部组件的CPU效率之外,我们还期望将代码生成推到更广泛的地方,其中一个就是shuffle过程中将数据从内存二进制格式转换到wire-protocol。如之前所述,取代带宽,shuffle通常会因数据系列化出现瓶颈。通过代码生成,我们可以显著地提升序列化吞吐量,从而反过来作用到shuffle网络吞吐量的提升。

上面的图片对比了单线程对800万复杂行做shuffle的性能,分别使用的是Kryo和代码生成,在速度上后者是前者的2倍以上。

Tungsten和未来的工作

在未来的几个版本中,Tungsten将大幅度提升Spark的核心引擎。它首先将登陆Spark 1.4版本,包括了Dataframe API中聚合操作的内存管理,以及定制化序列化器。二进制内存管理的扩展和cache-aware数据结构将出现在Spark 1.5的部分项目(基于DataFrame模型)中。当然如果需要的话,这个提升也会应用到Spark RDD API。

对于Spark,Tungsten是一个长期的项目,因此也存在很多的可能性。值得关注的是,我们还将考察LLVM或者OpenCL,让Spark应用程序可以利用新型CPU所提供的SSE/SIMD指令,以及GPU更好的并行性来提升机器学习和图的计算。

Spark不变的目标就是提供一个单一的平台,让用户可以从中获得更好的分布式算法来匹配任何类型的数据处理任务。其中,性能一直是主要的目标之一,而Tungsten的目标就是让Spark应用程序达到硬件性能的极限。更多详情可以持续关注Databricks博客,以及6月旧金山的Spark Summit。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2015-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 about云 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Spark重点难点06】SparkSQL YYDS(中)!
在上节课中我们讲解了Spark SQL的来源,Spark DataFrame创建的方式以及常用的算子。这节课继续讲解Spark SQL中的Catalyst优化器和Tungsten,以及Spark SQL的Join策略选择。
王知无-import_bigdata
2021/12/16
7770
【Spark重点难点06】SparkSQL YYDS(中)!
flink二三事(2):起家的技术
上一篇聊到flink的历史,请看上篇 flink两三事 ----(1)历史。 可以说基本上是起了个大早,赶了个晚集,但是flink能做今天这种热度,没有被spark干死也是不容易。原来大家都在想办法突破MapReduce太慢的问题时候,除了spark,比如还有Tez等框架基本上销声匿迹了。14年flink在apache孵化能活下来并成为顶级项目的关键还是flink的有些自己的创新技术。 Spark的核心概念是RDD,抽象概念是弹性分布式数据集(RDD),它是一个元素集合,划分到集群的各个节点上,可以被并行操
大数据和云计算技术
2018/03/08
1.2K0
flink二三事(2):起家的技术
Spark Tungsten-sort Based Shuffle 分析
看这篇文章前,建议你先简单看看Spark Sort Based Shuffle内存分析。
用户2936994
2018/08/27
1.5K0
Spark Tungsten-sort  Based Shuffle 分析
Spark性能优化总结
Spark的瓶颈一般来自于集群(standalone, yarn, mesos, k8s)的资源紧张,CPU,网络带宽,内存。通过都会将数据序列化,降低其内存memory和网络带宽shuffle的消耗。
王知无-import_bigdata
2020/04/02
1.5K0
【Spark重点难点07】SparkSQL YYDS(加餐)!
Spark发展到今天,Spark SQL的方式已经是官方推荐的开发方式了。在今年的Spark 3.0大版本发布中,Spark SQL的优化占比将近50%;而像PySpark、Mllib 和 Streaming的优化占比都不超过10%,Graph的占比几乎可以忽略不计。
王知无-import_bigdata
2021/12/22
8090
【Spark重点难点07】SparkSQL YYDS(加餐)!
【Spark篇】---Spark中内存管理和Shuffle参数调优
Spark执行应用程序时,Spark集群会启动Driver和Executor两种JVM进程,Driver负责创建SparkContext上下文,提交任务,task的分发等。Executor负责task的计算任务,并将结果返回给Driver。同时需要为需要持久化的RDD提供储存。Driver端的内存管理比较简单,这里所说的Spark内存管理针对Executor端的内存管理。
LhWorld哥陪你聊算法
2018/09/13
1.5K0
【Spark篇】---Spark中内存管理和Shuffle参数调优
Apache Spark 内存管理详解(下)
弹性分布式数据集(RDD)作为Spark最根本的数据抽象,是只读的分区记录(Partition)的集合,只能基于在稳定物理存储中的数据集上创建,或者在其他已有的RDD上执行转换(Transformation)操作产生一个新的RDD。转换后的RDD与原始的RDD之间产生的依赖关系,构成了血统(Lineage)。凭借血统,Spark保证了每一个RDD都可以被重新恢复。但RDD的所有转换都是惰性的,即只有当一个返回结果给Driver的行动(Action)发生时,Spark才会创建任务读取RDD,然后真正触发转换的执行。
大数据技术架构
2019/08/16
1.2K0
Apache Spark 内存管理详解(下)
Spark内存调优
Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色。理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优。本文旨在梳理出 Spark 内存管理的脉络,抛砖引玉,引出读者对这个话题的深入探讨。本文中阐述的原理基于 Spark 2.1 版本,阅读本文需要读者有一定的 Spark 和 Java 基础,了解 RDD、Shuffle、JVM 等相关概念。
王知无-import_bigdata
2019/06/03
1.4K0
PySpark 中的 Tungsten 项目是什么?它如何提升内存和 CPU 的性能?
Tungsten 是 Apache Spark 项目中的一个子项目,旨在通过优化内存管理和计算执行来提高 Spark 的性能。Tungsten 项目的引入主要是为了解决 Spark 在处理大规模数据集时的性能瓶颈问题,特别是在内存使用和 CPU 利用率方面。
代码小李
2025/01/26
1970
【Spark重点难点】你的代码跑起来谁说了算?(内存管理)
这节课我们要讲的是Spark中的 【内存模型】,也就是决定我们Spark代码运行所需要的资源信息。
王知无-import_bigdata
2021/12/08
8390
【Spark重点难点】你的代码跑起来谁说了算?(内存管理)
Spark系列 - (5) Spark Shuffle
有些运算需要将各节点上的同一类数据汇集到某一节点进行计算,把这些分布在不同节点的数据按照一定的规则汇集到一起的过程称为Shuffle。
码老思
2023/10/19
5010
Spark系列 - (5) Spark Shuffle
Apache Spark作为编译器:深入介绍新的Tungsten执行引擎
《Spark 2.0技术预览:更容易、更快速、更智能》文中简单地介绍了Spark 2.0相关技术, 本文将深入介绍新的Tungsten执行引擎。Apache Spark已经非常快了,但是我们能不能让它再快10倍? 这个问题使得我们从根本上重新思考Spark物理执行层的设计。当你随便调查一个现代数据引擎(比如Spark、其他的MPP数据库),你会发现大部分的CPU周期都花费在无用的工作之上,比如虚函数的调用;或者读取/写入中间数据到CPU高速缓存或内存中。通过减少花在这些无用功的CPU周期一直是现代编译器长期
CSDN技术头条
2018/02/12
1.3K0
Apache Spark作为编译器:深入介绍新的Tungsten执行引擎
Spark性能调优05-Shuffle调优
在Spark的源码中,负责shuffle过程的执行、计算和处理的组件主要就是ShuffleManager,也即shuffle管理器。而随着Spark的版本的发展,ShuffleManager也在不断迭代,变得越来越先进。
CoderJed
2018/09/13
1.7K0
Spark性能调优05-Shuffle调优
[SPARK][CORE] 面试问题之UnsafeShuffleWriter流程解析(上)
在说UnsafeShuffleWriter 前,需要先细谈下Tungsten对内存管理的优化。当然这里就不展开讲了以防内容过于冗长。
Tim在路上
2022/05/29
4390
[SPARK][CORE] 面试问题之UnsafeShuffleWriter流程解析(上)
Spark Shuffle
在分析 Spark Shuffle 内存使用之前。我们首先了解下以下问题:当一个 Spark 子任务 (Task) 被分配到 Executor 上运行时,Spark 管理内存以及消费内存的大体模型是什么样呢?(注:由于 OOM 主要发生在 Executor 端,所以接下来的讨论主要针对 Executor 端的内存管理和使用)。
用户1483438
2022/03/25
4340
Spark内部原理
Spark中的Shuffle、宽依赖窄依赖、RDD持久化、共享变量
俺也想起舞
2019/07/24
8010
大数据技术之_19_Spark学习_07_Spark 性能调优小结
========== Spark 的监控方式 ========== 1、Spark Web UI Spark 内置应用运行监控工具(提供了应用运行层面的主要信息--重要) 2、Ganglia 分析集群的使用状况和资源瓶颈(提供了集群的使用状况--资源瓶颈--重要) 3、Nmon 主机 CPU、网络、磁盘、内存(提供了单机信息) 4、Jmeter 系统实时性能监控工具(提供了单机的实时信息) 5、Jprofile Java 程序性能监控工具(提供了对应用程序开发和JVM的监控--次重要)
黑泽君
2019/05/14
5980
Spark调优 | Spark OOM问题常见解决方式
Spark常见的问题不外乎OOM。我们首先看一下Spark 的内存模型:Spark在一个Executor中的内存分为三块,一块是execution内存,一块是storage内存,一块是other内存。
大数据技术架构
2021/11/23
3.6K0
Spark 性能优化指南(官网文档)
由于大多数Spark组件基于内存的特性,Spark程序可能会因为集群中的任何资源而导致出现瓶颈:CPU、网络带宽或内存。通常情况下,如果数据适合于放到内存中,那么瓶颈就是网络带宽,但有时,我们还是需要内存进行一些调优的,比如以序列化的形式保存RDDs,以便减少内存占用。
大数据学习指南
2022/05/26
8770
大数据技术之_19_Spark学习_06_Spark 源码解析 + Spark 通信架构、脚本解析、standalone 模式启动、提交流程 + Spark Shuffle 过程 + Spark 内存
上图展示了 2 个 RDD 进行 JOIN 操作,体现了 RDD 所具备的 5 个主要特性,如下所示:   • 1)一组分区   • 2)计算每一个数据分片的函数   • 3)RDD 上的一组依赖   • 4)可选,对于键值对 RDD,有一个 Partitioner(通常是 HashPartitioner)   • 5)可选,一组 Preferred location 信息(例如,HDFS 文件的 Block 所在 location 信息) 有了上述特性,能够非常好地通过 RDD 来表达分布式数据集,并作为构建 DAG 图的基础:首先抽象一个分布式计算任务的逻辑表示,最终将任务在实际的物理计算环境中进行处理执行。
黑泽君
2019/05/14
1.6K0
大数据技术之_19_Spark学习_06_Spark 源码解析 + Spark 通信架构、脚本解析、standalone 模式启动、提交流程 + Spark Shuffle 过程 + Spark 内存
相关推荐
【Spark重点难点06】SparkSQL YYDS(中)!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档