Map Reduce commit job 优化

本文探讨了Hadoop MapReduce版本2 (MRv2) 中针对Job提交过程的优化措施。通过改进FileOutputCommitter组件,在commitJob阶段减少了大量的文件重命名操作,从而显著提升了大型作业的提交效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

经常会看到用户的job在所有的map和reduce都完成之后,还需要几分钟时间才能finish。这个阶段主要在进行job output的commit过程。

MR v2中有进行这部分的优化。

https://issues.apache.org/jira/browse/MAPREDUCE-4815

https://issues.apache.org/jira/browse/MAPREDUCE-6275

https://issues.apache.org/jira/browse/MAPREDUCE-6280

目前看来在hadoop 2.7之后才有这些功能,但是还是有坑。


在FileOutputCommitter中的commitJob方法中,可以看到根据mapreduce.fileoutputcommitter.algorithm.version的不同,会有不同的处理逻辑。

org/apache/hadoop/mapreduce/lib/output/FileOutputCommitter.java


mapreduce.fileoutputcommitter.algorithm.version


官方文档中的介绍https://hadoop.apache.org/docs/r2.7.0/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml非常清楚,如下:

总结来说,就是减少了一步rename的过程,而且老版本中commitJob是单线程串行rename大量output,这本身很花时间。现在新版本中,只是rename一个文件夹就行了,可以大大提高速度。


The file output committer algorithm version valid algorithm version number: 1 or 2 default to 1, which is the original algorithm In algorithm version 1, 1. commitTask will rename directory $joboutput/_temporary/$appAttemptID/_temporary/$taskAttemptID/ to $joboutput/_temporary/$appAttemptID/$taskID/ 2. recoverTask will also do a rename $joboutput/_temporary/$appAttemptID/$taskID/ to $joboutput/_temporary/($appAttemptID + 1)/$taskID/ 3. commitJob will merge every task output file in $joboutput/_temporary/$appAttemptID/$taskID/ to $joboutput/, then it will delete $joboutput/_temporary/ and write $joboutput/_SUCCESS It has a performance regression, which is discussed in MAPREDUCE-4815. If a job generates many files to commit then the commitJob method call at the end of the job can take minutes. the commit is single-threaded and waits until all tasks have completed before commencing. algorithm version 2 will change the behavior of commitTask, recoverTask, and commitJob. 1. commitTask will rename all files in $joboutput/_temporary/$appAttemptID/_temporary/$taskAttemptID/ to $joboutput/ 2. recoverTask actually doesn't require to do anything, but for upgrade from version 1 to version 2 case, it will check if there are any files in $joboutput/_temporary/($appAttemptID - 1)/$taskID/ and rename them to $joboutput/ 3. commitJob can simply delete $joboutput/_temporary and write $joboutput/_SUCCESS This algorithm will reduce the output commit time for large jobs by having the tasks commit directly to the final output directory as they were completing and commitJob had very little to do.

在Hadoop MapReduce中,`TransactionDefinition`是Apache HBase提供的一个接口,用于定义和管理事务的特性。如果你想在MapReduce任务中控制小事务,你可以通过创建`TransactionCallable`来封装你的MapReduce操作,并在`TransactionDefinition`中指定所需的事务属性。以下是一个简单的例子: ```java import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.mapreduce.TableMapper; import org.apache.hadoop.hbase.mapreduce.TableReducer; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.transaction.TransactionConfiguration; import org.apache.hadoop.hbase.transaction.TransactionDefiningCallable; public class CustomTransactionTask { private static final TableName TABLE_NAME = TableName.valueOf("your_table_name"); private static final byte[] FAMILY_NAME = Bytes.toBytes("family_name"); public static class MyMapper extends TableMapper<String, String> { private TransactionDefiningCallable<Void, Result> callable; @Override protected void setup(Context context) throws Exception { Configuration conf = context.getConfiguration(); TransactionConfiguration transactionConf = TransactionConfiguration.create(conf); // 创建TransactionDefiningCallable,指定需要的隔离级别等 callable = new TransactionDefiningCallable<>(User.getCurrent(), TABLE_NAME, TransactionDefinition.PRIORITY_KEY, TransactionDefinition.PRIORITY_DEFAULT, TransactionDefinition.ISOLATION_DEFAULT, 5000, null /* No auto-commit */); // 设置TransactionDefiningCallable为当前任务的callble context.setCallables(callable); } // ...其他Mapper的处理逻辑 } public static class MyReducer extends TableReducer<String, String, Void> { // ...其他Reducer的处理逻辑 } public static void main(String[] args) throws Exception { Configuration config = new Configuration(); // 配置HBase连接信息 HBaseAdmin admin = ConnectionFactory.createConnection(config).getAdmin(); // 开始MapReduce任务 Job job = Job.getInstance(config, "Custom Transaction Task"); job.setJarByClass(CustomTransactionTask.class); job.setMapperClass(MyMapper.class); job.setReducerClass(MyReducer.class); job.setOutputKeyClass(Bytes.toStringUtf8()); job.setOutputValueClass(Bytes.toStringUtf8()); admin.close(); boolean success = job.waitForCompletion(true); System.exit(success ? 0 : 1); } } ``` 在这个例子中,`MyMapper`的`setup`方法设置了`TransactionDefiningCallable`作为任务的回调函数,这使得每个mapper在开始处理前会开启一个新的事务。然后,`MyReducer`会在事务范围内接收和处理结果。 注意,`TransactionDefinition`允许设置如隔离级别、事务优先级和超时时间等参数。在实际应用中,你需要根据你的业务需求选择合适的参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值