本文档是参考多个博客以及Hadoop2.5.0和Hive0.13.1的配置文件及源码整理出来的,未做详细解释的部分可以在文章尾查看参考文档
一、硬件优化
1、配置
二、网络优化
1、交换机
⑴普通交换机:网线连接服务器,便宜,常用,数据交换能力一般;
⑵光纤交换机:光纤连接服务器,比较贵,数据交换能力强;
⑶带宽(最好千兆以上);
三、MR优化
1、map优化
⑴map的优化,主要是确定合适的mapper数(默认等于block数)。
⑵map的计算公式
①getFormatMinSplitSize()默认为1byte,getMinSplitSize(job)返回的就是属性②mapreduce.input.fileinputformat.split.minsize的值,默认为1Lbyte;
③getMaxSplitSize(job)返回的值是Long.MAX_VALUE,对应的十进制为9223372036854775807约等于9EB;
④所以getFormatMinSplitSize()就是为了确定分片下限的,getMaxSplitSize(job)就是确定分片上限的;
⑤通过上面的分析,我们可以得出,分片的大小取决于Math.max("mapreduce.input.fileinputformat.split.minsize", blockSize)),这两个参数是我们可以配置的,再根据文件大小就可以确定mapper数量了;
源码分析见:hadoop2如何确定map数量
实际应用
⑴减小Map-Reduce job 启动时创建的Mapper数量
当处理大批量的大数据时,一种常见的情况是job启动的mapper数量太多而超出了系统限制,导致Hadoop抛出异常终止执行。解决这种异常的思路是减少mapper的数量。具体如下:
①输入文件size巨大,但不是小文件
这种情况可以通过增大每个mapper的input size,即增大minSize或者增大blockSize来减少所需的mapper的数量。增大blockSize通常不可行,因为当HDFS被hadoop namenode -format之后,blockSize就已经确定了(由格式化时dfs.block.size决定),如果要更改blockSize,需要重新格式化HDFS,这样当然会丢失已有的数据。所以通常情况下只能通过增大minSize,即增大mapreduce.input.fileinputformat.split.minsize的值。
②输入文件数量巨大,且都是小文件
所谓小文件,就是单个文件的size小于blockSize。这种情况通过增大mapreduce.input.fileinputformat.split.minsize不可行,需要使用FileInputFormat衍生的CombineFileInputFormat将多个input path合并成一个InputSplit送给mapper处理,从而减少mapper的数量。具体细节稍后会更新并展开。
⑵增加Map-Reduce job 启动时创建的Mapper数量
增加mapper的数量,可以通过减小每个mapper的输入做到,即减小blockSize或者减小mapreduce.input.fileinputformat.split.minsize的值。
注释:
调整大小的时机根据查询的不同而不同,总的来讲可以通过观察Map task的完成时间来确定是否需要增加Map资源。如果Map task的完成时间都是接近1分钟,甚至几分钟了,那么往往增加Map数量,使得每个Map task处理的数据量减少,能够让Map task更快完成;而如果Map task的运行时间已经很少了,比如10-20秒,这个时候增加Map不太可能让Map task更快完成,反而可能因为Map需要的初始化时间反而让Job总体速度变慢,这个时候反而需要考虑是否可以把Map的数量减少,这样可以节省更多资源给其他Job。
2、reduce优化
⑴reduce的优化,主要是确定reducer的数量;
⑵如果不需要Reducer,可以使用Job.setNumReduceTasks(int)将Reducer的数量设置为0(如果不使用该方法设置Reducer的数量,由于mapreduce.job.reduces默认为1,会启动一个Reducer);
⑶增加Reducer的数量虽然增加了框架开销,但增加了负载平衡和降低了失败的成本。
3、spill与sort优化
在Spill阶段,由于内存不够,数据可能没办法在内存中一次性排序完成,那么就只能把局部排序的文件先保存到磁盘上,这个动作叫Spill,然后Spill出来的多个文件可以在最后进行merge。如果发生Spill,可以通过设置mapreduce.task.io.sort.mb(默认100M)来增大Mapper输出buffer的大小,避免Spill的发生。另外合并时可以通过设置mapreduce.task.io.sort.factor(默认10)来使得一次性能够合并更多的数据。调试参数的时候,一个要看Spill的时间成本,一个要看merge的时间成本,还需要注意不要撑爆内存(mapreduce.task.io.sort.mb是算在Map的内存里面的)。Reduce端的merge也是一样可以用mapreduce.task.io.sort.factor。一般情况下这两个参数很少需要调整,除非很明确知道这个地方是瓶颈。
4、copy优化
copy阶段是把文件从Map端copy到Reduce端。默认情况下在5%的Map完成的情况下Reduce就开始启动copy,这个有时候是很浪费资源的,因为Reduce一旦启动就被占用,一直等到Map全部完成,收集到所有数据才可以进行后面的动作,所以我们可以等比较多的Map完成之后再启动Reduce流程,这个比例可以通mapreduce.job.reduce.slowstart.completedmaps去调整,他的默认值就是5%。如果觉得这么做会减慢Reduce端copy的进度,可以把copy过程的线程增大。mapreduce.tasktracker.http.threads(默认40)可以决定作为server端的Map用于提供数据传输服务的线程,mapreduce.reduce.shuffle.parallelcopies(默认5)可以决定作为client端的Reduce同时从Map端拉取数据的并行度(一次同时从多少个Map拉数据),修改参数的时候这两个注意协调一下,server端能处理client端的请求即可。
5、文件格式
四、Job优化
1、Job执行模式
Hadoop的Map Reduce Job可以有3种模式执行,即本地模式,伪分布式,还有真正的分布式。本地模式和伪分布式都是在最初学习Hadoop的时候往往被说成是做单机开发的时候用到。但是实际上对于处理数据量非常小的Job,直接启动分布式Job会消耗大量资源,而真正执行计算的时间反而非常少。这个时候就应该使用本地模式执行mr Job,这样执行的时候不会启动分布式Job,执行速度就会快很多。比如一般来说启动分布式Job,无论多小的数据量,执行时间一般不会少于20s,而使用本地mr模式,10秒左右就能出结果。
设置执行模式的主要参数有三个,一个是Hive.exec.mode.local.auto,把他设为true就能够自动开启local mr模式。但是这还不足以启动local mr,输入的文件数量和数据量大小必须要控制,这两个参数分别为Hive.exec.mode.local.auto.tasks.max和Hive.exec.mode.local.auto.inputbytes.max,默认值分别为4和128MB,即默认情况下,Map处理的文件数不超过4个并且总大小小于128MB就启用local mr模式。
2、JVM重用
正常情况下,MapReduce启动的JVM在完成一个task之后就退出了,但是如果任务花费时间很短,又要多次启动JVM的情况下(比如对很大数据量进行计数操作),JVM的启动时间就会变成一个比较大的overhead。在这种情况下,可以使用jvm重用的参数mapreduce.job.jvm.numtasks(默认为1,设置为-1时则不受限制),他的作用是让一个jvm运行多次任务之后再退出。这样一来也能节约不少JVM启动时间。
3、索引
4、join算法
处理分布式join,一般有两种方法:
⑴replication join:把其中一个表复制到所有节点,这样另一个表在每个节点上面的分片就可以跟这个完整的表join了;
⑵repartition join:把两份数据按照join key进行hash重分布,让每个节点处理hash值相同的join key数据,也就是做局部的join。
5、数据倾斜
所谓数据倾斜,说的是由于数据分布不均匀,个别值集中占据大部分数据量,加上Hadoop的计算模式,导致计算资源不均匀引起性能下降。
五、Hql优化
1、表连接优化
2、排序
3、insert into 替换 union all
4、limit
5、自定义函数
六、平台优化
1、Hive on tez
2、Spark sql
七、参考文档
3、