Hadoop 是一个开源的分布式计算和存储框架,它的作用非常简单,就是在多计算机集群环境中营造一个统一而稳定的存储和计算环境,并能为其他分布式应用服务提供平台支持,相当于在某种程度上将多台计算机组织成了一台计算机。
Hadoop 框架最根本的原理就是利用大量的计算机同时运算来加快大量数据的处理速度。Hadoop 集群可运行于一般的商用服务器上,具有高容错、高可靠性、高扩展性等特点。适合一次写入,多次读取的场景,不适合频繁修改文件及大量的小文件和低延时的数据访问。
本文将对Hadoop 的三大核心组件进行介绍:
HDFS: 分布式文件系统
YARN: 分布式资源管理
MapReduce: 分布式计算系统
Hadoop Distributed File System,Hadoop分布式文件系统,简称HDFS。HDFS运行在许多不同的计算机上,有的计算机专门用于存储数据,有的计算机专门用于指挥其它计算机储存数据。这里所提到的"计算机"我们可以称之为集群中的节点。
命名节点又称管理节点,管理文件系统的命名空间,存储文件的元数据,它维护文件系统树及其所有文件和目录,数据会定时保存到本地磁盘,也记录每个文件中各个数据块所在的数据节点(DataNode)信息,但不保存数据块(Block)的位置信息,因为这些信息会在NameNode 每次重启后动态重建。若NameNode 失效则整个HDFS 都失效了,所以要保证NameNode 的可用性,这时就引入辅助命名节点(Secondary NameNode),它并不能代替NameNode 的工作,无论NameNode 是否有能力继续工作,它主要负责分摊命名节点的压力、备份命名节点的状态并执行一些管理工作,如果NameNode 坏掉了,它也可以提供备份数据以恢复NameNode。
保存具体的数据块(Block)的节点。当一个文件被命名节点(NameNode)承认并分块之后将会被储存到被分配的数据节点(DataNode)中去。DataNode 具有储存数据、读写数据的功能。
在HDFS 中,数据块的默认大小是128M,大于128M的文件将被拆分成多个数据块,每一个小于Block 大小的文件,存储是实际占用的存储空间仍然是实际的文件大小,而不是整个Block 大小。数据块默认备份3份存储在不同的DataNode 中,以提高可用性和容错能力,但如果集群只有两个DataNode,数据只会备份两份。一个Block 在NameNode 中对应一条记录(一般一个block占用150字节),如果是大量的小文件,会消耗大量内存。
1.客户端将文件写入本地磁盘的HDFS Client 文件中;
2.当临时文件大小达到一个block 大小时,HDFS client 通知NameNode,申请写入文件;
3.NameNode 在HDFS 的文件系统中创建一个文件,并把该block id 和要写入的DataNode 的列表返回给客户端;
4.客户端收到这些信息后,将临时文件写入DataNodes;
4.1 客户端将文件内容写入第一个DataNode;
4.2 第一个DataNode 接收后,将数据写入本地磁盘,同时也传输给第二个DataNode,依此类推到最后一个DataNode;
5.后面的DataNode 接收完数据后,都会发送一个确认给前一个DataNode,最终第一个 DataNode 返回确认给客户端;
6.当客户端接收到整个block 的确认后,会向NameNode 发送一个最终的确认信息。
如果写入某个DataNode 失败,数据会继续写入其他的DataNode。然后NameNode 会找另外一个好的DataNode 继续复制,以保证冗余性
每个block 都会有一个校验码,并存放到独立的文件中,以便读的时候来验证其完整性
假设复制参数是3,在写入文件时,会在本地的机架保存一份数据,然后在另外一个机架内保存两份数据。同机架内的传输速度快,从而提高性能(机架感应)
2.NameNode 返回文件的所有block 和这些block 所在的DataNodes
3.客户端直接从DataNode 中读取数据,如果该DataNode 读取失败,则从复制节点中读取。如果读取的数据就在本机,则直接读取,否则通过网络读取
#显示目录下的文件和子目录
hadoop fs -ls
#新建文件夹
hadoop fs -mkdir
#上传文件
hadoop fs -put hello.txt /hello/
#下载文件
hadoop fs -get /hello/hello.txt
#输出文件内容
hadoop fs -cat /hello/hello.txt
Yet Another Resource Negotiator 是一种新的Hadoop 资源管理器,简称YARN。它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处。
YARN 的基本思想是创建一个全局的ResourceManager(RM)和若干个针对应用程序的ApplicationMaster(AM)
RM 是一个全局的资源管理器,负责整个系统的资源管理和分配。
它主要由两个组件构成:调度器(Scheduler)和应用程序管理器(Applications Manager,ASM)。
RM 控制整个集群并管理应用程序向基础计算资源的分配,将各个资源部分(计算、内存、带宽等)精心安排给每个节点的任务和资源管理器(NodeManager)。RM 还与AM 一起分配资源,与NodeManager 一起启动和监视它们的基础应用程序。RM 只负责监控AM,在AM 运行失败时候启动它,并不负责AM 内部任务的容错,这由AM 自己完成。
应用程序管理器负责管理整个系统中所有应用程序,包括应用程序提交、与调度器协商资源以启动AM 、监控AM 运行状态并在失败时重新启动它等。
调度器根据容量、队列等限制条件,将系统中的资源分配给各个正在运行的应用程序,如每个队列分配一定的资源,最多执行一定数量的作业等。
调度器不再从事任何与具体应用程序相关的工作,比如不负责监控或者跟踪应用的执行状态等,也不负责重新启动因应用执行失败或者硬件故障而产生的失败任务,这些均交由应用程序相关的AM 完成。
调度器仅根据各个应用程序的资源需求进行资源分配,而资源分配单位用一个抽象概念“资源容器”(Resource Container,简称Container)表示。
Container 是一个动态资源分配单位,它将内存、CPU、磁盘、网络等资源封装在一起,从而限定每个任务使用的资源量。当AM 向RM 申请资源时,RM 为AM 返回的资源便是用Container 表示。YARN会为每个任务分配一个Container,且该任务只能使用该Container中描述的资源。
调度器是一个可插拔的组件,用户可根据自己的需要设计新的调度器,YARN 中有三种调度器可以选择:FIFO Scheduler,Capacity Scheduler,Fair Scheduler。
(1) FIFO Scheduler 将应用放置在一个队列中,按照提交的顺序先进先出运行应用。它的优点是简单易懂不需要任何配置,但是不适合共享集群。大型应用会占用集群中的所有资源,这就导致其它应用被阻塞。
(2) Capacity Scheduler 允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。除此之外,队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
(3) Fair Scheduler 会为所有运行的job 动态调整系统资源。当第一个大任务提交时,只有这一个任务在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair Scheduler 会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。Fair Scheduler 既得到了较高的资源利用率又能保证小任务及时完成。
AM 管理一个在YARN 内运行的应用程序的每个实例。AM 负责协调来自RM 的资源,并通过NodeManager 监视容器的执行和资源使用。用户提交的每个应用程序均包含一个AM,它计算应用的资源需求,向RM 申请资源,与NM 交互进行程序的运行和监控,监控申请的资源的使用情况,监控所有任务运行状态,并在任务运行失败时重新为任务申请资源以重启任务。
NM 是每个节点上的资源和任务管理器,它会定时地向RM 汇报本节点上的资源使用情况和各个Container 的运行状态,并接收并处理来自AM 的Container 启动/停止等各种请求。当RM 宕机时,NM 自动连接RM 备用节点。
首先客户端联系RM,要求它运行一个AM(步骤1)。RM 找到一个能够在Container 中启动AM 的节点管理器NM(步骤2)。AM 在所处Container 中进行一个简单计算将结果返回给客户端,或向RM 请求更多的Container(步骤3),以运行一个分布式计算(步骤4)。
1.客户端向YARN 提交应用程序;
2.RM 分配第一个Container,并与对应的NM 通信,要求它在这个Container 启动应用程序的ApplicationMaster;
3.AM 首先向RM 注册,通过RM 可以查看应用程序的运行状态,然后它将为各个任务申请资源,并监控它的运行状态,直至运行结束;
4.AM 采用轮询的方式通过RPC 协议向RM 申请和领取资源;
5.一旦AM 申请到资源后,便与对应的NM 通信,要求它启动任务;
6.NM 为任务设置好运行环境后,将任务启动命令写到一个脚本中,并通过运行该脚本启动任务;
7.各个任务通过RPC 协议向AM 汇报自己的状态和进度,让AM 随时掌握各个任务的运行状态,从而可以在任务失败时重启任务;
8.应用程序运行完成后,AM 向RM 注销并关闭自己。
#显示正在执行的yarn程序
yarn application -list
#停止指定的yarn程序
yarn application -kill <application_id>
#查看指定的yarn程序
yarn application - status <application_id>
#查看指定的yarn程序的尝试列表
yarn applicationattempt -list <application_id>
#查看指定的yarn程序的container列表
yarn container -list <Application Attempt ID>
#查看指定的container的信息
yarn container -status <Container ID>
#显示nodemanager列表
yarn node -list
#显示nodemanager信息
yarn node -status <Node-Id>
MapReduce 的含义就像它的名字一样:Map(映射)和Reduce (归约) 。
MapReduce 处理大规模数据的原理可以这样理解,先把样本分成一段段能够令单台计算机处理的规模,然后一段段地进行统计,每执行完一次统计就对映射统计结果进行规约处理,即将统计结果合并到一个更庞大的数据结果中去,最终就可以完成大规模的数据归约。
第一阶段的整理工作就是映射,把数据进行分类和整理,到这里我们可以得到一个相比于源数据小很多的结果。第二阶段的工作往往由集群来完成,整理完数据之后,我们需要将这些数据进行总体的归纳,毕竟有可能多个节点的映射结果出现重叠分类。这个过程中映射的结果将会进一步缩略成可获取的统计结果。
Partitioner 分区
对来自combiner 的输出数据按照key 值进行分区。对数据进行哈希运算,具有相同key 的记录会被分到相同的分区,每个分区会被发送给同一reducer
Sort 排序
对每个分区中的数据进行排序
Combiner
对mapper 的输出数据做本地聚合,减少mapper 和reducer 之间的数据传输
合并溢出文件
环形缓冲区每次溢出都会生成一个文件,所有map 任务完成前,它们会进行合并成为一个文件。由于每次溢出的文件都是按照分区进行排序的,在合并文件的过程中也会进行分区和排序,最终形成一个已经按分区排好序的map 输出文件
压缩
Map 输出结果在进行了一系列的分区、 排序、 combiner 合并、合并溢出文件后,得到一个 map 最
终的结果后,就应该真正存储这个结果了,在存储之前,可以对最终结果数据进行压缩,一是可
以节约磁盘空间,而是可以减少传递给 reduce 时的网络传输数据量
如MapReduce 计算中最为经典的Word Count 操作,经过上面一系列操作,最终输出统计结果
#提交一个job
hadoop job -submit <job-file>
#依据job-id杀掉指定job
hadoop job -kill <job-id>
#打印当前正在执行的job,加all则打印全部job
hadoop job -list [all]
#Kill任务,杀掉的任务不记录失败重试的数量
hadoop job -kill-task <task-id>
#fail任务,杀掉的任务不记录失败重试的数量
hadoop job -fail-task <task-id>
默认任务的尝试次数是4次,超过4次则不尝试。假设使用fail-task命令fail同一个任务四次,这个任务将不会继续尝试,并且会导致整个job失败
#改变JOB的优先级
hadoop job -set-priority <job-id> priority
同意的优先级有:VERY_HIGH, HIGH, NORMAL, LOW, VERY_LOW
参数名 | 默认值 | 备注 |
---|---|---|
dfs.block.size | 128M | HDFS 上数据块的大小. |
mapreduce.min.split.size | 0 | 最小分片大小. |
mapreduce.max.split.size | 256M | 最大分片大小. |
io.sort.mb | 100 | 映射输出分类时所使用缓冲区的大小. |
io.sort.record.percent | 0.05 | 剩余空间用于映射输出自身记录.在1.X发布后去除此属性.随机代码用于使用映射所有内存并记录信息. |
io.sort.spill.percent | 0.8 | 针对映射输出内存缓冲和记录索引的阈值使用比例. |
io.sort.factor | 10 | 文件分类时合并流的最大数量。此属性也用于reduce。通常把数字设为100. |
min.num.spills.for.combine | 3 | 组合运行所需最小溢出文件数目. |
mapred.compress.map.output | FALSE | 压缩映射输出. |
mapred.map.output.compression.codec | DefaultCodec | 映射输出所需的压缩解编码器. |
mapred.reduce.parallel.copies | 5 | 用于向reducer传送映射输出的线程数目. |
mapred.reduce.copy.backoff | 300 | 时间的最大数量,以秒为单位,这段时间内若reducer失败则会反复尝试传输 |
io.sort.factor | 10 | 组合运行所需最大溢出文件数目. |
mapred.job.shuffle.input.buffer.percent | 0.7 | 随机复制阶段映射输出缓冲器的堆栈大小比例 |
mapred.job.shuffle.merge.percent | 0.66 | 用于启动合并输出进程和磁盘传输的映射输出缓冲器的阀值使用比例 |
mapred.inmem.merge.threshold | 1000 | 用于启动合并输出和磁盘传输进程的映射输出的阀值数目。小于等于0意味着没有门槛,而溢出行为由 mapred.job.shuffle.merge.percent单独管理. |
mapred.job.reduce.input.buffer.percent | 0 | 用于减少内存映射输出的堆栈大小比例,内存中映射大小不得超出此值。若reducer需要较少内存则可以提高该值. |
注:文章内容主要参考:W3Cschool、《Hadoop 权威指南》及网上多篇文章