hadoop学习
Hadoop 概述
1、Hadoop是什么
- Hadoop是一个由Apache基金会开发的分布式系统基础架构;
- 主要解决海量数据的存储和分析计算问题;
- 广义上来说,Hadoop通常是指一个更广泛的概念——Hadoop生态圈;
【Hadoop 三大发行版本】
- Apache:版本最原始(最基础)的版本,对于入门学习最好。2006
- Cloudera:内部集成了很多大数据框架,对应产品 CDH。2008
- Hortonworks:文档较好,对应产品 HDP。2011(Hortonworks 现在已经被 Cloudera 公司收购,推出新的品牌 CDP)
2、Hadoop 优势
- 高可靠性:Hadoop底层维护多个数据副本,所以即使Hadoop某个计算元素或存储出现故障,也不会导致数据的丢失。
- 高扩展性:在集群间分配任务数据,可方便的扩展数以千计的节点。
- 高效性:在MapReduce的思想下,Hadoop是并行工作的,以加快任务处理速度。
- 高容错性:能够自动将失败的任务重新分配。
3、Hadoop 组成
【Hadoop1.x、2.x、3.x区别】
- 在 Hadoop1.x 时代,Hadoop中的MapReduce同时处理业务逻辑运算和资源的调度,耦合性较大。
- 在 Hadoop2.x 时代,增加了Yarn。Yarn只负责资源的调度 ,MapReduce只负责运算。
- Hadoop3.x在组成上没有变化。
(1)HDFS 架构
Hadoop Distributed File System,简称 HDFS,是一个分布式文件系统。
- NameNode(nn):存储文件的元数据,如文件名,文件目录结构,文件属性(生成时间、副本数、 文件权限),以及每个文件的块列表和块所在的DataNode等。
- DataNode(dn):在本地文件系统存储文件块数据,以及块数据的校验和。
- Secondary NameNode(2nn):每隔一段时间对NameNode元数据备份。
(2)YARN 架构
Yet Another Resource Negotiator 简称 YARN ,另一种资源协调者,是 Hadoop 的资源管理器。
- ResourceManager(RM):整个集群资源(内存、CPU等)的老大
- NodeManager(NM):单个节点服务器资源老大
- ApplicationMaster(AM):单个任务运行的老大
- Container:容器,相当一台独立的服务器,里面封装了任务运行所需要的资源,如内存、CPU、磁盘、网络等
(3)MapReduce 架构
MapReduce 将计算过程分为两个阶段:Map 和 Reduce
- Map 阶段并行处理输入数据;
- Reduce 阶段对 Map 结果进行汇总;
(4)HDFS、YARN、MapReduce 三者关系
4、大数据技术生态体系
- Sqoop:Sqoop 是一款开源的工具,主要用于在 Hadoop、Hive 与传统的数据库(MySQL) 间进行数据的传递,可以将一个关系型数据库(例如 :MySQL,Oracle 等)中的数据导进 到 Hadoop 的 HDFS 中,也可以将 HDFS 的数据导进到关系型数据库中。
- Flume:Flume 是一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统, Flume 支持在日志系统中定制各类数据发送方,用于收集数据;
- Kafka:Kafka 是一种高吞吐量的分布式发布订阅消息系统;
- Spark:Spark 是当前最流行的开源大数据内存计算框架。可以基于 Hadoop 上存储的大数 据进行计算。
- Flink:Flink 是当前最流行的开源大数据内存计算框架。用于实时计算的场景较多。
- Oozie:Oozie 是一个管理 Hadoop 作业(job)的工作流程调度管理系统。
- Hbase:HBase 是一个分布式的、面向列的开源数据库。HBase 不同于一般的关系数据库, 它是一个适合于非结构化数据存储的数据库。
- Hive:Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张 数据库表,并提供简单的 SQL 查询功能,可以将 SQL 语句转换为 MapReduce 任务进行运行。其优点是学习成本低,可以通过类 SQL 语句快速实现简单的 MapReduce 统计,不必开发专门的 MapReduce 应用,十分适合数据仓库的统计分析。
- ZooKeeper:它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、 名字服务、分布式同步、组服务等。
5、Hadoop 配置文件
【默认配置文件】
- core-default.xml:默认的核心Hadoop属性文件
- hdfs-default.xml:默认的HDFS属性配置文件
- mapred-default.xml:默认MapReduce属性配置文件
- yarn-default.xml:默认的YARN属性配置文件
【自定义配置文件】
- core-site.xml:配置文件的配置项会覆盖core-default.xml中的相同配置
- hdfs-site.xml:配置文件的配置项会覆盖hdfs-default.xml中的相同配置
- mapred-site.xml:配置文件的配置项会覆盖mapred-default.xml的相同配置
- yarn-site.xml:配置文件的配置项会覆盖yarn-default.xml的相同配置
HDFS
1、HDFS 概述
【HDFS 产生背景】
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS 只是分布式文件管理系统中的一种。
【HDFS 定义】
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS 的使用场景:适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭之后就不需要改变。
【优点】
- 高容错性:数据自动保存多个副本。它通过增加副本的形式,提高容错性。某一个副本丢失以后,它可以自动恢复
- 适合处理大数据:
- 数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据;
- 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
- 可构建在廉价机器上,通过多副本机制,提高可靠性。
【缺点】
- 不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
- 无法高效的对大量小文件进行存储
- 存储大量小文件的话,它会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode的内存总是有限的;
- 小文件存储的寻址时间会超过读取时间,它违反了HDFS的设计目标。
- 不支持并发写入、文件随机修改
- 一个文件只能有一个写,不允许多个线程同时写;
- 仅支持数据append(追加),不支持文件的随机修改。
2、HDFS 组成架构
- NameNode:就是Master,它是一个主管、管理者。
- 管理HDFS的名称空间;
- 配置副本策略;
- 管理数据块(Block)映射信息;
- 处理客户端读写请求。
- DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操作。
- 存储实际的数据块;
- 执行数据块的读/写操作。
- Client:就是客户端。
- 文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;
- 与NameNode交互,获取文件的位置信息;
- 与DataNode交互,读取或者写入数据;
- Client提供一些命令来管理HDFS,比如NameNode格式化;
- Client可以通过一些命令来访问HDFS,比如对HDFS增删查改操作;
- Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
- 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode ;
- 在紧急情况下,可辅助恢复NameNode。
3、HDFS 文件块大小
HDFS中的文件在物理上是分块存储(Block),块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在Hadoop2.x/3.x版本中是128M,1.x版本中是64M。
【为什么块的大小不能设置太小,也不能设置太大】
- HDFS的块设置太小,会增加寻址时间,程序一直在找块的开始位置;
- 如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。导致程序在处理这块数据时,会非常慢。
(总结:HDFS块的大小设置主要取决于磁盘传输速率)
【数据单位】
- block
- 文件上传前需要分块,这个块就是block,一般为128MB,可以修改。因为块太小:寻址时间占比过高。块太大:Map任务数太少,作业执行速度变慢。它是最大的一个单位;
- packet
- packet是第二大的单位,它是client端向DataNode,或DataNode的PipLine之间传数据的基本单位,默认64KB。
- chunk
- chunk是最小的单位,它是client向DataNode,或DataNode的PipLine之间进行数据校验的基本单位,默认512Byte,因为用作校验,故每个chunk需要带有4Byte的校验位。所以实际每个chunk写入packet的大小为516Byte。由此可见真实数据与校验值数据的比值 约为128 : 1。(即64*1024 / 512)
4、HDFS 的读写流程
(1)写数据流程
- 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
- NameNode 返回是否可以上传。
- 客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
- NameNode 返回 3 个 DataNode 节点,分别为 dn1、dn2、dn3。
- 客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
- dn1、dn2、dn3 逐级应答客户端。
- 客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存), 以 Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 packet 会放入一个应答队列等待应答。
- 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3-7 步)
【网络拓扑-节点距离计算】
在HDFS写数据的过程中,NameNode 会选择距离待上传数据最近距离的 DataNode 接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和
【Hadoop3.1.3副本节点选择】
- 第一个副本在Client所处的节点上。 如果客户端在集群外,随机选一个。
- 第二个副本在另一个机架的随机一个节点
- 第三个副本在第二个副本所在机架的随机节点
(2)读数据流程
- 客户端通过 DistributedFileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据,找到文件块所在的 DataNode 地址。
- 挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
- DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)。
- 客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。
(3)数据完整性校验机制
- HDFS写流程
- 客户端通过管道将数据发送到多个DataNode上,并在管道的最后一个DataNode节点上,先对数据内容计算出校验和,然后和数据中存储的校验和进行比较,如果不一致则抛出异常;
- HDFS读流程
- 客户端在收到DataNode返回的数据块时,先对数据内容计算出校验和,然后和数据块中存储的校验和进行比较,如果不一致则上报坏块并选择其他节点读取;
5、NameNode 工作机制
思考:NameNode 中的元数据是存储在哪里的?
首先,我们做个假设,如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的 FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新 FsImage,就会导 致效率过低,但如果不更新,就会发生一致性问题,一旦 NameNode 节点断电,就会产生数 据丢失。因此,引入 Edits 文件(只进行追加操作,效率很高)每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到 Edits 中。这样,一旦 NameNode 节点断电,可 以通过 FsImage 和 Edits 的合并,合成元数据。
但是,如果长时间添加数据到 Edits 中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行 FsImage 和 Edits 的合并,如果这 个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode, 专门用于 FsImage 和 Edits 的合并。
第一阶段:NameNode 启动
- 第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
- 客户端对元数据进行增删改的请求。
- NameNode 记录操作日志,更新滚动日志。
- NameNode 在内存中对元数据进行增删改。
第二阶段:Secondary NameNode 工作
- Secondary NameNode 询问 NameNode 是否需要 CheckPoint。直接带回 NameNode 是否检查结果。
- Secondary NameNode 请求执行 CheckPoint。
- NameNode 滚动正在写的 Edits 日志。
- 将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode。
- Secondary NameNode 加载编辑日志和镜像文件到内存,并合并。
- 生成新的镜像文件 fsimage.chkpoint。
- 拷贝 fsimage.chkpoint 到 NameNode。
- NameNode 将 fsimage.chkpoint 重新命名成 fsimage。
6、DataNode 工作机制
- 一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
- DataNode 启动后向 NameNode 注册,通过后,周期性(6 小时)的向 NameNode 上报所有的块信息。
- 心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳, 则认为该节点不可用。
- 集群运行中可以安全加入和退出一些机器。
【DataNode掉线时限参数设置】
1、DataNode进程死亡或者网络故障造成DataNode 无法与NameNode通信;
2、NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
3、HDFS默认的超时时长为10分钟+30秒。
4、如果定义超时时间为TimeOut,则超时时长的计算公式为:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
7、HDFS 的 Shell 操作
基本语法:hadoop fs 具体命令 | hdfs dfs 具体命令,大部分命令跟Linux命令类似;
- 帮助命令: hadoop fs -help
- 上传:hadoop fs -put <本地目录或文件> <HDFS目录或文件>
- 下载:hadoop fs -get <HDFS目录或文件> <本地目录或文件>
MapReduce
1、MapReduce 概述
【MapReduce 定义】
MapReduce 是一个分布式运算程序的编程框架,是用户开发“基于 Hadoop 的数据分析 应用”的核心框架。 MapReduce 核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个 Hadoop 集群上。
【优点】
- MapReduce 易于编程:它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的 PC 机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一 样的。就是因为这个特点使得 MapReduce 编程变得非常流行。
- 良好的扩展性:当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
- 高容错性:MapReduce 设计的初衷就是使程序能够部署在廉价的 PC 机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行, 不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由 Hadoop 内部完成的。
- 适合 PB 级以上海量数据的离线处理:可以实现上千台服务器集群并发工作,提供数据处理能力。
【缺点】
- 不擅长实时计算:MapReduce 无法像 MySQL 一样,在毫秒或者秒级内返回结果。
- 不擅长流式计算:流式计算的输入数据是动态的,而 MapReduce 的输入数据集是静态的,不能动态变化。 这是因为 MapReduce 自身的设计特点决定了数据源必须是静态的。
- 不擅长 DAG(有向无环图)计算:多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下, MapReduce 并不是不能做,而是使用后,每个 MapReduce 作业的输出结果都会写入到磁盘, 会造成大量的磁盘 IO,导致性能非常的低下。
2、MapReduce 核心思想
- 分布式的运算程序往往需要分成至少 2 个阶段。
- 第一个阶段的 MapTask 并发实例,完全并行运行,互不相干。
- 第二个阶段的 ReduceTask 并发实例互不相干,但是他们的数据依赖于上一个阶段 的所有 MapTask 并发实例的输出。
- MapReduce 编程模型只能包含一个 Map 阶段和一个 Reduce 阶段,如果用户的业 务逻辑非常复杂,那就只能多个 MapReduce 程序,串行运行。
【MapReduce 进程】
一个完整的 MapReduce 程序在分布式运行时有三类实例进程:
- MrAppMaster:负责整个程序的过程调度及状态协调。
- MapTask:负责 Map 阶段的整个数据处理流程。
- ReduceTask:负责 Reduce 阶段的整个数据处理流程。
3、MapReduce 编程规范
用户编写的程序分成三个部分:Mapper、Reducer 和 Driver。
- Mapper阶段
- 用户自定义的Mapper要继承自己的父类
- Mapper的输入数据是KV对的形式(KV的类型可自定义)
- Mapper中的业务逻辑写在map()方法中
- Mapper的输出数据是KV对的形式(KV的类型可自定义)
- map()方法(MapTask进程)对每一个调用一次
- Reducer阶段
- 用户自定义的Reducer要继承自己的父类
- Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
- Reducer的业务逻辑写在reduce()方法中
- ReduceTask进程对每一组相同k的组调用一次reduce()方法
- Driver阶段
- 相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象
【常用数据序列化类型】
4、MapReduce 框架原理
(1)InputFormat 数据输入
【数据切片与MapTask 并行度决定机制】
- 数据块:Block 是 HDFS 物理上把数据分成一块一块。数据块是 HDFS 存储数据单位。
- 数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行 存储。数据切片是 MapReduce 程序计算输入数据的单位,一个切片会对应启动一个 MapTask。
1.1、FileInputFormat
【FileInputFormat切片机制】
- 简单地按照文件的内容长度进行切片
- 切片大小,默认等于Block大小
- 切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
1.2、TextInputFormat
TextInputFormat 是默认的 FileInputFormat 实现类。按行读取每条记录。键是存储该行在 整个文件中的起始字节偏移量, LongWritable 类型。值是这行的内容,不包括任何行终止符(换行符和回车符),Text 类型。
1.3、CombineTextInputFormat
CombineTextInputFormat 用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个 MapTask 处理。
(2)MapReduce 工作流程
(3)Shuffle 机制
Map 方法之后,Reduce 方法之前的数据处理过程称之为 Shuffle。
【Shuffle 过程】
- MapTask 收集我们的 map()方法输出的 kv 对,放到内存缓冲区中;
- 从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件 ;
- 多个溢出文件会被合并成大的溢出文件;
- 在溢出过程及合并的过程中,都要调用 Partitioner 进行分区和针对 key 进行排序;
- ReduceTask 根据自己的分区号,去各个 MapTask 机器上取相应的结果分区数据
- ReduceTask 会抓取到同一个分区的来自不同 MapTask 的结果文件,ReduceTask 会将这些文件再进行合并(归并排序)
- 合并成大文件后,Shuffle 的过程也就结束了,后面进入 ReduceTask 的逻辑运算过程(从文件中取出一个一个的键值对 Group,调用用户自定义的 reduce()方法)
(4)Partition 分区
在进行MapReduce计算时,有时候需要把最终的输出数据分到不同的文件中,比如按照省份划分的话,需要把同一省份的数据放到一个文件中。我们知道最终的输出数据是来自于Reducer任务。那么,如果要得到多个文件,意味着有同样数量的Reducer任务在运行。
Reducer任务的数据来自于Mapper任务,也就说Mapper任务要划分数据,对于不同的数据分配给不同的Reducer任务运行。Mapper任务划分数据的过程就称作Partition。负责实现划分数据的类称作Partitioner。
【默认 partition 分区】
- 源码中:numReduceTasks:默认是1,numReduceTasks如果等于1不会走getPartition方法,
- 默认分区是根据key的hashCode对ReduceTasks个数取模得到的。用户没法控制哪个key存储到哪个分区。
【自定义Partition】
【分区总结】
- 如果ReduceTask的数量 > getPartition的结果数,则会多产生几个空的输出文件part-r-000xx;
- 如果1 < ReduceTask的数量 < getPartition的结果数,则有一部分分区数据无处安放,会Exception;
- 如果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个ReduceTask,最终也就只会产生一个结果文件part-r-00000;
- 分区号必须从零开始,逐一累加。
(5)WritableComparable 排序
排序是MapReduce框架中最重要的操作之一。
MapTask和ReduceTask均会对数据按照key进行排序。该操作属于 Hadoop的默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。
默认排序是按照字典顺序排序,且实现该排序的方法是快速排序。
- 对于MapTask:
- 它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值后,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行归并排序。
- 对于ReduceTask:
- 它从每个MapTask上远程拷贝相应的数据文件,如果文件大小超过一定阈值,则溢写磁盘上,否则存储在内存中。如果磁盘上文件数目达到一定阈值,则进行一次归并排序以生成一个更大文件;如果内存中文件大小或者 数目超过一定阈值,则进行一次合并后将数据溢写到磁盘上。当所有数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序。
(6)Combiner 合并
- Combiner是MR程序中Mapper和Reducer之外的一种组件。
- Combiner组件的父类就是Reducer。
- Combiner和Reducer的区别在于运行的位置 Combiner是在每一个MapTask所在的节点运行;
- Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减小网络传输量。
- Combiner能够应用的前提是不能影响最终的业务逻辑,而且Combiner的输出kv 应该跟Reducer的输入kv类型要对应起来。
(7)OutputFormat 数据输出
OutputFormat是MapReduce输出的基类,所有实现MapReduce输出都实现了OutputFormat 接口。默认输出格式TextOutputFormat。
【ReduceTask 并行度决定机制】
ReduceTask 的并行度同样影响整个 Job 的执行并发度和执行效率,但与MapTask 的并发数由切片数决定不同,ReduceTask 数量的决定是可以直接手动设置的,默认是1;
(8)MapTask 工作机制
- Read 阶段:MapTask 通过 InputFormat 获得的 RecordReader,从输入 InputSplit 中 解析出一个个 key/value。
- Map 阶段:该节点主要是将解析出的 key/value 交给用户编写 map()函数处理,并 产生一系列新的 key/value。
- Collect 收集阶段:在用户编写 map()函数中,当数据处理完成后,一般会调用 OutputCollector.collect()输出结果。在该函数内部,它会将生成的 key/value 分区(调用 Partitioner),并写入一个环形内存缓冲区中。
- 溢写阶段:当环形缓冲区满后,MapReduce 会将数据写到本地磁盘上, 生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。
- Merge 阶段:当所有数据处理完成后,MapTask 对所有临时文件进行一次合并, 以确保最终只会生成一个数据文件。
(9)ReduceTask 工作机制
- Copy 阶段:ReduceTask 从各个 MapTask 上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
- Sort 阶段:在远程拷贝数据的同时,ReduceTask 启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。按照 MapReduce 语义,用户编写 reduce()函数输入数据是按 key 进行聚集的一组数据。为了将 key 相同的数据聚在一 起,Hadoop 采用了基于排序的策略。由于各个 MapTask 已经实现对自己的处理结果进行了 局部排序,因此,ReduceTask 只需对所有数据进行一次归并排序即可。
- Reduce 阶段:reduce()函数将计算结果写到 HDFS 上。
5、Hadoop 数据压缩
【压缩的好处和坏处】
- 优点:以减少磁盘 IO、减少磁盘存储空间。
- 缺点:增加 CPU 开销。
【压缩原则】
- 运算密集型的 Job,少用压缩
- IO 密集型的 Job,多用压缩
【常见压缩方式】
- Gzip 压缩
- 优点:压缩率比较高;
- 缺点:不支持 Split;压缩/解压速度一般;
- Bzip2 压缩
- 优点:压缩率高;支持 Split;
- 缺点:压缩/解压速度慢。
- Lzo 压缩
- 优点:压缩/解压速度比较快;支持 Split;
- 缺点:压缩率一般;想支持切片需要额外创建索引。
- Snappy 压缩
- 优点:压缩和解压缩速度快;
- 缺点:不支持 Split;压缩率一般
YARN
Yarn 是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而 MapReduce 等运算程序则相当于运行于操作系统之上的应用程序。
1、Yarn 基础架构
YARN 主要由 ResourceManager、NodeManager、ApplicationMaster 和 Container 等组件构成。
2、Yarn 工作机制
- MR 程序提交到客户端所在的节点。
- YarnRunner 向 ResourceManager 申请一个 Application。
- RM 将该应用程序的资源路径返回给 YarnRunner。
- 该程序将运行所需资源提交到 HDFS 上。
- 程序资源提交完毕后,申请运行 mrAppMaster。
- RM 将用户的请求初始化成一个 Task。
- 其中一个 NodeManager 领取到 Task 任务。
- 该 NodeManager 创建容器 Container,并产生 MRAppmaster。
- Container 从 HDFS 上拷贝资源到本地。
- MRAppmaster 向 RM 申请运行 MapTask 资源。
- RM 将运行 MapTask 任务分配给另外两个 NodeManager,另两个 NodeManager 分别领取任务并创建容器。
- MR 向两个接收到任务的 NodeManager 发送程序启动脚本,这两个 NodeManager 分别启动 MapTask,MapTask 对数据分区排序。
- MrAppMaster 等待所有 MapTask 运行完毕后,向 RM 申请容器,运行 ReduceTask。
- ReduceTask 向 MapTask 获取相应分区的数据。
- 程序运行完毕后,MR 会向 RM 申请注销自己。
3、Yarn 调度器和调度算法
Hadoop 作业调度器主要有三种:FIFO、容量(Capacity Scheduler)和公平(Fair Scheduler)。Apache Hadoop3.1.3 默认的资源调度器是容量调度器。
(1)先进先出调度器(FIFO)
单队列,根据提交作业的先后顺序,先来先服务。
- 优点:简单易懂;
- 缺点:
- 不支持多队列,生产环境很少使用
- 不适用于共享集群,大的应用可能会占用所有集群资源,这就导致其它应用被阻塞
(2)容量调度器(Capacity Scheduler)
容量调度器是 Yahoo 开发的多用户调度器。
允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。
队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
- 优点:
- 多队列:每个队列可配置一定的资源量,每个队列采用FIFO调度策略。
- 容量保证:管理员可为每个队列设置资源最低保证和资源使用上限
- 灵活性:如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用 程序提交,则其他队列借调的资源会归还给该队列。
- 多租户: 支持多用户共享集群和多应用程序同时运行。 为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占资源量进行限定。
- 缺点:
- 有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。
【分配算法】
- 队列资源分配:从root开始,使用深度优先算法,优先选择资源占用率最低的队列分配资源。
- 作业资源分配:默认按照提交作业的优先级和提交时间顺序分配资源。
- 容器资源分配:按照容器的优先级分配资源, 如果优先级相同,按照数据本地性原则:
- 任务和数据在同一节点
- 任务和数据在同一机架
- 任务和数据不在同一节点也不在同一机架
(3)公平调度器(Fair Scheduler)
公平调度器是 Facebook 开发的多用户调度器。
公平调度器设计目标是:在时间尺度上,所有作业获得公平的资源。某一 时刻一个作业应获资源和实际获取资源的差距叫“缺额”,调度器会优先为缺额大的作业分配资源
【与容量调度器相同点】
多队列、容量保证、灵活性、多租户
【与容量调度器不同点】
- 核心调度策略不同
- 容量调度器:优先选择资源利用率低的队列
- 公平调度器:优先选择对资源的缺额比例大的
- 每个队列可以单独设置资源分配方式
- 容量调度器:FIFO、 DRF
- 公平调度器:FIFO、FAIR、DRF
【队列资源分配方式】
- FIFO策略
- 公平调度器每个队列资源分配策略如果选择FIFO的话,此时公平调度器相当于上面的容量调度器。
- FAIR策略
- Fair 策略(默认)是一种基于最大最小公平算法实现的资源多路复用方式,
- 默认情况下,每个队列内部采用该方式分配资源。如果一个队列中有两个应用程序同时运行,则每个应用程序可得到1/2的资源;如果三个应用程序同时运行,则 每个应用程序可得到1/3的资源。
具体资源分配流程和容量调度器一致:
(1)选择队列
(2)选择作业
(3)选择容器
以上三步,每一步都是按照公平策略分配资源:
- 实际最小资源份额:mindshare = Min(资源需求量,配置的最小资源)
- 是否饥饿:isNeedy = 资源使用量 < mindshare(实际最小资源份额)
- 资源分配比:minShareRatio = 资源使用量 / Max(mindshare, 1)
- 资源使用权重比:useToWeightRatio = 资源使用量 / 权重
【分配案例】
- DRF策略
- DRF(Dominant Resource Fairness)是一种通用的多资源最大最小公平分配策略,我们通常的资源都是单一标准,例如只考虑内存(也是Yarn默认的情况)。但是很多时候我们资源有很多种,例如内存,CPU,网络带宽等,这样我们很难衡量两个应用应该分配的资源比例。
- 假设集群一共有100 CPU和10T 内存,而应用A需要(2 CPU, 300GB),应用B需要(6 CPU,100GB)。 则两个应用分别需要A(2%CPU, 3%内存)和B(6%CPU, 1%内存)的资源,这就意味着A是内存主导的, B是 CPU主导的,针对这种情况,我们可以选择DRF策略对不同应用进行不同资源(CPU和内存)的一个不同比例的限制。
4、Yarn 常用命令
- 查看任务:yarn application -list
- 查看日志:yarn logs -applicationId <ApplicationId>
- 查看尝试运行的任务:yarn applicationattempt -list <ApplicationId>
- 查看容器:yarn container -list <ApplicationAttemptId>
- 查看容器状态:yarn container -status <ApplicationAttemptId>
- 查看节点状态:yarn node -list -all
- 加载队列配置:yarn rmadmin -refreshQueues
- 查看队列:yarn queue -status <QueueName>
5、Yarn 的 Container 容器
Yarn 的 container 容器是 yarn 虚拟出来的一个东西,属于虚拟化的,它是由 memory + vcore 组成,是专门用来运行任务的。
vcore:指的是虚拟CPU,之所以产生虚拟CPU(CPU vCore)这一概念,是因为物理CPU的处理能力的差异,为平衡这种差异,就引入这一概念。
在 YARN 的 NodeManager 节点上,会将机器的CPU和内存的一定值抽离出来,抽离成虚拟的值,然后这些虚拟的值在根据配置组成多个Container,当application提出申请时,就会分配相应的Container资源。
生产调优
- NameNode 内存生产配置
- NameNode 内存默认 2000m,如果服务器内存 4G,NameNode 内存可以配置 3g
- NameNode 心跳并发配置
- NameNode 有一个工作线程池,用来处理不同 DataNode 的并发心跳以及客户端并发的元数据操作。 对于大集群或者有大量客户端的集群来说,通常需要增大该参数。默认值是 10
- 开启回收站配置
- 可以将删除的文件在不超时的情况下,恢复原数据,起到防止误删除、 备份等作用
- NameNode 多目录配置
- NameNode 的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性
- DataNode 多目录配置
- DataNode 可以配置成多个目录,每个目录存储的数据不一样(数据不是副本)
- 集群扩容及缩容
- 添加白名单和黑名单
- Hadoop 小文件优化
- 纠删码
- HDFS 默认情况下,一个文件有 3 个副本,这样提高了数据的可靠性,但也带来了 2 倍的冗余开销。Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约 50%左右的存储空间。
- 异构存储(冷热数据分离)
- 主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。
Hadoop HA 高可用
- 所谓 HA(High Available),即高可用(7*24 小时不中断服务)。
- 实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA。
1、HDFS HA
- NameNode
- 两台NameNode形成互备,一台处于Active状态,为主NameNode,另一台为Standby状态,为备NameNode,只有主NameNode才能对外提供读写服务;
- ZKFailoverController(主备切换控制,ZKFC)
- ZKFC作为独立的进程运行,负责监控NameNode的健康状况,在主NameNode故障时借助Zookeeper实现自动主备切换;
- Zookeeper
- ZKFC会在ZK上创建一个临时节点,创建成功的ZKFC会将对应NameNode的状态切换成Active;没有创建成功的ZKFC会监控这个节点的状态变化事件;
- 如果Active NameNode状态异常时,对应的ZKFC会主动删除在ZK上创建的临时节点,这样的话Standby NameNode节点的ZKFC会收到节点删除的事件,然后尝试去ZK上创建临时节点,若创建成功,就会将NameNode的状态从Standby切换为Active;
- JournalNode(共享存储系统)
- 共享存储系统保存了edits编辑日志,也就是在NameNode运行过程中产生的HDFS的元数据;主NameNode可以进行读写,备NameNode只能读;
- 主NameNode和备NameNode通过共享存储系统实现元数据同步,在进行主备切换时保证元数据不丢失;
- DataNode
- DataNode会同时向主NameNode和备NameNode上报数据块的位置信息,目的是方便快速进行主备切换;
(1)脑裂
主NameNode在垃圾回收时,可能会长时间内无响应,也就无法向zk写入心跳信息,可能就会导致zk的临时节点被删除,备NameNode会切换到Active状态,这种情况可能就会导致整个集群里有两个Active状态的NameNode,这就是脑裂问题。
- 脑裂问题的解决方案是隔离(Fencing),主要有三处隔离措施:
- 共享存储:任一时刻,只有一个NameNode可以写入;
- DataNode:需要保证只有一个NamaNode发出管理数据副本相关的命令;
- Client:需要保证同一时刻只有一个NameNode对Client请求进行响应;
- 解决方案的实现
- zkfc在zk上创建临时节点的时候,会在另外一个路径创建持久节点,这个节点保存了当前Active NameNode的地址信息;
- Active NameNode在正常状态下关闭时,会一起删除这个持久节点;但是在非正常状态下关闭时,这个持久节点会保留下来,后面新选举的Active NameNode会根据这个持久节点,找到原来的NameNode进行隔离操作;
- 首先尝试调用原来NameNode的RPC接口,看能否将它状态切换为Standby;
- 若调用失败,则会执行Hadoop配置文件中的预定义的隔离措施,一般有两种:
- SSH:通过SSH登录到目标机器上,执行命令将对应的进程杀死;
- Shell:执行一个用户自定义的shell脚本来将进程隔离;
- 只有成功执行完隔离操作后,新选举的NameNode才会将状态切换为Active状态,开始对外提供服务;
(2)联邦(Federation)
【基本介绍】
- 可以理解为有多个NameNode节点的HDFS集群;
- 这些NameNode相互独立,各自分工管理自己区域的元数据信息;
- 每个DadaNode要向集群中所有的NameNode注册,并执行来自所有NameNode的命令
- 核心思想是将一个大的namespace划分多个小namespace,每个namespace分别由单独的NameNode负责;
【优点】
- 提高存储量:NameNode把所有元数据存储在内存中,单个NameNode的内存空间是有限的;
- 提高吞吐量:整个hdfs的吞吐量受限于单个NameNode的吞吐量;
【缺点】
- 对应单个NameNode,仍然存在单点故障问题,当某个NameNode挂掉后,其管理的文件便不可用;
- 可以针对每个NameNode,配一个Secondary NameNode,用于方便还原元数据信息;
2、YARN HA
- ResourceManager
- 两台ResourceManager形成互备,一台处于Active状态,另一台为Standby状态;
- ZKFC
- ZKFC不是单独的进程,只作为RM进程的一个线程
- Zookeeper
- RM启动时会向zk的/rmstore目录写一个lock文件,写成功就为Active,否则为Standby;Standby的RM会一直监听锁文件
- 当ActiveRM挂掉时,对应的锁文件会被删除,这时其他的StandbyRM会尝试去创建锁文件,若创建成功,则转化为Active;
- RMStateStore(共享存储)
- RM的作业信息存储在zk的/rmstore目录下,相当于一个文件夹,RM会向这个目录写入job信息;
- 当ActiveRM挂了,后面新选举的ActiveRM,会从这个目录下读取作业job的信息,去保证高可靠;
- NodeManager
- 单个节点资源的管理,负责启动容器运行task任务,只会向ActiveRM汇报,不会向StandbyRM汇报;
(1)脑裂
当ActiveRM由于网络原因一段时间无法对外响应,发生“假死”,zk会删除对应的锁文件,这时其中一个StandbyRM会去重新创建一个锁文件,且状态转化为Active,这个时候就会造成多个ActiveRM的存在;
解决办法:使用ZK的ACL机制(访问控制)
- “假死“状态的ActiveRM恢复后,尝试去更新zk锁文件信息,由于现在的锁文件是由新的ActiveRM创建的,所以更新失败,则会将自身状态切换为Standby
(2)联邦
- 一个YARN集群看成一个子集群,多个YARN集群组合成一个大集群
- 应用可以跨子集群运行