Hadoop集群的优化方法

19 篇文章 7 订阅
2 篇文章 0 订阅

Hadoop优化

数据压缩

压缩前小思考

在学习这个数据压缩前,我们想想为什么要压缩?

压缩技术能够有效减少底层存储系统(HDFS)读写字节数。压缩提高了网络带宽和磁盘空间的效率。在运行MR程序时,I/O操作、网络数据传输、 Shuffle和Merge要花大量的时间,尤其是数据规模很大和工作负载密集的情况下,因此,使用数据压缩显得非常重要。

上面看到了压缩的好处,知道压缩可以节约很多的时间,但是所有的文件都适合压缩吗?

答案肯定是否定的,相信大多数人都和我一样的答案. 部分小文件压缩的话,肯定是得不偿失的.磁盘I/O和网络带宽是Hadoop的宝贵资源,数据压缩对于节省资源、最小化磁盘I/O和网络传输非常有帮助。可以在任意MapReduce阶段启用压缩。不过,尽管压缩与解压操作的CPU开销不高,其性能的提升和资源的节省并非没有代价。因此在压缩时也是需要想想是否利大于弊的.

看完上面两个问题过后,我们怎样去权衡压缩情况呢?或者说有哪些注意事项呢?

基本原则:

① 运算密集型的job,少用压缩

② IO密集型的job,多用压缩

注意:采用压缩技术减少了磁盘IO,但同时增加了CPU运算负担。所以,压缩特性运用得当能提高性能,但运用不当也可能降低性能。

MR支持的压缩编码

压缩格式hadoop自带?算法文件扩展名是否可切分换成压缩格式后,原来的程序是否需要修改
DEFLATE是,直接使用DEFLATE.deflate和文本处理一样,不需要修改
Gzip是,直接使用DEFLATE.gz和文本处理一样,不需要修改
bzip2是,直接使用bzip2.bz2和文本处理一样,不需要修改
LZO否,需要安装LZO.lzo需要建索引,还需要指定输入格式
Snappy是,直接使用Snappy.snappy和文本处理一样,不需要修改

为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器,如下表所示。

压缩格式对应的编码/解码器
DEFLATEorg.apache.hadoop.io.compress.DefaultCodec
gziporg.apache.hadoop.io.compress.GzipCodec
bzip2org.apache.hadoop.io.compress.BZip2Codec
LZOcom.hadoop.compression.lzo.LzopCodec
Snappyorg.apache.hadoop.io.compress.SnappyCodec

压缩性能的比较

压缩算法原始文件大小压缩文件大小压缩速度解压速度优缺点
gzip8.3GB1.8GB17.5MB/s58MB/s本身自带;效率较高高;但不支持split切分
bzip28.3GB1.1GB2.4MB/s9.5MB/s支持Split;具有很高的压缩率,比Gzip压缩率都高;本身自带;压缩速度慢;
LZO8.3GB2.9GB49.3MB/s74.6MB/s压缩/解压速度也比较快,合理的压缩率;支持Split;压缩率比Gzip要低一些;本身不支持,需要安装;在应用中对Lzo格式的文件需要做一些特殊处理(为了支持Split需要建索引,还需要指定InputFormat为Lzo格式)。
Snappy//最快250MB/s最快500MB/s高速压缩速度和合理的压缩率;不支持Split;压缩率比Gzip要低;Hadoop本身不支持,需要安装。

MR选择压缩的地方

在学习MR的时候,我们有看到MR可以选择的压缩地方有很多,下面一起看看压缩的具体位置:

image-20220412094739961

压缩的参数配置

要在Hadoop中启用压缩,可以配置如下参数:

参数默认值阶段建议
io.compression.codecs (在core-site.xml中配置)无,这个需要在命令行输入hadoop checknative查看输入压缩Hadoop使用文件扩展名判断是否支持某种编解码器
mapreduce.map.output.compress(在mapred-site.xml中配置)falsemapper输出这个参数设为true启用压缩
mapreduce.map.output.compress.codec(在mapred-site.xml中配置)org.apache.hadoop.io.compress.DefaultCodecmapper输出企业多使用LZO或Snappy编解码器在此阶段压缩数据
mapreduce.output.fileoutputformat.compress(在mapred-site.xml中配置)falsereducer输出这个参数设为true启用压缩
mapreduce.output.fileoutputformat.compress.codec(在mapred-site.xml中配置)org.apache.hadoop.io.compress.DefaultCodecreducer输出使用标准工具或者编解码器,如gzip和bzip2
mapreduce.output.fileoutputformat.compress.type(在mapred-site.xml中配置)RECORDreducer输出SequenceFile输出使用的压缩类型:NONE和BLOCK

案例实操

​ 这里给大家一个压缩小方式哟:小伙子不想安装压缩软件的,建议直接使用Java,YYDS。

package com.mr.workcount;
/**
 * @author:Pier
 * @DATE:2022/3/2
 */
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * MR程序的驱动类:主要用于提交MR任务
 */
