概念
Hadoop是Apache旗下的一个用Java语言实现开源软件框架,是一个存储和计算大规模数据的软件平台。
框架内容
狭义解释
核心组件
- HDFS 分布式文件系统 - 解决海量数据存储
- MAPREDUCE 分布式运算编程框架 - 解决海量数据计算
- YARN 作业调度和集群资源管理的框架 - 解决资源任务调度
广义解释
Hadoop的生态圈
- HUE - 运营和开发Hadoop应用的图形化用户界面。
- Kafka - 大数据消息队列。
- Oozie - 用于 Hadoop 平台的开源的工作流调度引擎。 是用来管理Hadoop作业。
- Spark - 大规模数据处理的统一分析引擎。实时数据或者离线数据的分析。
- Flink - 实时数据流分析。
- Sqoop - 数据迁移工作,充当ETL工具。
- Hive - 数据仓库,可用作离线数据分析。
- Zeppelin - 可以进行大数据可视化分析的交互式开发系统,可以承担数据接入、数据发现、数据分析、数据可视化、数据协作等任务。
- Drill - Hadoop和NoSQL低延迟的SQL查询引擎。低延迟的分布式海量数据(涵盖结构化、半结构化以及嵌套数据)交互式查询引擎。
- Mahout - 提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序。
- Tajo - 一个分布式数据仓库系统,基于 Hadoop 实现,特点是低延迟、高可伸缩,提供专用查询和 ETL 工具。
- Avro - 一个数据序列化系统,设计用于支持大 批量数据交换的应用。
- Pig - 基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin,该语言的编译器会把类SQL的数据分析请求转换为一系列经过优化处理的MapReduce运算。Pig为复杂的海量数据并行计算提供了一个简单的操作和编程接口。
- Impala - 一个架构于hadoop之上的全新、开源MPP查询引擎,提供低延迟、高并发的以读为主的查询。
- Tez - 支持 DAG 作业的开源计算框架,它可以将多个有依赖的作业转换为一个作业从而大幅提升 DAG 作业的性能。计算引擎。
- Zookeeper - 一个分布式的,开放源码的分布式应用程序协调服务。
- Hbase - 一个高可靠性、高性能、面向列、可伸缩的分布式存储系统。
- Cassandra - 一套开源分布式数据库管理系统,由Facebook开发,用于储存特别大的数据。
- Redis - 高性能K-Vs数据库。
- Chukwa - 一个开源的用于监控大型分布式系统的数据收集系统。
- Mesos - 开源分布式资源管理框架,它被称为是分布式系统的内核。
- Yarn - 负责Hadoop集群中的资源管理(resource management)和对任务进行调度和监控(scheduling/monitoring)。
- MapReduce - 一种编程模型,用于大规模数据集(大于1TB)的并行运算。
- Flume - 一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。
- Hdfs - 设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统(Distributed File System)。
- Ambari - 一种基于Web的工具,支持Apache Hadoop集群的供应、管理和监控。
Hadoop配置的文件
配置文件名 | 配置对象 | 主要内容 |
---|---|---|
core-site.xml | 集群全局参数 | 用于定义系统级别的参数,如HDFS URL、Hadoop的临时目录等。 |
hdfs-site.xml | HDFS参数 | 如名称节点和数据节点的存放位置、文件副本的个数、文件读取权限 |
mapred-site.xml | Mapreduce参数 | 包括JobHistory Server和应用程序参数两部分,如reduce任务的默认个数、任务所能够使用内存的默认上下限等 |
yarn-site.xml | 集群资源管理系统参数 | 配置ResourceManager,NodeManager的通信端口,web监控端口等 |
Hadoop之HDFS
概述
HDFS定义
HDFS(Hadoop Distributed File System) 它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合做数据分析,并不适合用来做网盘应用。
优点
- 高容错性,数据自动保存多个副本。某一个副本丢失以后,它可以自动恢复。
- 适合处理大数据。
- 可在廉价机器上,通过多副本机制提高可靠性。
缺点
- 不适合低延时数据访问。
- 无法高效的对大量小文件进行存储。
- 不支持并发写入、文件随机修改。
HDFS组成架构
NameNode
Master,它是一个主管、管理者。
- 管理HDFS的名称空间
- 配置副本策略
- 管理数据块(Block)映射信息
- 处理客户端读写请求
DataNode
Slave,NameNode下达命令,DataNode执行实际的操作。
- 存储实际的数据块
- 执行数据块的读/写操作
Client客户端
- 文件切分。文件上传HDFS的时候,Client将文件切分为一个一个Block,然后进行上传
- 与NameNode交互,获取文件的位置信息
- 与DataNode交互,读取或者写入数据
- Client提供一些命令来管理HDFS,比如NameNode格式化
- Clientk可以通过一些命令来访问HDFS,比如对HDFS增删查改操作
Secondary NameNode
并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
- 辅助NameNode,分担其工作量
- 在紧急情况下,可辅助恢复NameNode
HDFS文件块
概述
hadoop集群中文件的存储都是以块的形式存储在hdfs中。
默认值
从2.7.3版本开始block size的默认大小为128M,之前版本的默认值是64M.
如何修改block块的大小?
可以通过修改hdfs-site.xml文件中的dfs.blocksize对应的值。
注意:在修改HDFS的数据块大小时,首先停掉集群hadoop的运行进程,修改完毕后重新启动。
block块大小设置规则
在实际应用中,hdfs block块的大小设置为多少合适呢?为什么有的是64M,有的是128M、256M、512呢?
首先我们先来了解几个概念:
1)寻址时间:HDFS中找到目标文件block块所花费的时间。
2)原理:文件块越大,寻址时间越短,但磁盘传输时间越长;文件块越小,寻址时间越长,但磁盘传输时间越短。
block不能设置过大,也不要能设置过小
- 如果块设置过大,一方面从磁盘传输数据的时间会明显大于寻址时间,导致程序在处理这块数据时,变得非常慢;另一方面,MapReduce中的map任务通常一次只处理一个块中的数据,如果块过大运行速度也会很慢。
- 如果设置过小,一方面存放大量小文件会占用NameNode中大量内存来存储元数据,而NameNode的内存是有限的,不可取;另一方面块过小,寻址时间增长,导致程序一直在找block的开始位置。因此,块适当设置大一些,减少寻址时间,那么传输一个有多个块组成的文件的时间主要取决于磁盘的传输速度。
多大合适呢?
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.
HDFS的Shell操作
shell
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 ...]]
HDFS的数据流
写数据流程
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使用的是就近读取。
Hadoop之MapReduce
概述
定义
MapReduce是一个分布式运算程序的编程框架,是用户开发"基于Hadoop的数据分析应用"的核心框架。
MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群中。
注意
- 不擅长实时计算
- 不擅长流式计算
- 不擅长DAG(有向图)计算
MapReduce核心编程思想
1)MapReduce运算程序一般需要分成2个阶段:Map阶段和Reduce阶段。
2)Map阶段的并发MapTask,完全并行运行,互不相干
3)Reduce阶段的并发ReduceTask,完全互不相干,但是他们的数据依赖于上一阶段的所有MapTask并发实例输出
4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
MapReduce进程
一个完整的MapReduce程序在分布式运行时有三类实例进程
- MrAppMaster 负责整个程序的过程调度及状态协调
- MapTask 负责Map阶段的整个数据处理流程
- ReduceTask 负责Reduce阶段的整个数据处理流程
MapReduce编程规范
Mapper阶段
1、用户自定义的Mapper要继承自己的父类
2、Mapper的输入数据是KVd对形式(KV的类型可自定义)
3、Mapper中的业务逻辑写在map()方法中
4、Mapper的输出数据是KV对的形式(KV的类型可自定义)
5、map()方法(MapTask进程)对每一个<K,V>调用一次
Reducer阶段
1、用户自定义的Reducer要继承自己的父类
2、Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
3、Reducer的业务逻辑写在reduce()方法中
4、ReduceTask进程对每一组相同K的<K,V>组调用一次reduce()方法
Driver阶段
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象
Hadoop序列化
序列化就是把内存中的对象,转换为字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。
反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换为内存中的对象。
Hadoop自己开发了一套序列化机制(Writable),特点
- 紧凑,高效使用存储空间
- 快速,读写数据的额外开销小
- 可扩展,随着通信协议的升级而可升级
- 互操作,支持多语言的交互
MapReduce框架原理
数据切片与MapTask并行度决定机制
- 一个Job的Map阶段并行度由客户端在提交Job时的切片数决定
- 每一个Split切片分配一个MapTask并行实例处理
- 默认情况下,切片大小=BlockSize
- 切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
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)
Shuffle机制
Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。
分区
要求将统计结果按照条件输出到不同文件中(分区)。
自定义分区
自定义分区Partitioner步骤
1)自定义类继承Partitioner,重写getPartition()方法
public class CustomPartitioner extends Partitioner<Text,FlowBean>{
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);
分区总结
- 如果ReduceTask的数量>getPartition的结果数,则会多产生几个空的输出文件part-r-000xx;
- 如果1<ReduceTask的数量=1,<getPartition的结果数,则有一部分分区数据无处安放,会Exception
- 如果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个ReduceTask,最终也就只会产生一个结果文件part-r-00000;
- 分区号必须从零开始,逐一累加。
排序
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;
}
}
Combiner合并
(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、创建一个构造将比较对象的类传给父类
Reduce Join
Map端的主要工作:为来自不同表或文件的key/value对, 打标签以区别不同来源的记录。然后用连接字段作为key ,其余部分和新加的标志作为value ,最后进行输出。
Reduce端的主要工作:在Reduce端以连接字段作为key的分组已经完成,我们只需要在每一个分组当中将那些来源于不同文件的记录(在Map阶段已经打标
志)分开,最后进行合并就ok了。
Map Join
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
Hadoop之YARN
概述
Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行于操作系统之上的应用程序.