1 背景及目的

对于ODPS上的运行时间长的任务来说,针对不同的问题有不同的优化方法(详见其他章节)。但是对于一些特殊场景的任务来说,除了从业务上可以进行优化之外,还需要通过一些辅助的参数设置才能达到比较好的优化效果。因此,ODPS提供了很多性能参数供开发人员使用。

2 参数介绍

2.1 资源参数

ODPS处理一个任务主要分为三个阶段:Map、Reduce、Join。如果处理的数据量比较大,导致各个阶段的每个Instance处理的的时间比较长,在没有发生倾斜的情况下,可以通过设置下面的资源参数增加资源来加快处理速度。

2.1.1 Map设置

set odps.sql.mapper.cpu=100

作用:设置处理Map Task每个Instance的CPU数目,默认为100,在[50,800]之间调整。
场景:某些任务如果特别耗计算资源的话,可以适当调整Cpu数目。对于大多数Sql任务来说,一般不需要调整Cpu个数的。

set odps.sql.mapper.memory=1024

作用:设定Map Task每个Instance的Memory大小,单位M,默认1024M,在[256,12288]之间调整。
场景:当Map阶段的Instance有Writer Dumps时,可以适当的增加内存大小,减少Dumps所花的时间。

set odps.sql.mapper.merge.limit.size=64

作用:设定控制文件被合并的最大阈值,单位M,默认64M,在[0,Integer.MAX_VALUE]之间调整。
场景:当Map端每个Instance读入的数据量不均匀时,可以通过设置这个变量值进行小文件的合并,使得每个Instance的读入文件均匀。一般会和odps.sql.mapper.split.size这个参数结合使用。

set odps.sql.mapper.split.size=256

作用:设定一个Map的最大数据输入量,可以通过设置这个变量达到对Map端输入的控制,单位M,默认256M,在[1,Integer.MAX_VALUE]之间调整。
场景:当每个Map Instance处理的数据量比较大,时间比较长,并且没有发生长尾时,可以适当调小这个参数。如果有发生长尾,则结合odps.sql.mapper.merge.limit.size这个参数设置每个Map的输入数量。

2.1.2 Join设置

set odps.sql.joiner.instances=-1

作用: 设定Join Task的Instance数量,默认为-1,在[0,2000]之间调整。不走HBO优化时,ODPS能够自动设定的最大值为1111,手动设定的最大值为2000,走HBO时可以超过2000。
场景:每个Join Instance处理的数据量比较大,耗时较长,没有发生长尾,可以考虑增大使用这个参数。

set odps.sql.joiner.cpu=100

作用: 设定Join Task每个Instance的CPU数目,默认为100,在[50,800]之间调整。
场景:某些任务如果特别耗计算资源的话,可以适当调整CPU数目。对于大多数SQL任务来说,一般不需要调整CPU。

set odps.sql.joiner.memory=1024

作用:设定Join Task每个Instance的Memory大小,单位为M,默认为1024M,在[256,12288]之间调整。
场景:当Join阶段的Instance有Writer Dumps时,可以适当的增加内存大小,减少Dumps所花的时间。

2.1.3 Reduce设置

set odps.sql.reducer.instances=-1

作用: 设定Reduce Task的Instance数量,默认为-1,在[0,2000]之间调整。不走HBO优化时,ODPS能够自动设定的最大值为1111,手动设定的最大值为2000,走HBO优化时可以超过2000。
场景:每个Join Instance处理的数据量比较大,耗时较长,没有发生长尾,可以考虑增大使用这个参数。

set odps.sql.reducer.cpu=100

作用:设定处理Reduce Task每个Instance的Cpu数目,默认为100,在[50,800]之间调整。
场景:某些任务如果特别耗计算资源的话,可以适当调整Cpu数目。对于大多数Sql任务来说,一般不需要调整Cpu。

set odps.sql.reducer.memory=1024

作用:设定Reduce Task每个Instance的Memory大小,单位M,默认1024M,在[256,12288]之间调整。
场景:当Reduce阶段的Instance有Writer Dumps时,可以适当的增加内存的大小,减少Dumps所花的时间。

上面这些参数虽然好用,但是也过于简单暴力,可能会对集群产生一定的压力。特别是在集群整体资源紧张的情况下,增加资源的方法可能得不到应有的效果,随着资源的增大,等待资源的时间变长的风险也随之增加,导致效果不好!因此请合理的使用资源参数!

2.2 小文件合并参数

set odps.merge.cross.paths=true|false

作用:设置是否跨路径合并,对于表下面有多个分区的情况,合并过程会将多个分区生成独立的Merge Action进行合并,所以对于odps.merge.cross.paths设置为true,并不会改变路径个数,只是分别去合并每个路径下的小文件。

set odps.merge.smallfile.filesize.threshold = 64

作用:设置合并文件的小文件大小阀值,文件大小超过该阀值,则不进行合并,单位为M,可以不设,不设时,则使用全局变量odps_g_merge_filesize_threshold,该值默认为32M,设置时必须大于32M。

set odps.merge.maxmerged.filesize.threshold = 256

作用:设置合并输出文件量的大小,输出文件大于该阀值,则创建新的输出文件,单位为M,可以不设,不设时,则使用全局变odps_g_max_merged_filesize_threshold,该值默认为256M,设置时必须大于256M。

