Spark之Mapper端和Reduce端调优

Spark在shuffle分为两部分,Mapper端和Reduce端

一、Mapper端调优

假设Mapper端有3个Task,task1,task2,task3,Reducer有两个Task,task1,task2

数据传输到Reducer端的时候首先进行Mapper端的处理,Mapper端的处理很简单,Mapper端有一个Cache写入文件,Mapper端的缓冲层根据Reducer端的需要,将数据分成既定的分区。Reducer端抓取属于自己的数据进行Reduce操作,Reduce端也有Cache。

(1)Mapper端通过缓存层不断地把数据写入文件系统,并汇报给Driver。

(2)Reducer端把相同的Key放在同一个Task中,并进行业务逻辑的处理。

如果Mapper端每个task负责处理的数据量很大,比如要处理百万数据量级别假设是(16G),缓存层大小是16k,那么会出现

100万次的磁盘读写。reducer端读取这些数据,reducer缓存设置的不合理,也会溢写到磁盘,造成大量磁盘IO。

Mapper端的调优主要是调整Mapper端的缓存大小,参数:spark.shuffle.file.buffer(默认值是32KB),根据数据量和机器内存适当的调整缓存层大小,观察任务运行的情况。

二、Reducer端调优

假设在Mapper端有3个Task:Task1、Task2、Task3;在Reducer端有2个任务:Task1、Task2。
从Reducer端的角度考虑,每个Task生成几个部分的文件,因为在Shuffle的时候,有不同的Shuffle策略:Hash的方式,排序的方式等等。
在Mapper端和Reducer端中间加一个Cache缓存,Reducer端的Task有2个,所以文件会有2个小部分的文件。filepart1、filepart2。这里不是指第一个文件,第二个文件,而是文件的第一部分,第二部分。Mapper端Task的数据有2部分,是因为Reducer端有2个并行的Task,不同的Shuffle策略会说明怎么分这2部分。

Cache缓存层分别从不同Task的filepart1、filepart2抓到属于自己的数据,把属于自己的数据拿到Cache缓存层。然后把Cache中的数据抓到Reducer端,在Redcuer端里面对RDD进行一系列业务逻辑的处理。

整个Spark的作业每个Job分成Mapper端、Reducer端,由于是链式表达式,可能很多Mapper端、Reducer端,其实可以看一个很长的链条,但这里只要看一个Mapper、Reducer。Mapper端产生数据会分成若干个部分,分成几部分是由Reducer端的并行度决定的,这里分成filepart1,filepart2,也可能是在一个文件中,例如排序的方式就在一个文件或者是Hash的方式,采用了文件压缩。Reducer端去获取具体数据的时候,Reducer端的前端有一个缓存层Cache,持续从Mapper端的Task输出中不断的去抓到属于自己的数据,Reducer端通过transformation对业务逻辑代码对抓到的数据进行处理。

考虑如下几种场景

(1)Reducer端的缓存层

Mapper端不断的输出数据,因为根据不同的作业以及作业不同的阶段,数据可能很多,也可能很少;Reducer端要运行Task,是否要等到Mapper端将所有的数据都写到磁盘中之后,Reducer端才向Mapper端去抓数据?不是的!这里是一边Shuffle一边处理,在进行Shuffle的过程中,抓数据中间有一个缓冲层,类似java nio方式读写文件,所以缓存层不是等Mapper端把所有的数据都放到filepart1,filepart2才处理,而是数据存入一点,就读取一点。然后Reducer端的Task的代码进行业务处理。

一边读取数据一遍处理,那Reducer端最多能拉取多少数据?由谁来决定?这个由缓存层决定的!在Reducer端的代码部分,代码是基于缓冲层处理数据的。默认配置是为每个task配置48MB的缓存大小,设置参数:spark.reducer.maxSizeInFlight。

那么实际生产环境缓存层的大小一般多大合适?

Reducer端的性能调优参数spark.shuffle.memoryFraction默认大小是0.2,Reducer端的业务逻辑运行占用Executor的内存大小的20%,调整的时候可以从0.2调到0.3、0.4等。调整的越大,Spill到磁盘的次数就越少,次数越少那从磁盘中读取文件的时候数量也会越小。

(2)Reducer端的堆

从Mapper端抓取的数据先放到缓冲层,然后才用Task执行抓到的数据,那Reducer端执行级别默认情况下的Task堆的大小是20%的空间,可以进行调整。

如果Reducer端的缓存层的数据特别大,会不会有问题?

一般情况下,Mapper端的数据不是特别多,远远达不到配置的限额,这种情况下不会出问题。但如果Mapper端的数据特别大,Reducer端抓数据到自己的缓存层的时候,每一次缓存层都填满, 这个时候再加上Reducer端Task运行的时候分配的对象,就有可能导致大量的对象创建,Reducer端就发生了OOM。

生产环境遇到这个问题,怎么办?可能有人提出增加executor、增加内存,但在实际生产环境中,资源被严格限制,所以先从我们知识技能的层面,在不改变资源的情况下,考虑我们如何去处理。这个时候比较简单的方式就是将Reducer端的Cache层减少。例如原先缓存层是48M发生了OOM,将参数调整成24M就行了。这是最简单最直接的解决方案。先让程序跑起来,然后才让程序跑的更快。这个想法跟平时单机版本的想法完全一样,如果单机版本发现OOM,是调大缓存大小还是调小缓存大小?确实要调小缓存大小。例如:单机版本中分配一个很大的数组集,就会造成oom,那把数组改小就可以了。

缓存层变小了,那向Mapper层拉取数据的次数变多了,Shuffle的次数变得更多了,也就是性能降低。此时增加executor,分配更多的内存,然后再调大缓存大小

(3)shuffle file not found

Shuffle file not found找不到,原因有可能是GC,无论是Minor GC还是final GC,只要有GC,就有可能在map端GC的时候我们无法把数据抓过来。

一般情况下当Executor进行GC的时候,所有的线程都停止工作,当然包括进行数据传输的Netty中的线程也会停止工作,所以就暂时无法获取数据。

当Reducer端根据Driver端提供的信息到Mapper中指定的位置去获取属于自己的数据的时候,首先会去定位数据所在的文件,而此时可能发生shufle file not found的错误。这个错误的出现一般是由于Mapper端正在进行GC,然后去请求数据的时候没有响应,spark.shuffle.io.maxRetries=3

spark.shuffle.io.retryWait =5s

默认情况下15s中还没有拉到属于自己的数据就会出现shufflefile not found的错误。

解决办法是调大上述参数:
spark.shuffle.io.maxRetries =30
spark.shuffle.io.retryWait =30s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值