spark调优篇-oom 优化(汇总)
spark 之所以需要调优,一是代码执行效率低,二是经常 OOM
内存溢出
内存溢出无非两点:
1. Driver 内存不够
2. Executor 内存不够
Driver 内存不够无非两点:
1. 读取数据太大
2. 数据回传
Executor 内存不够无非两点:
1. map 类操作产生大量数据,包括 map、flatMap、filter、mapPartitions 等
2. shuffle 后产生数据倾斜
Executor 内存不够
有个通用的解决办法就是增加 Executor 内存
--executor-memory MEM Memory per executor (e.g. 1000M, 2G) (Default: 1G).
但这并不一定是最好的办法
map 过程产生大量对象
造成 Executor 内存溢出
解决思路是减少每个 task 的大小,从而减少每个 task 的输出;
具体做法是在 会产生大量对象的 map 操作前 添加 repartition(重新分区) 方法,分区成更小的块传入 map
rdd.flatMap(lambda x: ['%d'%x*50 for _ in range(100000000)]).count() # 100 * 100000000 个对象,内存溢出
rdd.flatMap(lambda x: len(['%d'%x*50 for _ in range(100000000)])).sum() # 内存溢出 rdd.repartition(1000000).flatMap(lambda x: ['%d'%x*50 for _ in range(100000000)]).count() # 可执行
数据倾斜
参考我的博客 数据倾斜
standalone 模式资源分配不均
该模式下配置了
--total-executor-cores NUM (Total cores for all executors.) 集群 executor 核数
--executor-memory MEM Memory per executor (e.g. 1000M, 2G) (Default: 1G). 每个 executor 内存
而没有配置
--executor-cores NUM Number of cores per executor. (Default: 1 in YARN mode,
or all available cores on the worker in standalone mode) 每个 executor 核数
假如各个 executor 核数不一样,核数多的 executor 执行的 task 就多,内存就容易溢出
解决方法是配置参数 --executor-cores,或者是在 spark 中配置 spark.executor.cores
在 RDD 中共用对象
rdd = sc.parallelize(range(100))
def myfunc(x): return x
rdd.flatMap(lambda x: [('k', 'v') for _ in range(200000000)]).foreach(myfunc) # 每次生成一个 tuple 对象,内存溢出
rdd.flatMap(lambda x: ['k'+'v' for _ in range(2000000)]).count() # 无需生成新的 string 对象,可执行
tuple 为不可变对象,不过字符串也是可变对象
此条方法有待进一步验证
Driver 中需要读取大量数据
造成 Driver 内存溢出
解决思路是增加 Driver 内存,具体做法为设置参数
--driver-memory MEM Memory for driver (e.g. 1000M, 2G) (Default: 1024M).
示例
from pyspark import SparkContext
sc = SparkContext(master='yarn')
rdd = sc.parallelize(range(300000000))
# spark-submit --master yarn-client --driver-memory 512M driver_oom.py 内存溢出
# spark-submit --master yarn-client --driver-memory 3G driver_oom.py 可以执行
collect
大量数据回传 Driver,造成内存溢出
解决思路是分区输出,具体做法是 foreach
rdd = sc.parallelize(range(100))
rdd.flatMap(lambda x: ['%d'%x*50 for _ in range(100000)]).collect() # 内存溢出 def func(x): print(x)
rdd.flatMap(lambda x: ['%d'%x*50 for _ in range(100000)]).foreach(func) # 分区输出
或者增加 Driver 内存
代码优化
mapPartitions
1. 批处理
2. 减少中间输出
用 mapPartitions 替代多个 map,减少 Executor 内存压力
from pyspark import SparkContext
sc = SparkContext(master='yarn')
data = range(10)
rdd = sc.parallelize(data, 2) ##### map
rdd.map(lambda x: x % 3).filter(lambda x : x>1 ).countByValue().values() # [3] ##### mapPartitions
# 避免了中间 RDD 的产生,节约内存,防止 oom
def myfunc(datas):
# datas type is itertools.chain
for data in datas:
value = data % 3
if value > 1:
yield value print rdd.mapPartitions(myfunc).countByValue().values() # [3]
# spark-submit --master yarn-client mapVSmapPartitions.py python 只支持 client 模式
DataFrame 代替 RDD
任务被划分成多个 stage,在每个 stage 内部,RDD 是无法自动优化的,
rdd.map(lambda x: x+1).map(lambda x: x+1) == rdd.map(lambda x: x+2)
如上面两个操作是等价的,但是 RDD 并不会自动优化,
而 DataFrame 使用 sql 查询,自带 sql 优化器,可自动找到最优方案
broadcast join
在分布式计算中,数据跨节点移动是非常影响性能的,网络传输耗时,多次传输消耗内存,broadcast 在某些场景可以减少数据移动;
如 一个 小RDD 要和 一个 大RDD 进行 join 操作,常规情况下要互传 RDD,由于多个 task,故需多次传输, 【注意必须是有个小 RDD,否则这种做法意义不大,因为后面要遍历这个广播变量】
如果把 小RDD 变成 broadcast 变量,就不用传输 大RDD,把 broadcast(小RDD) 缓存在对应 Executor 上即可

