Hadoop是Apache旗下的一个用Java语言实现开源软件框架,是一个存储和计算大规模数据的软件平台。
核心组件
Hadoop的生态圈
配置文件名 | 配置对象 | 主要内容 |
---|---|---|
core-site.xml | 集群全局参数 | 用于定义系统级别的参数,如HDFS URL、Hadoop的临时目录等。 |
hdfs-site.xml | HDFS参数 | 如名称节点和数据节点的存放位置、文件副本的个数、文件读取权限 |
mapred-site.xml | Mapreduce参数 | 包括JobHistory Server和应用程序参数两部分,如reduce任务的默认个数、任务所能够使用内存的默认上下限等 |
yarn-site.xml | 集群资源管理系统参数 | 配置ResourceManager,NodeManager的通信端口,web监控端口等 |
HDFS(Hadoop Distributed File System) 它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合做数据分析,并不适合用来做网盘应用。
优点
缺点
Master,它是一个主管、管理者。
Slave,NameNode下达命令,DataNode执行实际的操作。
并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
hadoop集群中文件的存储都是以块的形式存储在hdfs中。
从2.7.3版本开始block size的默认大小为128M,之前版本的默认值是64M.
可以通过修改hdfs-site.xml文件中的dfs.blocksize对应的值。
注意:在修改HDFS的数据块大小时,首先停掉集群hadoop的运行进程,修改完毕后重新启动。
在实际应用中,hdfs block块的大小设置为多少合适呢?为什么有的是64M,有的是128M、256M、512呢?
首先我们先来了解几个概念:
1)寻址时间:HDFS中找到目标文件block块所花费的时间。
2)原理:文件块越大,寻址时间越短,但磁盘传输时间越长;文件块越小,寻址时间越长,但磁盘传输时间越短。
多大合适呢?
1)HDFS中平均寻址时间大概为10ms;
2)经过前任的大量测试发现,寻址时间为传输时间的1%时,为最佳状态,所以最佳传输时间为:
10ms/0.01=1000s=1s
3)目前磁盘的传输速度普遍为100MB/s,最佳block大小计算:
00MB/s*1s=100MB
所以我们设置block大小为128MB.
4)实际中,磁盘传输速率为200MB/s时,一般设定block大小为256MB;磁盘传输速率为400MB/s时,一般设定block大小为512MB.
Usage: hadoop fs [generic options]
[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] [-v] [-x] <path> ...]
[-expunge [-immediate]]
[-find <path> ... <expression> ...]
[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getfattr [-R] {-n name | -d} [-e en] <path>]
[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
[-head <file>]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setfattr {-n name [-v value] | -x name} <path>]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] [-s <sleep interval>] <file>]
[-test -[defswrz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touch [-a] [-m] [-t TIMESTAMP ] [-c] <path> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]
1、客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
2、NameNode返回是否可以上传
3、客户端请求第一个Block上传到哪几个DataNode服务器上。
4、NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
5、客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道j建立完成。
6、dn1、dn2、dn3逐级应答客户端。
7、客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1没传一个Packet会放入一个应答队列等待应答。
8、当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
1、HDFS通过Distributed FileSystem模块向NameNode请求获得文件开始部分或者全部Block列表
2、NameNode返回Block列表
3、Client Node从距离最近的DataNode上读取数据。
4、Client Noded调用read() 方法
5、找出离ClientNode最近的DataNode并连接DataNode读取
HDFS使用的是就近读取。
MapReduce是一个分布式运算程序的编程框架,是用户开发"基于Hadoop的数据分析应用"的核心框架。
MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群中。
注意
1)MapReduce运算程序一般需要分成2个阶段:Map阶段和Reduce阶段。
2)Map阶段的并发MapTask,完全并行运行,互不相干
3)Reduce阶段的并发ReduceTask,完全互不相干,但是他们的数据依赖于上一阶段的所有MapTask并发实例输出
4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
一个完整的MapReduce程序在分布式运行时有三类实例进程
1、用户自定义的Mapper要继承自己的父类
2、Mapper的输入数据是KVd对形式(KV的类型可自定义)
3、Mapper中的业务逻辑写在map()方法中
4、Mapper的输出数据是KV对的形式(KV的类型可自定义)
5、map()方法(MapTask进程)对每一个
1、用户自定义的Reducer要继承自己的父类
2、Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
3、Reducer的业务逻辑写在reduce()方法中
4、ReduceTask进程对每一组相同K的
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象
序列化就是把内存中的对象,转换为字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。
反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换为内存中的对象。
Hadoop自己开发了一套序列化机制(Writable),特点
数据切片与MapTask并行度决定机制
FileInputFormat切片源码解析
1、程序先找到数据存储目录
2、遍历处理目录下的每一个文件
3、遍历第一个文件ss.txt
a、获取文件大小,fs.sizeOf(ss.txt)
b、计算切片大小
computeSliteSize(Math.max(minSize,Math.min(maxSize,blockSize)))=blocksize = 128M
c、默认情况下,切片大小=blocksize
d、开始切,形成第一个切片 ss.txt - 0-128M
第二个切片 128 - 2556M
第三个切片 256 - 300M
(每次切片时,都要判断切完剩下的部分是否大于块的1.1倍,不大于1.1倍就划分一块切片)
e、将切片信息写到一个切片规划文件中
f、整个切片的核心过程在getSplit()方法中完成
g、InputSplit只记录了切片的元数据信息,比如起始位置、长度以及所在的节点列表等。
4、提交切分规划文件到YARN上,YARN上的MrAppMaster就可以根据切片规划文件计算开启MapTask个数。
CombineTextInputFormat切片机制
框架默认的TextInputFormat切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。
1、应用场景
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,
这样多小的文件就可以交给一个MapTask处理。
2、虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job,4194304); //4M
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
KeyValueTextInputFormat
每一行均为一条记录,被分隔符分割为key,value。可以通过在驱动类中设置conf.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR,“\t”);来设定分隔符。默认分隔符是tab(\t)。
NLineInputFormat
如果使用NLineInputFormat,代表每个map进程处理的InputSplit不再按Block块去划分,而是按NLineInputFormat指定的行数N来划分。即输入文件的总行数/N=切片数,如果不整除,切片数=商+1.
//设置每个切片InputSplit中划分三条记录
NLineInputFormat.setNumLinesPerSplit(job,3)
Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。
要求将统计结果按照条件输出到不同文件中(分区)。
自定义分区
自定义分区Partitioner步骤
1)自定义类继承Partitioner,重写getPartition()方法
public class CustomPartitioner extends Partitioner{
public int getPartition(Text key,FlowBean value,int numPartitions){
//逻辑代码
return partition;
}
}
2)在Job驱动中,设置自定义Partitioner
job.setPartitionerClass(CustomPartitioner.class);
3)自定义Partition后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask
job.setNumReduceTasks(5);
分区总结
MapTask和ReduceTask均会对数据按照key进行排序。该操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。
默认排序是按照字典顺序排序,且实现该排序的方法是快速排序。
1)部分排序:MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部有序。
2)全排序:最终结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。但该方法在处理大型文件时效率极低,因为一台机器处理所有文件,完全丧失了MapReduce所提供的并行架构。
3) 辅助排序:在Reduce端对key进行分组。应用于:在接收的key为bean对象时,想让一个或几个字段相同(全部字段比较不相同)的key进入到同一个reduce方法时,可以采用分组排序。
4)二次排序:在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。
5)自定义排序:Bean需要实现WritableComparble接口重写compareTo方法,就可以实现排序
案例
public class FlowBean implements WritableComparble{
public int compareTo(FlowBean bean){
int result;
if(sumFlow > bean.getSumFlow()){
result = -1;
}else if(sumFlow < bean.getSumFlow()){
result = 1;
}else{
result = 0;
}
return result;
}
}
(1) Combiner是MR程序中Mapper和Reducer之外的一种组件。
(2) Combiner组件的父类就是Reducer。
(3) Combiner和Reducer的区别在于运行的位置:
Combiner是在每一个MapTask所在的节点运行;
Reducer是接收全局所有Mapper的输出结果;
(4)Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减小网络传输量。
(5) Combiner能 够应用的前提是不能影响最终的业务逻辑,而且,Combiner的输出kv应该跟Reducer的输入kv类型要对应起来。
1、自定义类继承WritableComparaator
2、重写compare方法
3、创建一个构造将比较对象的类传给父类
Map端的主要工作:为来自不同表或文件的key/value对, 打标签以区别不同来源的记录。然后用连接字段作为key ,其余部分和新加的标志作为value ,最后进行输出。
Reduce端的主要工作:在Reduce端以连接字段作为key的分组已经完成,我们只需要在每一个分组当中将那些来源于不同文件的记录(在Map阶段已经打标
志)分开,最后进行合并就ok了。
Map Join适合于一张表十分小,一张表十分大的场景。
** 输入数据接口 InputFormat**
1、默认使用实现类 TextInputFormat
2、TextInputFormat功能逻辑是:
一次读一行文本,然后将该行的起始编译量作为Key,行内容作为value返回
3、KeyValueTextInputFormat每一行均为一条记录,被分隔符分割为key,value。默认分隔符是tab
4、NlineInputFormat按照指定的行数N来划分切片
5、CombineTextInputFormat可以把多个小文件合并成一个切片处理,提高处理效率。
6、用户还可以自定义InputFormat
逻辑处理接口 Mapper
用户根据业务需求实现其中三个方法
map() setup() cleanup()
Partitioner分区
默认实现HashPartitioner,逻辑是根据key的哈希值和numReduces来返回一个分区号
用户可自定义分区号
Comparable排序
1、我们用自定义的对象作为key来输出时,就必须要实现WritableComparable接口,重写其中compareTo()方法
2、部分排序:对最终输出每一个文件进行内部排序
3、全排序:对所有数据进行排序,通常只有一个Reduce
4、二次排序:对排序的条件有两个
Combiner
Combiner合并可以提高程序执行效率,减少IO传输,但是使用时必须不能影响原有的业务处理结果。
Reduce端分组 GroupingComparator
在Reduce端对key进行分组。应用于:在接收的key为bean对象时,想让一个或几个字段相同(全部字段比较不相同)的key进入到同一个reduce方法时,可以使用分组排序。
逻辑处理接口 Reducer
用户根据业务需求实现 reduce() setup() cleanup()
输出数据接口 OutputFormat
1、默认实现类是TextOutputFormat,功能逻辑是:将每一个KV对,向目标文本文件输出一行
2、将SequenceFileOutputFormat输出作为后续MapReduce任务输入。
3、用户可自定义OutputFFormat
Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行于操作系统之上的应用程序.