Hadoop简单介绍
Hadoop是apache基金会组织的一个顶级项目,其核心为HDFS和MapReduce,HDFS为海量的数据提供存储,而MapReduce为海量的数据提供并行计算,所以简单说就是大数据的分布式存储与计算平台。
Hadoop 基础架构负责处理分布式处理的所有复杂方面:并行化、调度、资源管理、机器间通信、软件和硬件故障处理,等等。得益于这种干净的抽象,实现处理数百(或者甚至数千)个机器上的数 TB 数据的分布式应用程序非常容易。
Apache Hadoop :http://archive.apache.org/dis...
Apache Hadoop文档:http://hadoop.apache.org/docs
常用于一下场景:
场景1:数据分析平台
场景2:推荐系统
场景3:业务系统的底层存储系统
场景4:业务监控系统
生态系统:
HBase位于结构化存储层,Hadoop HDFS为HBase提供了高可靠性的底层存储支持,Hadoop MapReduce/Hive为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定服务和failover机制。
hadoop版本
①Apache:官方版本。
②Cloudera:使用下载最多的版本,稳定,有商业支持,在Apache的基础上打上了一些patch。推荐使用。
③Yahoo:Yahoo内部使用的版本,发不过两次,已有的版本都放到Apache上,后续不再继续发布,在集中在Apache的版本上
hadoop Cloudera版本
在Apache Hadoop的基础上,Cloudera公司将其进行商业化改进和更新,它的发行版本就是CDH(Cloudera Distribution Hadoop)。
下载地址:
CDH4.x: http://archive.cloudera.com/c...
CDH5.x: http://archive.cloudera.com/c...
CDH5.3.6文档:http://archive.cloudera.com/c...
hadoop的4个模块
Hadoop Common:为其他模块提供基础设施。
HDFS:高可靠、高吞吐量的分布式系统。
MapReduce:分布式离线并行计算框架。
Yarn:任务调度与资源管理的MapReduce框架。
端口号
hadoop2.x常用端口
http://www.cnblogs.com/jancco...
8020:接收Client连接的RPC端口,用于获取文件系统metadata信息。core-site.xml。
10020:Hadoop自带历史服务器配置。mapred-site.xml
50070:HDFS外部管理界面端口号。通过 jetty 启动的 Web 服务。
HDFS
Hadoop Distributed File Syetem
主从结构
主节点,只有一个:namenode
从节点,有很多个:datanodes
secondarynamenode
namenode
作用:
①接收用户请求,返回客户端数据信息
②维护文件系统的目录结构
③管理文件元数据,block与datanode之间关系。
文件内容:
- fsimage:元数据镜像文件。储存某一时段NameNode内存元数据信息。
- edits:操作日志文件
- fstime:保存最近一次checkpoint的时间
datanode
作用:
①存储、读写文件
②文件被分成block存储在磁盘上
③为保证数据安全,文件会有多个副本
存储的形式:
块block,大小默认128MB,可以用户自定义大小。hdfs-site.xmldfs.blocksize
自定义块大小属性,单位字节。
如果文件大小小于数据块的大小,它是不会占据整个块的空间,剩余的空间可以给别人用。
多个文件不能放到一个块中。
一次写入,多次读取。
如:文件大小为500MB,块大小是256MB,第一个块:256,第二个块:244。
ps:由client进行文件切分。
SecondaryNameNode
可理解为nn的秘书。
hdfs首次启动需要格式化文件,生成fsimage元数据镜像文件,edits文件是用户行为记录文件,secondarynamenode会辅助nn,读取上述两类文件,加载到内存,使得namenode获取元数据文件。之后会从NameNode上下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,同时重置NameNode的edits。
它的目的是帮助 NameNode 合并编辑日志,减少 NameNode 启动时间。
- HDFS的高可用性(HA)的一个解决方案。但不支持热备,当nn挂掉,它并不能马上替换nn并提供服务。配置即可。
- 执行过程:从NameNode上下载元数据信息(fsimage,edits),然后把二者合并,生成新的fstime, 在本地保存,并将其推送到NameNode,同时重置NameNode的edits。
可靠性
1.block默认有3个副本。
2.3个副本中,第一个副本一般放置在client所在的同一节点上(客户端无节点则随机放),第二个副本在与第一个所在节点同一机架的不同节点,第三个副本放到不同机架的节点,取用时遵循就近原则。
3.datanode以block为单位,每3s报告心跳状态(节点间通过ssh通信,需要节点间设置免密登入),10min不报告的block,nn会认作死掉,并备份其数据到其他一个dn,以保证副本数量。
4.datanode也会默认每小时报告其所有块状态信息。
5.safemode模式,nn接受报告会计算block的损坏率,达到0.01%时,进入安全模式,HDFS只读不写。
6.HA
MapReduce
对大规模的数据集的操作分配给各子节点进行操作,然后通过整合各子节点的中间结果,得到最终结果。简单来说就是“任务的分解和结果的汇总”。Hadoop将这个工作高度抽象成为两个函数,分别为map和reduce。map负责将任务分解为多个任务,reduce负责将多个map任务的中间结果合并为最终结果。至于在此过程中的其他步骤,均由hadoop的MapReduce框架自行负责处理,包括工作调度、任务分配、各节点通信等。
Map 任务 在输入数据的子集上调用 map 函数。在完成这些调用后,reduce 任务 开始在 map 函数所生成的中间数据上调用 reduce 任务,生成最终的输出。 map 和 reduce 任务彼此单独运行,这支持并行和容错的计算。
MapReduce是一个框架,可以理解是一种思想,可以选择使用语言开发。
也是主从架构:JobTracker,接收客户提交的计算任务,把计算任务分给TaskTrackers执行,监控TaskTracker的执行情况。
TaskTracker执行一个简单的循环,定期发送心跳(heartbeat)给JobTracker。
一个mapreduce程序分为五块
input(split) -> map -> shuffle -> reduce -> output
1.input输入来自 HDFS的 block 。Split 与 block 的对应关系可能是多对一,默认为一对一。
2.map任务
读取split,其中每个键值对都会调用一次 map 函数
mapper数量直接由split数决定,间接由 1)输入文件数目,2)输入文件的大小, 3)配置参数决定。mapreduce.input.fileinputformat.split.minsize
//启动map最小的split size大小,默认0mapreduce.input.fileinputformat.split.maxsize
//启动map最大的split size大小,默认256Mdfs.block.size
//block块大小,默认64M
计算公式:splitSize = Math.max(minSize, Math.min(maxSize, blockSize));
例如一个文件800M,Block大小是128M,那么Mapper数目就是7个。6个Mapper处理的数据是128M,1个Mapper处理的数据是32M;
如果要处理很多小文件,可以通过mapreduce.input.fileinputformat.split.minsize
调整Mapper的个数,因为小于这个值文件会合并。
map任务的结果都会被写入环形缓冲区(这个数据结构其实就是个字节数组,大小默认是mapreduce.task.io.sort.mb: 100
了解更多)。
写入之前,key 与value 值都会被序列化成字节数组。
3.Map端Shuffle
3.1切分Partition
mapreduce 提供的Partitioner接口,对key 进行 hash 后,再以 reducetask 数量取模,然后到指定的 job 上。如一个键值对的partition值为1,意味着这个键值对会交给第一个Reducer处理。
总结:Partition主要作用将map阶段产生的所有kv对分配给不同的reducer task处理,可以将reduce阶段的处理负载进行分摊。
3.2 排序sort
每个内存块中,按key排序
3.3溢写spill
由于环形缓冲区的大小限制,当map task输出结果很多时就可能发生内存溢出,所以需要在一定条件下将缓冲区的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill,中文可译为溢写。
这个溢写是由另外单独线程来完成,不影响往缓冲区写map结果的线程。
整个缓冲区有个溢写的比例spill.percent。这个比例默认是0.8(因为spill的时候还有可能别的线程在往里写数据)。可以通过mapreduce.map.sort.spill.percent
进行调整。
3.4合并merge
产生很多spill文件后,在Map Task结束前会对这些spill文件进行合并,这个过程就是merge的过程。
最多能同时mergemapreduce.task.io.sort.factor
(default:10)个spill文件,如果有100个spill个文件,此时就无法一次完成整个merge的过程,这个时候需要调大factor来减少merge的次数,从而减少磁盘的操作。
3.5combiner 将有相同key的 key/value 对加起来。(可选)
Combiner的适用场景:由于Combiner的输出是Reducer的输入,Combiner绝不能改变最终的计算结果。故大多数情况下,combiner适用于输入输出的key/value类型完全一致,且不影响最终结果的场景(比如累加、最大值等……需要自己设置)。min.num.spill.for.combine
的参数决定什么时候进行Combiner操作,默认是3,也就是说spill的文件数在默认情况下有三个的时候就要进行combine操作,减少溢写spill到磁盘的数据量,最终减少磁盘数据。
3.6 分组group
默认按key进行分组
3.7压缩(可选)
为了减少磁盘IO和网络IO还可以进行:压缩,对spill,merge文件都可以进行压缩。中间结果非常的大,IO成为瓶颈的时候压缩就非常有用,可以通过mapreduce.map.output.compress
(default:false)设置为true进行压缩,数据会被压缩写入磁盘,读数据读的是压缩数据需要解压,在实际经验中Hive在Hadoop的运行的瓶颈一般都是IO而不是CPU,压缩一般可以10倍的减少IO操作,压缩的方式Gzip,Lzo,BZip2,Lzma等,其中Lzo是一种比较平衡选择,mapreduce.map.output.compress.codec
(default:org.apache.hadoop.io.compress.DefaultCodec)参数设置。但这个过程会消耗CPU,适合IO瓶颈比较大。
4.reduce任务前,进行reduce端Shuffle
注意:数据达到reducer之前,mapreduce框架已经对这些数据按键排序了。
在 reduce task 之前,不断拉取当前 job 里每个 maptask 的最终结果,然后对从不同地方拉取过来的数据不断地做 merge ,也最终形成一个文件作为 reduce task 的输入文件。
4.1复制
一旦一个map任务完成之后,就会通过常规心跳通知应用程序的Application Master。
reduce的一个线程也会周期性地向master询问,因此reduce知道去哪些机器取数据。
数据被reduce提走之后,map机器不会立刻删除数据,这是为了预防reduce任务失败需要重做。因此map输出数据是在整个作业完成之后才被删除掉的。
Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求map task所在的TaskTracker获取map task的输出文件。因为maptask早已结束,这些文件就归TaskTracker管理在本地磁盘中。
下载也可以是并行的从多个map下载,这个并行度是可以通过mapreduce.reduce.shuffle.parallelcopies
(default5)调整。默认情况下,每个Reducer只会有5个map端并行的下载线程在从map下数据,这个参数比较适合在map很多并且完成的比较快的job的情况下调大,有利于reduce更快的获取属于自己部分的数据。 在Reducer内存和网络都比较好的情况下,也可以调大该参数。
reduce的每一个下载线程在下载某个map数据的时候,有可能因为那个map所在机器发生错误,或者中间结果的文件丢失,或者网络瞬断等等情况,这样reduce的下载就有可能失败,所以reduce的下载线程并不会无休止的等待下去,当一定时间后下载仍然失败,那么下载线程就会放弃这次下载,并在随后尝试从另外的地方下载(因为这段时间map可能重跑)。
reduce下载线程的这个最大的下载时间段是可以通过mapreduce.reduce.shuffle.read.timeout
(default180000秒)调整的。如果集群环境的网络本身是瓶颈,那么用户可以通过调大这个参数来避免reduce下载线程被误判为失败的情况。一般情况下都会调大这个参数。
4.2 排序
默认按key进行排序
4.3合并merge
Copy 过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比 map 端的更为灵活,它基于 JVM 的 heap size 设置,因为 Shuffle 阶段 Reducer 不运行,所以应该把绝大部分的内存都给 Shuffle 用。
参数 mapreduce.reduce.shuffle.input.buffer.percent
(default 0.7f 源码里面写死了) 这个一个百分比,意思是说,shuffile在reduce内存中的数据最多使用内存量为:0.7 × maxHeap of reduce task,即JVM的heapsize的70%。
比如reducetask的max heapsize为1G(通常通过mapreduce.admin.reduce.child.java.opts
来设置,比如设置为-Xmx1024m),那么用来做下载数据缓存的内存就为大概700MB左右。这700M的内存,跟map端一样,也不是要等到全部写满才会往磁盘刷的,而是当这700M中被使用到了一定的限度(通常是一个百分比),就会开始往磁盘刷(刷磁盘前会先做sortMerge)。这个限度阈值也是可以通过参数 mapreduce.reduce.shuffle.merge.percent
(default0.66)来设定。
这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。这种merge方式一直在运行,直到没有map端的数据时才结束,然后启动磁盘到磁盘的merge方式生成最终的那个文件。
补充:merge有三种形式:
1)内存到内存(memToMemMerger)
这种合并将内存中的map输出合并,然后再写入内存。这种合并默认关闭,可以通过mapreduce.reduce.merge.memtomem.enabled
(default:false)打开,当map输出文件达到mapreduce.reduce.merge.memtomem.threshold
时,触发这种合并。
2)内存中Merge(inMemoryMerger)
当缓冲中数据达到配置的阈值时,这些数据在内存中被合并、写入机器磁盘。
阈值有2种配置方式: 配置内存比例,前面提到reduceJVM堆内存的一部分用于存放来自map任务的输入,在这基础之上配置一个开始合并数据的比例。假设用于存放map输出的内存为500M,mapreduce.reduce.shuffle.merge.percent
配置为0.66,则当内存中的数据达到330M的时候,会触发合并写入。
配置map输出数量: 通过mapreduce.reduce.merge.inmem.threshold
配置。在合并的过程中,会对被合并的文件做全局的排序。如果作业配置了Combiner,则会运行combine函数,减少写入磁盘的数据量。
这种merge方式一直在运行,直到没有 map 端的数据时才结束。
3)磁盘上的Merge(onDiskMerger)具体包括两个:(一)Copy过程中磁盘合并(二)磁盘到磁盘。
磁盘到磁盘的 merge 方式生成最终的那个文件(有多少个reduce就生成几个文件)。当reducer 输入文件已定,整个 Shuffle 阶段才算结束。然后就是 Reducer 执行,把结果放到 HDFS 上。
5.reduce任务
默认情况下,reduce是全部从磁盘开始读处理数据。可以用mapreduce.reduce.input.buffer.percent
(default 0.0)(源代码MergeManagerImpl.java:674行)来设置reduce的缓存。如果这个参数大于0,那么就会有一定量的数据被缓存在内存并输送给reduce,当reduce计算逻辑消耗内存很小时,可以分一部分内存用来缓存数据,可以提升计算的速度。所以默认情况下都是从磁盘读取数据,如果内存足够大的话,务必设置该参数让reduce直接从缓存读数据
Reduce在这个阶段,框架为已分组的输入数据中的每个 <key, (list of values)>
对调用一次 reduce(WritableComparable,Iterator, OutputCollector, Reporter)
方法。Reduce任务的输出通常是通过调用 OutputCollector.collect(WritableComparable,Writable)
写入文件系统的。Reducer的输出是没有排序的。
Shuffle过程的作用
Hadoop 集群中,大部分 map task 与 reduce task 的执行是在不同的节点上。当然很多情况下 Reduce 执行时需要跨节点去拉取其它节点上的map task结果。如果集群正在运行的 job 有很多,那么 task 的正常执行对集群内部的网络资源消耗会很严重。而对于必要的网络资源消耗,最终的目的就是最大化地减少不必要的消耗。还有在节点内,相比于内存,磁盘 IO 对 job 完成时间的影响也是可观的。从最基本的要求来说,对于 MapReduce 的 job 性能调优的 Shuffle 过程,目标期望可以有:
完整地从map task端拉取数据到reduce 端;
在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗;
减少磁盘IO对task执行的影响。
总体来讲这段Shuffle过程,能优化的地方主要在于减少拉取数据的量及尽量使用内存而不是磁盘。
优化
运行map和reduce任务的JVM,内存通过mapred.child.java.opts属性来设置,尽可能设大内存。容器的内存大小通过mapreduce.map.memory.mb
和mapreduce.reduce.memory.mb
来设置,默认都是1024M。
过估计map的输出大小,设置合理的mapreduce.task.io.sort.*属性,使得spill文件数量最小。例如尽可能调大mapreduce.task.io.sort.mb。
在reduce端,如果能够让所有数据都保存在内存中,可以达到最佳的性能。通常情况下,内存都保留给reduce函数,但是如果reduce函数对内存需求不是很高,将mapreduce.reduce.merge.inmem.threshold(触发合并的map输出文件数)设为0,mapreduce.reduce.input.buffer.percent(用于保存map输出文件的堆内存比例)设为1.0,可以达到很好的性能提升。在2008年的TB级别数据排序性能测试中,Hadoop就是通过将reduce的中间数据都保存在内存中胜利的。
Hadoop默认使用4KB作为缓冲,这个算是很小的,可以通过io.file.buffer.size
来调高缓冲池大小。
cpu调整mapreduce.map.cpu.vcores
https://blog.csdn.net/aijiudu...
Yarn
Yet Another Resource Negotiator
MapReduce on Yarn流程
客户端提交job任务,resourcemanager
处理任务请求,首先会选择一台nodemanager
启动一个applicationmaster
。applicationmaster
启动后向resourcemanager
申请资源,申请到资源后调度nodemanager
分配任务,nodemanager
接受任务并运行任务(map/reduce),任务运行结束后会向applicationmaster
报告,applicationmaster
最后向resourcemanager
报告,并反馈结果给客户端 。
ApplicationMaster
应用管理者:每一个应用都会有一个应用管理者,去为应用程序申请资源并分配、监控任务。Container
:每个map都是在各自独立的环境中去运行(资源独立)。
Hadoop环境搭建
https://blog.csdn.net/gitchat...
不要用root用户搭建。
启动命令
启动当前节点的服务,如namenode、secondarynamenode、datanode、journalnode、dfs、dfsadmin、fsck、balancer、zkfc等:
$HADOOP_HOME/sbin/hadoop-daemon.sh start namenode
$HADOOP_HOME/sbin/hadoop-daemon.sh start datanode
注意:hadoop-daemons.sh其实就是在hadoop-daemon.sh的基础上还调用了salves.sh,通知其他机器执行命令,也就是说hadoop-daemon.sh只对一台机器起作用,但是hadoop-daemons.sh会对多台机器起作用。yarn-daemon.sh
同理。
或者分两个模块启动hdfs、yarn。
hdfs里面按顺序分别调用hadoop-daemons.sh脚本启动namenode,datanode,secondarynamenode,journalnode,zkfc。
stop-dfs.sh和start-dfs.sh一样,按照启动的顺序调用hadoop-daemons.sh来关闭服务进程;
yarn里面按顺序分别调用yarn-daemons.sh脚本启动resourcemanager,nodemanager服务。
stop-yarn.sh和start-yarn.sh一样,按照启动的顺序调用yarn-daemons.sh来关闭服务进程。
$HADOOP_HOME/sbin/start-dfs.sh
$HADOOP_HOME/sbin/start-yarn.sh
一个命令同时启动两个模块,不推荐:
$HADOOP_HOME/sbin/start-all.sh
sbin/mr-jobhistory-daemon.sh start historyserver
启动历史服务
HDFS shell命令
$HADOOP_HOME/bin/hdfs dfs
是对hdfs文件的操作命令,和linux中文件操作命令差不多。每一条命令都会读取配置文件。$HADOOP_HOME/bin/hdfs dfs -help ls
即可查看ls相关帮助信息。
常用有:$HADOOP_HOME/bin/hdfs dfs -get
下载文件,-P递归下载所有文件。$HADOOP_HOME/bin/hdfs dfs -text
读文件。 $HADOOP_HOME/bin/hdfs dfs -cat
读文件。$HADOOP_HOME/bin/hdfs dfs -ls
-R递归查看所有文件。$HADOOP_HOME/bin/hdfs dfs -cp
-r递归复制。$HADOOP_HOME/bin/hdfs dfs -getmerge
可以把多个文件(空格隔开)合并下载到本地。
-du -h 文件夹 查看文件夹大小、-put上传、-mkdir创建目录(-p递归创建)、-rm删除(-f删文件)(-R删目录)、-Dfs.defaultFS=file:/// -ls /读本地文件
-chown、 -chmod等。
$HADOOP_HOME/bin/hdfs dfsadmin
是对hdfs文件系统的管理命令。
-safemode enter | leave | get | wait即安全模式相关的
-report 查看集群报告
MR-jar执行
$HADOOP_HOME/bin/yarn jar xxx.jar mainClass /hdfs文件系统上的input文件夹 /hdfs文件系统上的output文件夹
HDFS api
Apache Hadoop Main 2.5.0-cdh5.3.6 API
Hadoop文件系统的接口
MapReducer-Java程序编写
数据类型
所有数据类型都实现Writable接口,以便可被序列化,最终实现网络传输和文件存储。
write()序列化
readFields()反序列化
因为MR中有个基于键的排序过程,所以作为键的类型必须实现Comparable<T>接口。重写compare()方法。
WritableComparable接口则是结合了以上两个接口。
还有一个接口RawComparaotor。
WritableComparable是需要把数据流反序列化为对象后,然后做对象之间的比较,而RawComparator是直接比较数据流的数据,不需要数据流反序列化成对象,省去了新建对象的开销。
1.基本数据类型
BooleanWritable、ByteWritable、DoubleWritable、FloatWritable
常用的来了:
IntWritable、LongWritable
Text文本类型,UTF-8编码的,
NullWritable,<key,value>中key或value是空时。
2.自定义数据类型
实际开发中常常需要自定义数据类型。
需要实现Writable接口或WritableComparable接口,然后重写hashCode()、equals()、compareTo()方法即可。
自定义Partitioner
继承Partitioner<KEY, VALUE>,并实现getPartition(KEY key, VALUE value, int numPartitions)方法
需要自定义分区器的情形1:
每一个Reduce的输出都是有序的,但是将所有Reduce的输出合并到一起却并非是全局有序的,如果要做到全局有序,我们该怎么做呢?最简单的方式,只设置一个Reduce task,但是这样完全发挥不出集群的优势,而且能应对的数据量也很受限。最佳的方式是自己定义一个Partitioner
用输入数据的最大值除以系统Reduce task数量的商作为分割边界,也就是说分割数据的边界为此商的1倍、2倍至numPartitions-1倍,这样就能保证执行partition后的数据是整体有序的。
需要自定义分区器的情形2:
各个Reduce task处理的键值对数量极不平衡。对于某些数据集,由于很多不同的key的hash值都一样,导致这些键值对都被分给同一个Reducer处理,而其他的Reducer处理的键值对很少,从而拖延整个任务的进度。(数据倾斜问题)
需要自定义分区器的情形3:
业务需要,如二次排序问题,不是根据key进行分区,而是key的某个属性进行分区。
数据格式
1.数据输入格式
抽象类InputFormat用于描述MR作业的数据输入格式规范。MapReduce框架依赖InputFormat进行输入数据分片以及提供读取分片数据的RecordReader实例对象。每一个InputFormat类都会有一个对应的RecordReader类,RecordReader类主要作用是将输入数据转换为键值对,传输给mapper阶段的map方法。Map input records
记录了mapper的输入数据条数。
MapReduce默认的数据输入格式是:TextInputFormat(LineRecordReader)。除了这个格式器以外,还有KeyValueTextInputFormat, CombineTextInputFormat, SequenceFileInputFormat, DBInputFormat等。
自定义时需要继承:
抽象类org.apache.hadoop.mapreduce.InputFormat:
getSplits:返回值是分片信息集合;作用:通过分片个数确定mappre的个数,并根据分片信息中的数据地址信息决定是否采用数据本地化策略。
createRecordReader:创建一个具体input数据并构造key/value键值对的RecordReader实例对象。
抽象类org.apache.hadoop.mapreduce.InputSplit:
getLength:获取分片长度。
getLocations:获取该分片数据对应的位置信息,确定数据本地化时候有用。
抽象类org.apache.hadoop.mapreduce.RecordReader:
initialize:根据对应的分片信息进行初始化操作。
nextKeyValue:判断是否还有下一个key/value键值对,如果有返回true;否则返回false。
getCurrentKey/getCurrentValue:获取当前key/value键值对。
getProgress:获取操作进度信息。
close:关闭资源读取相关连接。
2.数据输出格式
(OutputFormat)用于描述MR作业的数据输出格式规范。MapReduce框架依赖OutputFormat进行输出路径(输出空间)检测、获取提交job的OutputCommitter实例对象以及提供一个具体定义如何输出数据的RecordWriter实例对象。每一个OutputFormat类都会有一个对应的RecordWriter类,RecordWriter类主要作用是明确定义如何写入以及写入的格式,接收reducer阶段输出的key/value键值对。
MapReduce默认的数据输出格式是:TextOutputFormat(LineRecordWriter)。除了这个格式器以外,还有SequenceFileOutputFormat, DBOutputFormat等。
自定义时需要继承:
抽象类org.apache.hadoop.mapreduce.OutputFormat:
getRecordWriter:创建一个具体写数据的RecordWriter实例。
checkOutputSpecs:检测输出空间相关信息,如果检测失败,直接抛出异常。
getOutputCommitter:获取一个提交job的committer对象。一般情况下,直接使用FileOutputCommitter对象即可。如果觉得FileOutputCommitter内容比较多,也可以自己实现一个完全为空的类
抽象类org.apache.hadoop.mapreduce.RecordWriter:
write:接收reducer阶段产生的输出key/value键值对数据,并将其写出。
close:关闭流,进行一些其他操作。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。