对 大RDD 进行 map 操作,在 map 函数中调用 小RDD 的 value,遍历 小RDD
map(lambda x: i for i in smallRDD.value if x == i)
filter 之后再 join
就是所谓的谓词下推,在 sparkSQL 中会自动这么操作;
如果是自己操作 RDD,可以减少 shuffle 的数据量
cache and persist
缓存 RDD 既可以节省内存,也可以提高性能;
cahce 是缓存到内存,等同于 persist(Storage.MEMORY_ONLY),在内存不足时,这种缓存方式会丢失数据,再次使用时会重新计算;
rdd.persist(StorageLevel.MEMORY_AND_DISK_SER) 在内存不足时会写到磁盘,避免重复,只是耗费一点 IO 时间
combineByKey
在 hadoop 中也有 combine,有 combine 比 没有combine 效率高;
比如 reduceByKey (combine操作) 就比 groupyByKey (非combine操作) 效率高
import time
from pyspark import SparkContext sc = SparkContext(master='yarn') strs = list('abcd')*10000000
rdd = sc.parallelize(strs) time.clock()
print rdd.map(lambda x: (x, 1)).reduceByKey(lambda x, y: x+y).collect() # combinByKey 操作耗时少3.2s
# print rdd.map(lambda x: (x, 1)).groupByKey().mapValues(sum).collect() # 非 combinByKey 操作耗时3.6s
# 二者结果一样
print(time.clock()) strs = list('abcd')*10000000
for i in strs:i = (i, 1) # 6s,单机for循环做更少的事情,耗时更多
图解如下


参考资料:
https://blog.csdn.net/yhb315279058/article/details/51035631
spark调优篇-oom 优化(汇总)的更多相关文章
- spark调优篇-数据倾斜(汇总)
数据倾斜 为什么会数据倾斜 spark 中的数据倾斜并不是说原始数据存在倾斜,原始数据都是一个一个的 block,大小都一样,不存在数据倾斜: 而是指 shuffle 过程中产生的数据倾斜,由于不同的 ...
- Spark调优,性能优化
Spark调优,性能优化 1.使用reduceByKey/aggregateByKey替代groupByKey 2.使用mapPartitions替代普通map 3.使用foreachPartitio ...
- spark调优篇-Spark ON Yarn 内存管理(汇总)
本文旨在解析 spark on Yarn 的内存管理,使得 spark 调优思路更加清晰 内存相关参数 spark 是基于内存的计算,spark 调优大部分是针对内存的,了解 spark 内存参数有也 ...
- spark调优篇-spark on yarn web UI
spark on yarn 的执行过程在 yarn RM 上无法直接查看,即 http://192.168.10.10:8088,这对于调试程序很不方便,所以需要手动配置 配置方法 1. 配置 spa ...
- Linux网卡调优篇-禁用ipv6与优化socket缓冲区大小
Linux网卡调优篇-禁用ipv6与优化socket缓冲区大小 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一般在内网环境中,我们几乎是用不到IPV6,因此我们没有必要把多不 ...
- 性能优化 | JVM性能调优篇——来自阿里P7的经验总结
VM 调优概述: 性能定义: 吞吐量 - 指不考虑 GC 引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标. 延迟 - 其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收 ...
- Linux虚拟内存(swap)调优篇-“swappiness”,“vm.dirty_background_ratio”和“vm.dirty_ratio”
Linux虚拟内存(swap)调优篇-“swappiness”,“vm.dirty_background_ratio”和“vm.dirty_ratio” 作者:尹正杰 版权声明:原创作品,谢绝转载 ...
- 【Spark调优】Shuffle原理理解与参数调优
[生产实践经验] 生产实践中的切身体会是:影响Spark性能的大BOSS就是shuffle,抓住并解决shuffle这个主要原因,事半功倍. [Shuffle原理学习笔记] 1.未经优化的HashSh ...
- Spark调优秘诀——超详细
版权声明:本文为博主原创文章,转载请注明出处. Spark调优秘诀 1.诊断内存的消耗 在Spark应用程序中,内存都消耗在哪了? 1.每个Java对象都有一个包含该对象元数据的对象头,其大小是16个 ...
随机推荐
- jsp显示当前系统时间
第一种方式: <% java.text.SimpleDateFormat simpleDateFormat = new java.text.SimpleDateFormat( "yyy ...
- root of context hierarchy
Spring Boot项目,运行不明中断.日志如下: 2018-11-03 11:03:43.358 INFO [Thread-2][AbstractApplicationContext.java:9 ...
- 深入分析JAVA IO(BIO、NIO、AIO)
IO的基本常识 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否完成 2.异步 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程继续处理 3.阻塞 当一个线程调用 r ...
- Maven的安装和配置(Windows 10)
1. 官网下载Maven管理工具 官网:https://maven.apache.org/download.cgi 系统要求: JDK:Maven 3.3以上需要JDK 1.7以上版本支持 Memor ...
- ubuntu 上开发.netcore
ubuntu需要安装的软件: 1.sudo apt-get install openssh-server openssh-client 2.sudo apt-get git 3.安装vscode 4. ...
- .md 即 markdown 文件的基本常用编写语法
0. 前言 Markdown 是一种纯文本格式的标记语言.通过简单的标记语法,它可以使普通文本内容具有一定的格式.现在的项目都使用了 git 仓库,再加上远程仓库 github 托管,那就难免要写一些 ...
- 【ARTS】01_23_左耳听风-201900415~2019004021
ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...
- 二分类Logistic回归模型
Logistic回归属于概率型的非线性回归,分为二分类和多分类的回归模型.这里只讲二分类. 对于二分类的Logistic回归,因变量y只有“是.否”两个取值,记为1和0.这种值为0/1的二值品质型变量 ...
- 关于C++的智能指针
一句话概括:当类中有指针成员时,可以使用智能指针实现对象共享:智能指针通过引用计数实现,即对指向同一对象的指针计数:智能指针的使用可以方便/安全地控制对象的生命周期,对指针进行自动销毁. 当类中有指针 ...
- Note 2: Complain
Note 2: Complain 1. The collection of Linkun's [1]: 1.1suck If someone says that something sucks, th ...