• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
导航菜单
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • windows
  • 服务器硬件
  • 服务器运维
  • 云计算
  • 虚拟化
  • IIS教程
  • Linux
  • Apache
  • Ftp
  • DNS
  • Nginx
您的位置:首页 > 服务器 >云计算 > HDFS小文件的合并优化

HDFS小文件的合并优化

作者:diuleilaomo的博客 字体:[增加 减小] 来源:互联网

本文主要包含等服务器相关知识,diuleilaomo的博客希望可以进行参考

HDFS小文件的合并优化

我们都知道,HDFS设计是用来存储海量数据的,特别适合存储TB、PB量级别的数据。但是随着时间的推移,HDFS上可能会存在大量的小文件,这里说的小文件指的是文件大小远远小于一个HDFS块(128MB)的大小;HDFS上存在大量的小文件至少会产生以下影响:

消耗NameNode大量的内存
延长MapReduce作业的总运行时间

本文将介绍如何在MapReduce作业层面上将大量的小文件合并,以此减少运行作业的Map Task的数量;关于如何在HDFS上合并这些小文件

Hadoop内置提供了一个 CombineFileInputFormat 类来专门处理小文件,其核心思想是:根据一定的规则,将HDFS上多个小文件合并到一个 InputSplit中,然后会启用一个Map来处理这里面的文件,以此减少MR整体作业的运行时间。 
CombineFileInputFormat类继承自FileInputFormat,主要重写了List getSplits(JobContext job)方法;这个方法会根据数据的分布,mapreduce.input.fileinputformat.split.minsize.per.node、mapreduce.input.fileinputformat.split.minsize.per.rack以及mapreduce.input.fileinputformat.split.maxsize 参数的设置来合并小文件,并生成List。其中mapreduce.input.fileinputformat.split.maxsize参数至关重要:

如果用户没有设置这个参数(默认就是没设置),那么同一个机架上的所有小文件将组成一个InputSplit,最终由一个Map Task来处理;
如果用户设置了这个参数,那么同一个节点(node)上的文件将会组成一个InputSplit。

同一个 InputSplit 包含了多个HDFS块文件,这些信息存储在 CombineFileSplit 类中,它主要包含以下信息: 
private Path[] paths; 
private long[] startoffset; 
private long[] lengths; 
private String[] locations; 
private long totLength;

从上面的定义可以看出,CombineFileSplit类包含了每个块文件的路径、起始偏移量、相对于原始偏移量的大小以及这个文件的存储节点,因为一个CombineFileSplit包含了多个小文件,所以需要使用数组来存储这些信息。

CombineFileInputFormat是抽象类,如果我们要使用它,需要实现createRecordReader方法,告诉MR程序如何读取组合的InputSplit。内置实现了两种用于解析组合InputSplit的类:org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat 和 org.apache.hadoop.mapreduce.lib.input.CombineSequenceFileInputFormat,我们可以把这两个类理解是 TextInputFormat 和 SequenceFileInputFormat。为了简便,这里主要来介绍CombineTextInputFormat。

在 CombineTextInputFormat 中创建了 org.apache.hadoop.mapreduce.lib.input.CombineFileRecordReader,具体如何解析CombineFileSplit中的文件主要在CombineFileRecordReader中实现。

CombineFileRecordReader类中其实封装了TextInputFormat的RecordReader,并对CombineFileSplit中的多个文件循环遍历并读取其中的内容,初始化每个文件的RecordReader主要在initNextRecordReader里面实现;每次初始化新文件的RecordReader都会设置mapreduce.map.input.file、mapreduce.map.input.length以及mapreduce.map.input.start参数,这样我们可以在Map程序里面获取到当前正在处理哪个文件。

现在我们就来看看如何使用CombineTextInputFormat类,如下:

package com.hqdps.hadoop.mr.merge;

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.apache.hadoop.conf.Configuration; 
import org.apache.hadoop.conf.Configured; 
import org.apache.hadoop.fs.FileStatus; 
import org.apache.hadoop.fs.FileSystem; 
import org.apache.hadoop.fs.Path; 
import org.apache.hadoop.io.LongWritable; 
import org.apache.hadoop.io.NullWritable; 
import org.apache.hadoop.io.Text; 
import org.apache.hadoop.mapreduce.Job; 
import org.apache.hadoop.mapreduce.Mapper; 
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 org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 
import org.apache.hadoop.util.Tool; 
import org.apache.hadoop.util.ToolRunner;

import Java.io.IOException;

