大数据修炼之hadoop--MapReduce

2024-09-02 12:32
文章标签 数据 hadoop 修炼 mapreduce

本文主要是介绍大数据修炼之hadoop--MapReduce,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 定义
  • 概念
  • 流程
  • 支持的数据类型
  • demo
  • 切片策略
    • FileInputFormat
  • 片与块的关系
  • 提交流程
  • 关键设置
  • Job提交流程阶段总结
    • 准备
    • 提交

定义

MapReduce最早是由谷歌公司研究提出的一种面向大规模数据处理的并行计算模型和方法。
特点:
MapReduce是一个基于集群的高性能并行计算平台。
MapReduce是一个并行计算与运行软件框架。
MapReduce是一个并行程序设计模型与方法。

易于编程,良好的扩展性,高容错性,适合PB级别以上的海量数据的离线处理
但是同时,不适合实时计算,不擅长流式计算,不擅长DAG计算(程序依赖)

概念

Job(任务): 一个MR程序
MRAppMaster(MR任务的主节点):一个Job在运行是,会先启动一个进程,负责Job执行过程的监控,容错,申请资源,提交task
Task(任务):计算
Map:切分。 将输入数据切分成若干小部分,每个部分为1片split,每片数据交给一个task进行计算(MapTask)
Reduce: MapTask的汇总

常用组件:
Mapper
Reducer
InputFormat 输入目录的文件格式。 普通文件:FileInputFormat , SequeceFileInput(hadoop格式),DBInputFormat(数据库的格式)
OutputFormat 类上
RecordWriter 记录写出其 结果以什么格式,写出到文件中
Partitioner 分区器

流程

MapReduce中,Map阶段处理的数据如何传递给Reduce阶段,是整个MapReduce框架中最关键的一个流程,这个流程就叫Shuffle。它的核心机制包括数据分区、排序和缓存等。
在这里插入图片描述

支持的数据类型

(1)BooleanWritable:标准布尔型数值。
(2)ByteWritable:单字节数值。
(3)DoubleWritable:双字节数。
(4)FloatWritable:浮点数。
(5)IntWritable:整型数。
(6)LongWritable:长整型数。
(7)Text:使用UTF8格式存储的文本。
(8)NullWritable:当<key,value>中的key或value为空时使用。
(9)ArrayWritable:存储属于Writable类型的值数组(要使用ArrayWritable类型作为Reduce输入的value类型,需要创建ArrayWritable的子类来指定存储在其中的Writable值的类型)。

运行最新版hadoop的mapreduce的时候经常会有各种报错,最好是有linux环境可以用。windows环境下设置HADOOP_HOME,并把wintils放在bin目录下:
https://github.com/steveloughran/winutils

demo

maven

 <dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-mapreduce-client-core</artifactId><version>3.2.0</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>

code:

public class MyDriver {public static final Configuration configuration = new Configuration();static {
//        configuration.set("fs.defaultFS", "hdfs://192.168.31.101:9000");System.setProperty("HADOOP_USER_NAME", "hadoop");
//        System.setProperty("HADOOP_HOME", "D:\\tools\\hadoop-3.3.0");}public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {remortJob();
//        localJob();}private static void remortJob() throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {System.setProperty("HADOOP_HOME", "D:\\tools\\hadoop-3.3.0");Path inputPath=new Path("/wcinput/logs");Path outputPath=new Path("/wcoutput/test");configuration.set("fs.defaultFS","hdfs://192.168.31.101:9000");configuration.set("fs.defaultFS","hdfs://192.168.31.101:9000");FileSystem fs=FileSystem.get(new URI("hdfs://192.168.31.101:9000"),configuration,"root");if (fs.exists(outputPath)) {fs.delete(outputPath, true);}
//        创建jobJob job=Job.getInstance(configuration);job.setJobName("wordcount test");
//        设置jobjob.setMapperClass(MyMapper.class);job.setReducerClass(MyReducer.class);
//            准备序列化器job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);//            输入输出目录FileInputFormat.setInputPaths(job,inputPath);FileOutputFormat.setOutputPath(job,outputPath);
//        运行jobjob.waitForCompletion(true);}private static void localJob() throws IOException, InterruptedException, ClassNotFoundException {System.setProperty("HADOOP_HOME", "D:\\tools\\hadoop-3.3.0");Path inputPath=new Path("d:/mrinput/");Path outputPath=new Path("d:/mroutput/wd");FileSystem fs=FileSystem.get(configuration);
//        创建jobJob job=Job.getInstance(configuration);job.setJobName("wordcount test");
//        设置jobjob.setMapperClass(MyMapper.class);job.setReducerClass(MyReducer.class);
//            准备序列化器job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);//            输入输出目录FileInputFormat.setInputPaths(job,inputPath);FileOutputFormat.setOutputPath(job,outputPath);
//        运行jobjob.waitForCompletion(true);}
}public class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable> {private Text outKey=new Text();private IntWritable outValue=new IntWritable(1);/*** 每个 keyin  valuein 执行一次* 每个 keyvalue都转成(word,1)* @param key* @param value* @param context* @throws IOException* @throws InterruptedException*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//        super.map(key, value, context);System.out.println(" key:"+key +"  value:"+value);String[] split = value.toString().split("\t");for (String word :split) {outKey.set(word);context.write(outKey,outValue);}}
}public class MyReducer extends Reducer<Text, IntWritable,Text,IntWritable> {private IntWritable outValue;@Overrideprotected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//        super.reduce(key, values, context);int sum=0;for (IntWritable item :values) {sum += item.get();}outValue = new IntWritable(sum);context.write(key,outValue);}
}

InputFormat的作用:

  1. 验证输入目录中文件格式,是否符合当前Job的要求
  2. 生产切片,每个切片都会交给一个MapTask处理
  3. 提供RecordReader,由RR从切片中读取记录,交给Mapper处理。

方法 List getSplits: 切片
RecordReader<K,V> createRecordReader: 创建RR

默认使用的是TextInputFormat , LineRecordReader

切片策略

TextInputFormat:
常用于输入目录中全是文本文件
RecordReader: LineRecordReader 一次处理一行,将一行内容偏移量作为key,内容value

NLineInputFormat:
切分n行,执行逻辑复杂情况

KeyValueTextInputFormat:
键值对格式
CombineTextInputText:
多个小文件

FileInputFormat

 public List<InputSplit> getSplits(JobContext job) throws IOException {StopWatch sw = new StopWatch().start();long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));// getFormatMinSplitSize  其实是1,getMinSplitSize 是取配置 mapreduce.input.fileinputformat.split.maxsizelong maxSize = getMaxSplitSize(job);   //mapreduce.input.fileinputformat.split.maxsize// generate splitsList<InputSplit> splits = new ArrayList<InputSplit>();List<FileStatus> files = listStatus(job);  // 输入目录所有文件的状态信息boolean ignoreDirs = !getInputDirRecursive(job)&& job.getConfiguration().getBoolean(INPUT_DIR_NONRECURSIVE_IGNORE_SUBDIRS, false);for (FileStatus file: files) {if (ignoreDirs && file.isDirectory()) {continue;}Path path = file.getPath();long length = file.getLen();if (length != 0) {BlockLocation[] blkLocations;if (file instanceof LocatedFileStatus) {blkLocations = ((LocatedFileStatus) file).getBlockLocations();} else {FileSystem fs = path.getFileSystem(job.getConfiguration());blkLocations = fs.getFileBlockLocations(file, 0, length);}if (isSplitable(job, path)) {//  判断方法与实现类相关,各个类自己实现,默认truelong blockSize = file.getBlockSize();long splitSize = computeSplitSize(blockSize, minSize, maxSize);long bytesRemaining = length; // 循环切片while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);splits.add(makeSplit(path, length-bytesRemaining, splitSize,blkLocations[blkIndex].getHosts(),blkLocations[blkIndex].getCachedHosts()));bytesRemaining -= splitSize;}if (bytesRemaining != 0) {int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,blkLocations[blkIndex].getHosts(),blkLocations[blkIndex].getCachedHosts()));}} else { // not splitable  不可切,直接传入文件if (LOG.isDebugEnabled()) {// Log only if the file is big enough to be splittedif (length > Math.min(file.getBlockSize(), minSize)) {LOG.debug("File is not splittable so no parallelization "+ "is possible: " + file.getPath());}}splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),blkLocations[0].getCachedHosts()));}} else { //Create empty hosts array for zero length filessplits.add(makeSplit(path, 0, length, new String[0]));}}// Save the number of input files for metrics/loadgenjob.getConfiguration().setLong(NUM_INPUT_FILES, files.size());sw.stop();if (LOG.isDebugEnabled()) {LOG.debug("Total # of splits generated by getSplits: " + splits.size()+ ", TimeTaken: " + sw.now(TimeUnit.MILLISECONDS));}return splits;}

片与块的关系

默认的片大小是文件的块大小,文件默认128M
片: InputSplit 计算MR时进行切片,临时的逻辑区,与输入格式相关
块:Block HDFS的存储单位,实际物理存在

建议,片大小=块大小。减少磁盘IO,网络IO

提交流程

 public boolean waitForCompletion(boolean verbose) throws IOException, InterruptedException,ClassNotFoundException {if (state == JobState.DEFINE) {submit();}if (verbose) {monitorAndPrintJob();} else {// get the completion poll interval from the client.int completionPollIntervalMillis = Job.getCompletionPollInterval(cluster.getConf());while (!isComplete()) {try {Thread.sleep(completionPollIntervalMillis);} catch (InterruptedException ie) {}}}return isSuccessful();}
 public void submit() throws IOException, InterruptedException, ClassNotFoundException {ensureState(JobState.DEFINE);setUseNewAPI();connect();final JobSubmitter submitter = getJobSubmitter(cluster.getFileSystem(), cluster.getClient());status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() {public JobStatus run() throws IOException, InterruptedException, ClassNotFoundException {return submitter.submitJobInternal(Job.this, cluster);}});state = JobState.RUNNING;LOG.info("The url to track the job: " + getTrackingURL());}

关键设置

MapTask数量,认为设置无效,只能通过切片的方式设置,MapTask取决于切片数。

Job提交流程阶段总结

准备

运行job.waitForCompletion(),生成一下信息
job.split 当前job的切片信息,有几个切片对象
job.splitmetainfo 切片对象的属性信息
job.xml job的属性配置

提交

本地模式:LocalJobRunner提交,创建LocalJobRunner.Job()
Map阶段: 线程池,提交多个MapTaskRunnable
每个MapTaskRunnable线程上,实例化一个MapTask对象
每个MapTask对象实例化一个Mapper
线程运行结束,在线程的作业目录中生成file.out文件,报错MapTask输出的所有Key-value
map:使用RR将切片中的数据读入到Mapper.map() context.write(key,value)
Reduce阶段:
线程池提交多个ReduceTaskRunnable
每个ReduceTask对象,实例化一个Reducer, reducer.run()
线程运行结束,在输出目录中生成,part-r-000x文件,保存ReduceTask输出的所有Key-value
copy: shuffle线程拷贝MapTask指定的分区数据
sort:将拷贝的所有分区数据汇总后,排序
reduce:排好序的数据,进行 合并

这篇关于大数据修炼之hadoop--MapReduce的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129958

相关文章

MySQL InnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据

《MySQLInnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据》mysql的ibdata文件被误删、被恶意修改,没有从库和备份数据的情况下的数据恢复,不能保证数据库所有表数据... 参考:mysql Innodb表空间卸载、迁移、装载的使用方法注意!此方法只适用于innodb_fi

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq

mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespace id不一致处理

《mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespaceid不一致处理》文章描述了公司服务器断电后数据库故障的过程,作者通过查看错误日志、重新初始化数据目录、恢复备... 周末突然接到一位一年多没联系的妹妹打来电话,“刘哥,快来救救我”,我脑海瞬间冒出妙瓦底,电信火苲马扁.

golang获取prometheus数据(prometheus/client_golang包)

《golang获取prometheus数据(prometheus/client_golang包)》本文主要介绍了使用Go语言的prometheus/client_golang包来获取Prometheu... 目录1. 创建链接1.1 语法1.2 完整示例2. 简单查询2.1 语法2.2 完整示例3. 范围值

javaScript在表单提交时获取表单数据的示例代码

《javaScript在表单提交时获取表单数据的示例代码》本文介绍了五种在JavaScript中获取表单数据的方法:使用FormData对象、手动提取表单数据、使用querySelector获取单个字... 方法 1:使用 FormData 对象FormData 是一个方便的内置对象,用于获取表单中的键值

Rust中的BoxT之堆上的数据与递归类型详解

《Rust中的BoxT之堆上的数据与递归类型详解》本文介绍了Rust中的BoxT类型,包括其在堆与栈之间的内存分配,性能优势,以及如何利用BoxT来实现递归类型和处理大小未知类型,通过BoxT,Rus... 目录1. Box<T> 的基础知识1.1 堆与栈的分工1.2 性能优势2.1 递归类型的问题2.2

Python使用Pandas对比两列数据取最大值的五种方法

《Python使用Pandas对比两列数据取最大值的五种方法》本文主要介绍使用Pandas对比两列数据取最大值的五种方法,包括使用max方法、apply方法结合lambda函数、函数、clip方法、w... 目录引言一、使用max方法二、使用apply方法结合lambda函数三、使用np.maximum函数

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

Python给Excel写入数据的四种方法小结

《Python给Excel写入数据的四种方法小结》本文主要介绍了Python给Excel写入数据的四种方法小结,包含openpyxl库、xlsxwriter库、pandas库和win32com库,具有... 目录1. 使用 openpyxl 库2. 使用 xlsxwriter 库3. 使用 pandas 库