public class WordCountDriver {


    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //声明配置对象
        Configuration conf = new Configuration();

        //设置Mapper端输出的时候压缩
//        conf.set("mapredece.map.output.compress","true");
        conf.setBoolean("mapreduce.map.output.compress",true);
//        配置Hadoop默认的编解码器
        conf.set("mapreduce.map.output.compress.codec","org.apache.hadoop.io.compress.DefaultCodec");

        //设置reduce端输出的时候压缩
        conf.setBoolean("mapreduce.output.fileoutputformat.compress",true);
        conf.set("mapreduce.output.fileoutputformat.compress.codec","org.apache.hadoop.io.compress.DefaultCodec");
        //        指定当前job提交的队列名称
        conf.set("mapreduce.job.queuename","hello");
        //        conf.set("mapreduce.job.inputformat.class","org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat");

        //声明job对象
        Job job = Job.getInstance(conf);
        //指定当前Job的驱动类
        job.setJarByClass(WordCountDriver.class);
        //指定当前Job的Mapper和Reducer
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        //指定Map段输出数据的key的类型和输出数据value的类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //指定最终输出结果的key类型和value类型
        //知道这个结果输出
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        // 指定CombineTextInputFormat中的切片最大值
//        CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);
        // 指定InputFormat的具体实现
//        job.setInputFormatClass(CombineTextInputFormat.class);


        //指定输入数据的路径 和 输出数据的路径
        FileInputFormat.setInputPaths(job,new Path("inputPath"));
        //输出地址
        FileOutputFormat.setOutputPath(job,new Path("outputPath"));
        //若使用虚拟机的,请自行配置环境变量
//        FileInputFormat.setInputPaths(job,new Path(args[0]));
//        FileOutputFormat.setOutputPath(job,new Path(args[1]));

        //提交Job
        job.waitForCompletion(true);

    }
}

优化

可能会有的问题

企业的问题可能会有哪些:

MapReduce程序效率的瓶颈在于两点:

1.计算机性能
CPU、内存、磁盘健康、网络

2.I/O操作优化

  • 数据倾斜
  • Map和Reduce数设置不合理
  • Map运行时间太长,导致Reduce等待过久
  • 小文件过多
  • 大量的不可切片的超大压缩文件
  • Spill次数过多
  • Merge次数过多等

解决问题的方向

​ 计算机的性能提高不在我们的技术范围之内,但MapReduce优化方法可以从六个方面考虑:数据输入、Map阶段、Reduce阶段、IO传输、数据倾斜问题和常用的调优参数。

数据输入方面

  • 当输入端又大量小文件时,我们可以合并小文件,因为在执行MR任务前将小文件进行合并,大量的小文件会产生大量的Map任务,增大Map任务装载次数,而任务的装载比较耗时,从而导致MR运行较慢。
  • 采用CombineTextInputFormat来作为输入,解决输入端大量小文件场景。

Map阶段

  • 减少溢写(Spill)次数:通过调整mapreduce.task.io.sort.mb及mapreduce.map.sort.spill.percent参数值,增大触发Spill的内存上限,减少Spill次数,从而减少磁盘IO。
  • 减少合并(Merge)次数:通过调整mapreduce.task.io.sort.factor参数,增大Merge的文件数目,减少Merge的次数,从而缩短MR处理时间。
  • 在Map之后,不影响业务逻辑前提下,先进行Combine处理,减少 I/O。

Reduce阶段

  • 合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致Map、Reduce任务间竞争资源,造成处理超时等错误。
  • 合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致Map、Reduce任务间竞争资源,造成处理超时等错误。
  • 规避使用Reduce:因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。
  • 合理设置Reduce端的Buffer:默认情况下,数据达到一个阈值的时候,Buffer中的数据就会写入磁盘,然后Reduce会从磁盘中获得所有的数据。也就是说,Buffer和Reduce是没有直接关联的,中间多次写磁盘->读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得Buffer中的一部分数据可以直接输送到Reduce,从而减少IO开销:mapreduce.reduce.input.buffer.percent,默认为0.0。当值大于0的时候,会保留指定比例的内存读Buffer中的数据直接拿给Reduce使用。这样一来,设置Buffer需要内存,读取数据需要内存,Reduce计算也要内存,所以要根据作业的运行情况进行调整。

I/O传输

  • 采用数据压缩的方式,减少网络IO的时间。
  • 使用SequenceFile二进制文件。

数据倾斜
原因

  • key分布不均匀
  • 业务数据本身的特性
  • 建表时考虑不周
  • 某些SQL语句本身就有数据倾斜