public class MergeSmallFile extends Configured implements Tool { 
private static final Log LOG = LogFactory.getLog(MergeSmallFile.class); 
private static final long ONE_MB = 1024 * 1024L;

static class TextFileMapper extends
        Mapper<LongWritable, Text, Text, NullWritable> {
    //
    @Override
    protected void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        context.write(value, NullWritable.get());
    }
}

// 删除原来小文件
protected static void deleteSmallFiles(String deletepath)
        throws IOException, InterruptedException {
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(conf);
    Path filePath = new Path(deletepath);

    try {
        FileStatus[] status = fs.listStatus(filePath);
        LOG.info("共有" + status.length + "个文件");
        for (FileStatus st : status) {
            LOG.info("开始删除:" + st.getPath().getName() + "文件");
            fs.delete(st.getPath(), false);
        }
        fs.delete(filePath, false);
    } catch (Exception e) {
        e.printStackTrace();
        LOG.error(e.getMessage());
    }
}
//修改路径
protected static void modifyPath(String src,String dst)
        throws IOException, InterruptedException {
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(conf);
    Path srcPath = new Path(src);
    Path dstPath = new Path(dst);
    try {
        fs.rename(srcPath, dstPath);
        LOG.info("修改成"+dst+"路径,成功!!!");
    } catch (Exception e) {
        e.printStackTrace();
        LOG.error(e.getMessage());
    }
}

public static void main(String[] args) throws Exception {
    int exitCode = ToolRunner.run(new MergeSmallFile(), args);
    deleteSmallFiles(args[0]);
    modifyPath(args[1], args[0]);
    System.exit(exitCode);
}

@Override
public int run(String[] args) throws Exception {
    Configuration conf = new Configuration(getConf());

    String inputDir = args[0];
    String outputDir = args[1];
    int maxSplitSize = Integer.valueOf(args[2]);
    LOG.info("inputDir--->>" + inputDir);
    LOG.info("outputDir--->>" + outputDir);
    LOG.info("maxSplitSize--->>" + maxSplitSize + "M");

    Job job = Job.getInstance(conf);
    FileInputFormat.setInputPaths(job, inputDir);
    FileOutputFormat.setOutputPath(job, new Path(outputDir));
    job.setJarByClass(MergeSmallFile.class);

    // 设置最大输入分片大小,与运行的map、及生产的文件数密切相关
    CombineTextInputFormat.setMaxInputSplitSize(job, ONE_MB * maxSplitSize);
    job.setInputFormatClass(CombineTextInputFormat.class);
    job.setOutputFormatClass(TextOutputFormat.class);
    job.setOutputKeyClass(Text.class);
    job.setMapOutputValueClass(NullWritable.class);
    job.setMapperClass(TextFileMapper.class);
    job.setNumReduceTasks(0);
    return job.waitForCompletion(true) ? 0 : 1;
}

}

可以看到最终结果将三个文件里面的内容合并到一个文件中。注意体会mapreduce.input.fileinputformat.split.maxsize(CombineTextInputFormat.setMaxInputSplitSize)参数的设置,大家可以不设置这个参数并且和设置这个参数运行情况对比,观察Map Task的个数变化。

整形医院哪个好:http://www.shkqmrw.com/

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

相关文章

  • 机器学习-模型评估与选择
  • Spark性能优化:数据倾斜调优
  • HBase,hbase安装
  • hbase,hbase安装
  • kafka 效率优化,kafka优化
  • 玩转OpenStack网络Neutron(1)--热身,openstackneutron
  • 机器学习--k-近邻(kNN)算法案例,--k-knn
  • Andrew Ng Machine Learning,andrewlearning
  • Binary Tree Preorder Traversal (leetcode 144),preorderleetcode
  • hive 优化的原则,hive优化原则

文章分类

  • windows
  • 服务器硬件
  • 服务器运维
  • 云计算
  • 虚拟化
  • IIS教程
  • Linux
  • Apache
  • Ftp
  • DNS
  • Nginx

最近更新的内容

    • Hive Developing,hivedeveloping
    • shell命令curl抓取网页内容-下载xls文件,
    • What&#39;s Wrong With Hue Oozie Editor?,hueoozie
    • 别再用高考来绑架孩子们心中的“公平”,孩子们心中
    • HBase Shell的基本用法,HBaseShell用法
    • 吐槽Oozie: 挖好坑,等你跳!,oozie
    • zookeeper——分布式锁,zookeeper
    • window操作系统搭建Spark开发调试环境
    • Navicat连接oracle,出现Only compatible with oci version 8.1 and&amp;nb,navicatoci
    • 上传到dfs和hadoop统计计算

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有