set odps.merge.max.filenumber.per.instance = 10000

作用:设置合并Fuxi Job的单个Instance允许合并的小文件个数,控制合并并行的Fuxi Instance数,可以不设,不设时,则使用全局变量odps_g_merge_files_per_instance,该值默认为100,在一个Merge任务中,需要的Fuxi Instance个数至少为该目录下面的总文件个数除以该限制。

set odps.merge.max.filenumber.per.job = 10000

作用:设置合并最大的小文件个数,小文件数量超过该限制,则超过限制部分的文件忽略,不进行合并,可以不设,不设时,则使用全局变量odps_g_max_merge_files,该值默认为10000。

2.3 UDF相关参数

set odps.sql.udf.jvm.memory=1024

作用: 设定UDF JVM Heap使用的最大内存,单位M,默认1024M,在[256,12288]之间调整。
场景:某些UDF在内存计算、排序的数据量比较大时,会报内存溢出错误,这时候可以调大该参数,不过这个方法只能暂时缓解,还是需要从业务上去优化。

set odps.sql.udf.timeout=600

作用:设置UDF超时时间,默认为600秒,单位秒。[0,3600]之间调整。

set odps.sql.udf.python.memory=256

作用:设定UDF python 使用的最大内存,单位M,默认256M。[64,3072]之间调整。

set odps.sql.udf.optimize.reuse=true/false

作用:开启后,相同的UDF函数表达式,只计算一次,可以提高性能,默认为True。

set odps.sql.udf.strict.mode=false/true

作用:True为金融模式,False为淘宝模式,控制有些函数在遇到脏数据时是返回NULL还是抛异常,True是抛出异常,False是返回null。

2.4 Mapjoin设置

set odps.sql.mapjoin.memory.max=512

作用:设置Mapjoin时小表的最大内存,默认512,单位M,[128,2048]之间调整。

2.5 动态分区设置

set odps.sql.reshuffle.dynamicpt=true/false

作用:False:会减少小文件的产生,如果动态分区值很少,关闭数据就不会倾斜了。True:不会数据倾斜。

2.6 数据倾斜设置

set odps.sql.groupby.skewindata=true/false

作用:开启Group By优化。

set odps.sql.skewjoin=true/false

作用:开启Join优化,必须设置odps.sql.skewinfo 才有效。

set odps.sql.skewinfo

作用:设置join优化具体信息,格式:set odps.sql.skewinfo=skewed_src:(skewed_key)[("skewed_value")]例子:针对单个字段单个倾斜数值

set odps.sql.skewinfo=src_skewjoin1:(key)[("0")]
explain select a.key c1, a.value c2, b.key c3, b.value c4 from src a join src_skewjoin1 b on a.key = b.key;
针对单个字段多个倾斜数值

set odps.sql.skewinfo=src_skewjoin1:(key)[("0")("1")]
explain select a.key c1, a.value c2, b.key c3, b.value c4 from src a join src_skewjoin1 b on a.key = b.key;
2.7 Sevice Mode

odps.service.mode=limited/all/off

作用:开启/关闭准实时模式,限制脚本运行时间,默认为Off。
例子:set odps.service.mode=all开启后任务超时会出现:

failed:instance running interval is over live time(600)
注:Limited表示尽量使用Service Mode,All表示强制使用。

3 案例介绍

Map Split块大小设置,即调整Map Instance的个数,默认为:
set odps.sql.mapper.split.size=256p_w_picpath

调整Split Size后:
set odps.sql.mapper.split.size=128
计算时间减少1倍,因为文件块小了,那么导致输出的时候就有大量的小文件需要合并,合并时间增大4倍,得不偿失。p_w_picpath

继续设置:
set odps.sql.mapper.split.size=192
可以看到在计算时间和合并文件的时间都达到一个平衡点:p_w_picpath

总结:mapper.split.size的大小要慎重设置,否则会出现这个任务快了,其它的任务慢了,这是一个相互平衡的过程。

4 总结

尽量不要通过设置参数的方式进行优化,首先要看能否从业务上或者算法上减少数据和其他方式进行优化。

设置参数的话,要首先确定是Map、Reduce、Join哪个阶段的任务时间长,从而设置对应的参数。

在没有出现数据倾斜的情况下,如果通过设置Cpu参数(含Memory参数)和设置Instance个数两种方式都能调优的话,最好是先设置Instance个数。因为如果Cpu/Memory参数设置不合理,执行任务的机器满足不了参数的要求,要重新找机器的,这样反而会影响效率。如果执行日志中出现Dump,最好是Instance个数和Memory都增大一下。

Instance的个数设置,有个简单的方法是二分法。先设置个很大的,如果不能满足要求,那么就继续增大,如果满足了要求,就折半降低参数大小,最终找到一个合适的值。

原则上来说,ODPS的调度系统会在程序运行三次后,就开启HBO(CBO)的优化方案,这个时候就可以考虑把设置的参数去掉,让系统分配合适的资源,如果不能满足要求,再设置参数。

默认的Reduce Instance的个数,与Map Instance个数是成一定比例关系的(一般是几分之几)。如果设置Reduce Instance参数的话,就会突破这个限制。默认的Join参数的个数一般是参加Join的任务的Instance个数之和。

原文链接:http://click.aliyun.com/m/14014/