解决的方案

  • 常用优化手段
    • 增加jvm内存:适用于变量值非常少的情况,这种情况下,往往只能通过硬件的手段来进行调优,增加jvm内存可以显著的提高运行效率;
    • 增加reduce的个数:适用于变量值非常多的情况,这种情况下最容易造成的结果就是大量相同key被partition到一个分区,从而一个reduce执行了大量的工作
    • 重新设计key:在map阶段时给key加上一个随机数,有了随机数的key就不会被大量的分配到同一节点(小几率),待到reduce后再把随机数去掉即可
    • 使用combiner合并:combinner是在map阶段,reduce之前的一个中间阶段,在这个阶段可以选择性的把大量的相同key数据先进行一个合并,可以看做是local reduce,然后再交给reduce来处理,减轻了map端向reduce端发送的数据量(减轻了网络带宽),也减轻了map端和reduce端中间的shuffle阶段的数据拉取数量(本地化磁盘IO速率)设置参数hive.map.aggr=true
    • 设置合理的map reduce的task数,能有效提升性能数据量较大的情况下,慎用count(distinct),count(distinct)容易产生倾斜问题设置参数
    • 有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作
  • SQL语句调节
    • 如何jion:关于驱动表的选取,选用join key分布最均匀的表作为驱动表;
      做好列裁剪和filter操作,以达到两表做join的时候,数据量相对变小的效果
    • 大小表jion:使用map join让小的维度表(1000条以下的记录条数) 先进内存。在map端完成reduce
    • 大表Join大表:把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果
    • count distinct大量相同特殊值:count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union
    • group by维度过小:采用sum() group by的方式来替换count(distinct)完成计算
    • 特殊情况特殊处理:在业务逻辑优化效果的不大情况下,有些时候是可以将倾斜的数据单独拿出来处理。最后union回去

数据调参 :值得注意的是,一般情况下,我们用不到这些参数,建议收藏,以便企业使用时方便查询哟!

以下参数是在用户自己的MR应用程序中配置就可以生效(mapred-default.xml)

配置参数参数说明
mapreduce.map.memory.mb一个MapTask可使用的资源上限(单位:MB),默认为1024。如果MapTask实际使用的资源量超过该值,则会被强制杀死。
mapreduce.reduce.memory.mb一个ReduceTask可使用的资源上限(单位:MB),默认为1024。如果ReduceTask实际使用的资源量超过该值,则会被强制杀死。
mapreduce.map.cpu.vcores每个MapTask可使用的最多cpu core数目,默认值: 1
mapreduce.reduce.cpu.vcores每个ReduceTask可使用的最多cpu core数目,默认值: 1
mapreduce.reduce.shuffle.parallelcopies每个Reduce去Map中取数据的并行数。默认值是5
mapreduce.reduce.shuffle.merge.percentBuffer中的数据达到多少比例开始写入磁盘。默认值0.66
mapreduce.reduce.shuffle.input.buffer.percentBuffer大小占Reduce可用内存的比例。默认值0.7
mapreduce.reduce.input.buffer.percent指定多少比例的内存用来存放Buffer中的数据,默认值是0.0

应该在YARN启动之前就配置在服务器的配置文件中才能生效(yarn-default.xml)

配置参数参数说明
yarn.scheduler.minimum-allocation-mb给应用程序Container分配的最小内存,默认值:1024
yarn.scheduler.maximum-allocation-mb给应用程序Container分配的最大内存,默认值:8192
yarn.scheduler.minimum-allocation-vcores每个Container申请的最小CPU核数,默认值:1
yarn.scheduler.maximum-allocation-vcores每个Container申请的最大CPU核数,默认值:32
yarn.nodemanager.resource.memory-mb给Containers分配的最大物理内存,默认值:8192

Shuffle性能优化的关键参数,应在YARN启动之前就配置好(mapred-default.xml)

配置参数参数说明
mapreduce.task.io.sort.mbShuffle的环形缓冲区大小,默认100m
mapreduce.map.sort.spill.percent环形缓冲区溢出的阈值,默认80%

容错相关参数(MapReduce性能优化)

配置参数参数说明
mapreduce.map.maxattempts每个Map Task最大重试次数,一旦重试次数超过该值,则认为Map Task运行失败,默认值:4。
mapreduce.reduce.maxattempts每个Reduce Task最大重试次数,一旦重试次数超过该值,则认为Map Task运行失败,默认值:4。
mapreduce.task.timeoutTask超时时间,经常需要设置的一个参数,该参数表达的意思为:如果一个Task在一定时间内没有任何进入,即不会读取新的数据,也没有输出数据,则认为该Task处于Block状态,可能是卡住了,也许永远会卡住,为了防止因为用户程序永远Block住不退出,则强制设置了一个该超时时间(单位毫秒),默认是600000(10分钟)。如果你的程序对每条输入数据的处理时间过长(比如会访问数据库,通过网络拉取数据等),建议将该参数调大,该参数过小常出现的错误提示是:“AttemptID:attempt_14267829456721_123456_m_000224_0 Timed out after 300 secsContainer killed by the ApplicationMaster.”。

好了,本来后边还有Hadoop ha的流程搭建的,但是这里就不加了,太多了,大家有兴趣的可以给我评论或者私聊我哟,要是多的话,就发一下。

  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值