Hadoop期末复习(完整版)
前言(全部为语雀导出,个人所写,仅用于学习!!!!)
复习之前我们要有目的性,明确考什么,不考什么。对于hadoop来说,首先理论方面是跑不掉的,而且还是重中之重。例如:hdfs的读写流程,hdfs副本机制等等。其次是hadoop命令,如果学习了hadoop不了解hadoop dfs …和hdfs dfs …那么你可以重修了。最后要明确那一部分会出什么题。
下面背景色或者字体改变的背过就完了。
一 初始Hadoop部分(了解)
这一章主要考点如下:1.大数据技术的5V特征是什么?(选择,简答)
容量(Volume):数据的大小决定所考虑的数据的价值和潜在的信息
种类(Variety):数据类型的多样性
速度(Velocity):指获得数据的速度
可变性(Variability):妨碍了处理和有效地管理数据的过程
真实性(Veracity):数据的质量
2.大数据包括特点是(选择,简答)
海量数据处理;多结构化数据;增长速度快;价值密度低。
3.Hadoop的创始人是谁?(选择)
Doug Cutting。
扩充:以下项目中,哪个不是由Doug Cutting所创立的()。
A、Hadoop B、Nutch C、Lucene D、Solr
4.Hadoop 的框架最核心的设计:HDFS(存储)和 MapReduce(计算)。或者问Hadoop核心三大组件是:HDFS 、MapReduce 和 YARN。(填空)
注意:两个就没YARN,三个就有。
5.Hadoop 物理架构:Master-Slave 架构。(选择、填空)
6.Hadoop 的优点? (简答)
高可靠性:Hadoop按位存储和处理数据的能力值得人们信赖。
高效性:Hadoop能够在节点之间动态地移动数据,并保证各个节点的动态平衡,因此处理速度非常快。
高扩展性:Hadoop是在可用的计算机集蔟间分配数据并完成计算任务的,这些集蔟可以方便地扩展到数以千计的节点。
高容错性:Hadoop能够自动保存数据的多个副本,并且能够自动将失败的任务重新分配。
7.请列举几个Hadoop生态圈里的组件并简述其作用?(简答)最少记住四个标黄的
HDFS :分布式文件系统,用于存储大规模数据,具备高容错性。
MapReduce:编程模型和计算框架,用于批量处理大数据,分为 Map 和 Reduce 阶段。
YARN :资源管理和调度系统,负责集群资源的分配和任务调度。
Hive:数据仓库工具,使用类 SQL 查询语言进行数据分析和处理。
HBase:分布式 NoSQL 数据库,支持实时随机数据访问。
Spark:快速的计算引擎,支持批处理和流式处理,更高效于 MapReduce。
ZooKeeper:集群协调服务,处理分布式应用程序的同步和状态管理。
二 Hadoop3.x 环境搭建(附实验考点)(重点)
1.目前,[ Hadoop](https://so.csdn.net/so/search?q=Hadoop&spm=1001.2101.3001.7020) 的最高版本是Hadoop3.x。(选择)2.Hadoop有三种运行模式,分别是:单机(本地)模式,伪分布式模式,全分布式模式。(选择)
运行模式 | 说明 | 使用场景 | 配置要求 |
---|---|---|---|
单机模式(Local Mode) | 所有Hadoop组件在单个进程中运行,没有启动守护进程。 | 开发和测试小规模的Hadoop应用,快速验证程序逻辑。 | 配置简单,不需要复杂的集群设置。 |
伪分布式模式(Pseudo-Distributed Mode) | 模拟分布式环境,Hadoop守护进程(如NameNode、DataNode等)作为独立进程运行。 | 进行全面的测试,适合HDFS的文件输入输出操作和内存检查。 | 需配置Hadoop的配置文件(如core-site.xml、hdfs-site.xml)以模拟多节点环境。 |
全分布式模式(Fully-Distributed Mode) | 在多台机器上运行,每台机器作为独立节点,运行不同的Hadoop守护进程。 | 生产环境和大规模数据处理,充分利用集群资源。 | 配置每台机器,包括网络设置、SSH无密码登录等。 |
补充:关于Hadoop单机模式和伪分布式模式的说法,正确的是(D)
A. 两者都起守护进程,且守护进程运行在一台机器上
B. 单机模式不使用HDFS,但加载守护进程
C. 两者都不与守护进程交互,避免复杂性
D. 后者比前者增加了HDFS输入输出以及可检查内存使用情况
以下哪一项不属于 Hadoop 可以运行的模式(C)。
A、单机(本地)模式 B、伪分布式模式
C、互联网模式 D、全分布式模式
3.Hadoop集群配置文件及其作用。(选择)这几个都要背过必考类型
配置文件 | 修改内容 | 可修改参数 |
---|---|---|
hadoop-env.sh | 配置 JDK 环境变量 | <font style="background-color:#FBDE28;">JAVA_HOME</font> |
core-site.xml | 配置 HDFS 地址和临时文件目录 | <font style="background-color:#FBDE28;">fs.defaultFS</font> , hadoop.tmp.dir |
hdfs-site.xml | 配置 HDFS 上的 NameNode 和 DataNode 设置 | dfs.replication , dfs.namenode.name.dir , dfs.datanode.data.dir |
mapred-site.xml | 指定 MapReduce运行时框架 | mapreduce.framework.name |
yarn-site.xml | 配置 ResourceManager 和 NodeManager | yarn.resourcemanager.address , yarn.nodemanager.aux-services |
slaves | 记录所有从节点的主机名 | 列出每个从节点的主机名 |
补充例:
在配置Hadoop时,经常会在下面哪一个文件中配置JAVA_HOME(c)。
A、hadoop-default.xml B、hadoop-site.xml
C、hadoop-env.sh D、configuration.xsl
HDFS默认的当前工作目录是/user/$USER,fs.default.name的值需要在哪个配置文件内说明。(B)**
A. mapred-site.xml B. core-site.xml
C. hdfs-site.xml **D. 以上均不是
4.搭建环境时比较重要命令。(选择,填空,简答)
(1 让新的linux环境变量生效:source /etc/profile
(2 进行初始化命令:hdfs namenode -format
(3 单节点逐个启动:
在主节点上启动HDFS namenode进程:hadoop-daemon.sh start namenode
在从节点上使用指令启动 HDFS DataNode进程 :hadoop-daemon.sh start DataNode
在主节点上使用指令启动Yarn RecourseManager进程:yarn-daemon.sh start recoursemanager
在每个节点上从节点上使用指令启动Yarn nodemanager进程:yarn-daemon.sh start nodemanager
在规划节点Hadoop02使用指令启动SecondaryNameNode:hadoop-daemon.sh start secondarynamenode
(4 脚本一键启动和关闭全部守护进程
在主节点Hadoop上使用指令启动所有HDFS服务进程:start-dfs.sh
在主节点Hadoop01上使用指令启动所有Yarn服务进程:start-yarn.sh
将以上指令start改为stop就为关闭服务命令
(5 查看master上启动的5个NameNode、DataNode、SecondaryNameNode、NodeManager、ResourceManager守护进程:jps
注:这里只有搭建环境部分,剩余内容再第六,第七章。
补充例:Hadoop集群单独启动NameNode进程的命令是(c)。
A、./start-namenode.sh
B、./start-all.sh start namenode
C、./hadoop-daemon.sh start namenode
D、./hadoop-daemons.sh start namenode
三 认识HDFS分布式文件系统(核心)
1.HDFS是分布式文件系统,根据Google发表的论文 GFS建立起来的。(选择,填空)补充例:下面与HDFS类似的框架是(B)。
A、EXT3 B、GFS C、NTFS D、FAT32
2.HDFS的优势:(简答)
(1 大数据处理:HDFS 默认会将文件分割成 Block,以 128MB (默认)为 1 个 Block,然后按键值对存储在 HDFS 上,并将键值对的映射存储到内存中。如果小文件太多,那么内存负担会很重。
(2 流式数据访问:一次写入,多次读取是最高效的访问模式。因此,读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。
(3 商⽤硬件:Hadoop 被设计运行在商⽤硬件的集群上,并通过保存多个副本的形式提供冗余的容错机制,且副本丢失或宕机会自动恢复。默认保存的副本数为 3 个。
补充:例下列选项中,Hadoop集群的主要瓶颈是(B)。
A、CPU B、磁盘IO C、网络 D、内存
3.HDFS的局限性:(简答)
(1)不能进行低时间延迟的数据访问:HDFS是为高数据吞吐量应用优化的,以提高时间延迟为代价。<font style="background-color:#F9EFCD;">HDFS要求低时间延迟数据访问的应用不适合在HDFS上运行。</font>(2)不能存储大量的小文件:由于NameNode将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件总数受限于NameNode的内存容量。每个文件、目录和数据块的存储信息大约占150个字节。因此,举例来说,如果有一百万个文件,且每个文件占一个数据块,那至少需要300MB的内存。但是如果存储数据十亿的文件就超出了当前硬件的能力。<font style="background-color:#F9EFCD;">所以存储文件时尽量将小文件合并成较大的文件。</font>(3)不支持并发写入、文件随机修改:一个文件只能有一个写,不允许多个线程同时写;仅支持数据append(追加),不支持文件的随机修改,这种限制使得<font style="background-color:#F9EFCD;">HDFS不适合需要频繁修改文件内容的应用。</font>
补充:
(1 请例举出不适用HDFS的场景。
低延迟数据访问需求;大量小文件存储;需要高并发写入;需要随机修改文件内容。
(2 HDFS无法高效存储大量小文件,想让它能处理好小文件,比较可行的改进策略不包括(D)
A. 利用SequenceFile、MapFile、Har等方式归档小文件。
B. 多Master设计。
C. Block大小适当调小。
D. 调大namenode内存或将文件系统元数据存到硬盘里。
4.HDFS的特性:(了解有印象即可,不大好出题,可能会简答,但是过于简单,最好记下几条)
高度容错,可扩展性及可配置性强。
跨平台。使用Java语言开发,以JVM为运行环境,支持多个主流平台的环境。
Shell命令接口。HDFS拥有一套文件系统操作的Shell命令,可以用来直接操作HDFS文件系统。Web管理平台。NameNode和DataNode内置有Web服务器,方便用户检查集群的当前运行状态。文件权限管理。Hadoop分布式文件系统实现了一个和POSIX系统类似的文件和目录的权限模型。每个文件和目录有一个所有者(owner)和一个组(group)。文件或目录对其所有者、同组的其他用户以及所有其他用户分别有不同的权限。机架感知功能。机架感知功能使得Hadoop在任务调度和分配存储空间时系统会考虑节点的物理位置,从而实现高效的访问和计算。安全模式。安全模式是Hadoop的一种保护机制,用于保证集群中的数据块的安全性。集群维护时进入这种管理模式。当集群启动时会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。Rebalancer功能。当DataNode之间数据不均衡时,可以平衡集群上的数据负载,实现数据负载均衡。允许升级和回滚。在软件更新后有异常情况发生时,HDFS允许系统回滚到更新或升级之前的状态。
5.HDFS的设计目标:(了解有印象即可,不大好出题,可能会简答,但是过于简单,最好记下几条)
检测和快速恢复硬件故障:硬件错误是常态而不是异常。因此错误检测和快速、自动的恢复是HDFS最核心的架构目标。流式数据访问:运行在HDFS上的应用和普通的应用不同,需要流式访问它们的数据集。比之数据访问的低延迟问题,更关键的在于数据访问的高吞吐量。大规模数据集:运行在HDFS上的应用具有很大的数据集。因此,HDFS被调节以支持大文件存储。简化一致的模型:“一次写入多次读取”的文件访问模型。一个文件经过创建、写入和关闭之后就不需要改变。这一假设简化了数据一致性问题,并且使高吞吐量的数据访问成为可能。移动计算的代价比移动数据的代价低:一个应用请求的计算,离它操作的数据越近就越高效,在数据达到海量级别的时候更是如此。因为这样就能降低网络阻塞的影响,提高系统数据的吞吐量。在不同的软硬件平台间的可移植性:HDFS在设计的时候就考虑到平台的可移植性。这种特性方便了HDFS作为大规模数据应用平台的推广。健壮性:在出错时也要保证数据存储的可靠性。标准的通信协议:所有的HDFS通讯协议都是建立在TCP/IP协议之上。客户端通过一个可配置的TCP端口连接到Namenode,通过ClientProtocol协议与Namenode交互。
6.HDFS核心概念:(超级重点必考全部要背过,选择,填空,简答都会考)
(1 数据块:
默认为 128MB(Hadoop 2.X);
可根据实际需求进行配置,配置 hdfs-site.xml 文件中的 dfs.block.size 属性;
HDFS上的文件划分为数据块,作为独立的存储单元,数据块是HDFS文件系统存储处理数据的最小单元;
储存模式方式看下面你就明白了,200MB文件储存,200/128=1个快+72MB,一共占用俩块,这里需要注意的是HDFS中小于一个块大小的文件并不会占据整个块的空间,可以继续用于储存其他文件。
核心问题1:为什么HDFS的数据块如此之大?(理解版:核心问题是效率,总时间=寻址时间+传输时间,寻址时间远大于传输时间,因此hdfs数据块大。)
HDFS的数据块比磁盘块大,以最小化寻址开销。如果块足够大,从磁盘传输数据的时间将显著大于定位块起始位置的时间。因此,传输一个由多个块组成的文件的时间主要取决于磁盘传输速率。然而,块大小也不能过大,否则任务数可能少于集群节点数量,从而影响作业运行速度。
例如:要传输100MB的数据,假设寻址时间为10ms,而传输的速率为100MB/s:如果我们将块大小设置为100MB,这时寻址的时间仅占传输时间的1%;如果将块的大小设置为10MB,这时寻址的时间会占传输时间的10%。所以在允许的范围内,增加块的大小,可以有效缩短数据传输的时间。
核心问题2: 对分布式文件系统中的块进行抽象会带来什么好处。
1.一个文件的大小可以大于集群中任意一个磁盘的容量
2.简化存储子空间
3.块还非常适合⽤于数据备份,提供数据冗余,进而提高数据容错能力和提高可 ⽤性
补充例:
Hadoop2.0中HDFS 默认 Block Size(C)。
A. 32MB B. 64MB C. 128MB D. 256MB
一个gzip文件大小75MB,客户端设置Block大小为64MB,请问其占用几个Block?(B)
A、3 B、2 C、4 D、1
如果一个Hadoop集群中HDFS的默认大小是128MB,本地磁盘有个HDFS上的目录包含100个纯文本文件,每个文件200MB。如果使用TextInputFormat作为输入格式类,将该目录作为作业输入,将会启动(C)个Map。
A. 64 B. 100 C. 200 D. 640
一个文件大小156MB,在Hadoop2.0中默认情况下请问其占用几个Block(B)?
A. 1 B. 2 C. 3 D. 4
(2 数据复制:
HDFS存储大数据,文件分成等大小块(除最后一个),块默认复制多次以保证数据冗余。块大小和复制次数可配置,文件只能写一次,且同时只能有一个写入者。
理解例子:
文件/users/sameerp/data/part-0的Replication因子值是2,Block的ID列表包括了1和3,可以看到块1和块3分别被冗余复制了两份数据块。
文件/users/sameerp/data/part-1的Replication因子值是3,Block的ID列表包括了2、4和5,可以看到块2、块4和块5分别被冗余复制了三份数据块。
(3 数据副本的存放策略:
HDFS默认的副本复制因子是3。
修改副本存放策略。
方法1:修改配置文件hdfs-site.xml。(需要重启HDFS系统才能生效)
<property><name>dfs.replication</name><value>1</value>
</property>
默认dfs.replication的值为3,通过这种方法虽然更改了配置文件,但是参数只在文件被写入dfs时起作用,不会改变之前写入的文件的备份数。
方法2:通过命令更改备份数。(不需要重启HDFS系统即可生效)
# bin/hadoop fs -setrep -R 1 /
理解例子:(最好背过)
第一个Block副本放在client所在机架的node里(如果client不在集群范围内,则存放这第一个Block副本的node是随机选取的,当然系统会尝试不选择哪些太满或者太忙的node)。
第二个Block副本放置在与第一个Block副本不同机架的node中(随机选择)。第三个Block副本和第二个Block副本在同一个机架,随机放在不同的node中。
(4 机架感知
NameNode管理HDFS文件块的复制。基本的副本放置策略是将副本分布在不同机架,以提高系统的可靠性,但这会增加写副本的成本,因为需要跨机架或数据中心传输数据。机架感知的策略在保证副本分布在不同机架的可靠性的同时,优化了带宽使用,通常只需在一个机架内传输数据。
默认Hadoop机架感知是没有启用的,需要在NameNode机器的<font style="color:#70000D;">core-site.xml</font>里配置。
在没有机架信息的情况下,NameNode默认将所有的slaves机器全部默认为在/default-rack下,此时写Block时,所有DataNode机器的选择完全是随机的。
当Hadoop配置了机架感知信息后,数据副本的存放策略如下:
- 第一个副本放在上传文件的DataNode(如果该DataNode是上传机器),或者随机选择一个DataNode。
- 第二个副本放在与第一个副本不同机架的随机DataNode上。
- 第三个副本放在第二个副本所在机架的某个DataNode上,如果前两个副本不在同一机架,则可能放在任一机架上。
- NameNode会根据客户端与DataNode之间的“距离”对DataNode列表排序。
- 客户端(DFSClient)根据排序后的列表,从最近的DataNode开始写入数据。
- 依次写入后续的DataNode,直到所有副本都写入成功。
示例:
关于数据副本的存放策略正确的有些?(ABCD)
A、第三个副本:与第一个副本相同机架的其他节点上;
B、更多副本:随机节点。
C、第一个副本,放置在上传文件的数据节点;
D、第二个副本,放置在与第一个副本不同的机架的节点上;
(5 安全模式 (只列考点
作用:保护集群数据的完整性.
启动方式:NameNode在启动时会自动进入安全模式(SafeMode),也可以手动进入。
进入后,检查数据完整性(数据块的副本数量是否满足配置的最小副本比率)。
在hdfs-default.xml文件中,通过dfs.safemode.threshold.pct属性设置最小副本比率阈值。
当系统处于安全模式时,不接受任何对名称空间的修改,也不会对数据块进行复制或删除,但是可以浏览目录结构、查看文件内容等操作。在安全模式下尝试进行禁止的操作时,会抛出SafeModeException
。
hadoop dfsadmin -safemode leave //强制退出安全模式
hadoop dfsadmin -safemode enter //进入安全模式
hadoop dfsadmin -safemode get //查看安全模式状态
hadoop dfsadmin -safemode wait //等待,一直到安全模式结束
补充例:NameNode在启动时自动进入安全模式,在安全模式阶段,说法错误的是(D)
A. 安全模式目的是在系统启动时检查各个DataNode上数据块的有效性。
B. 根据策略对数据块进行必要的复制或删除。
C. 当数据块最小百分比数满足最小副本数条件时,会自动退出安全模式。
D. 文件系统允许有修改。
(6 负载均衡 (考的几率不大)
重新均衡DataNode上的数据分布命令:
$ HADOOP_HOME/bin/start-balancer.sh -t 10%
在这个命令中,-t 参数后面跟的是 HDFS 达到平衡状态的磁盘使⽤率偏差值。如果机器与机器之间磁盘使⽤率偏差小于 10%,那么我们就认为 HDFS 集群已经达到了平衡状态。
具体过程:
① 数据均衡服务( Rebalancing Server) 首先要求 NameNode 生成 DataNode 数据分布分析报告, 获取每个 DataNode磁盘使用情况。
② 数据均衡服务汇总需要移动的数据块分布情况,计算具体数据块迁移路线图, 确保为网络内的最短路径。③ 开始数据块迁移任务, Proxy Source DataNode(代理源数据节点)复制一块需要移动的数据块。④ 将复制的数据块复制到目标 DataNode节点上。⑤ 删除原始数据块及在 NameNode 上存储的元信息, 并将新的元信息更新到 NameNode上。⑥目标 DataNode 向 Proxy Source DataNode 确认该数据块迁移完成。⑦ Proxy Source DataNode 向数据均衡服务确认本次数据块迁移完成, 然后继续执行这个过程, 直至集群达到数据均衡标准。
(7 心跳机制 (考的几率不大)
Hadoop 集群节点之间的通信是通过心跳机制实现的。所谓“心跳”是指的持续的按照一定频率在运行,执行请求和响应。当长时间没有发送心跳时,NameNode 就判断 DataNode 的连接已经中断,不能继续工作了,就被定性为”dead node”。NameNode 会检查"dead node"中的副本数据,复制到其他的 DataNode 中。
Hadoop 的心跳机制的具体实现思路是:
(1) 当 master 节点启动时,会开一个 rpc server,等待 slave 的心跳连接。
(2) slave 节点启动时,会连接到 master,并开始每隔 3 秒钟主动向 master 发送一个“心跳”,这个时间间隔可以通过 heartbeat.recheck.interval 属性来设置。
(3) slave 通过“心跳”将自己的状态告诉 master,master 返回“心跳”值,向 slave 节点传达指令。
(4) Hadoop 集群中各个进程之间的通信,都是通过“心跳”这种 RPC 通信来完成的。
(5) 当 NameNode 长时间没有接收到 DataNode 发送的“心跳”时,NameNode 就判断DataNode 的连接已经中断,就被定性为”dead node”。NameNode 会检查 dead node中的副本数据,复制到其他的 DataNode 中。
7.HDFS体系结构(选择,填空,简答) (这里无论如何都要背过,不然后面无法学)
(1 单NameNode节点集群架构:
单NameNode节点的HDFS集群是由一个NameNode和一定数目的DataNode组成。
NameNode是一个中心服务器,负责管理文件系统的命名空间和客户端对文件的访问。
NameNode执行文件系统的命名空间操作,例如打开、关闭、重命名文件和目录,同时决定Block到DataNode节点的映射。
DataNode负责处理文件系统的读写请求,在NameNode的指挥下进行Block的创建、删除等。
一个文件被分成一个或多个Block,这些Block存储在DataNode集合里。
(2 一个典型的 HDFS 集群通常由 NameNode、SecondaryNameNode 和 DataNode 三个节点组 成,其实就是运行在这些节点服务器上的进程。
节点名 | 主要功能 | 容错机制 |
---|---|---|
NameNode(命名节点) (一个集群通常只有一个活动的NameNode节点) (决定是否将文件映射到DataNode的副本上) | 1. 提供名称查询服务,是一个 Jetty服务器。 2. 保存元数据信息,包括文件的所有者和权限、文件包含的块和块在 DataNode 的位置(通过“心跳”机制上报)。 3. 启动时加载元数据信息到内存。 | 1. 使用 SecondaryNameNode 恢复 NameNode。 2. 利用 NameNode 的高可用(HA)机制,包括自动故障转移和多个NameNode的配置。 |
SecondaryNameNode | 1. 定期将 Edits 文件中的操作合并到 FsImage 文件中,并清空 Edits 文件。 2. NameNode 重启时加载最新的 FsImage 文件,并重新创建 Edits 文件,记录自上次 FsImage以来的操作。此机制减少了重启时间并确保 HDFS 系统完整性。 | |
DataNode(数据节点) (负责数据存储计算) | 1. 保存数据块,每个块对应一个元数据信息文件,描述该块属于哪个文件及其序号。 2. 启动时向 NameNode 汇报块信息。 3. 通过发送心跳保持与 NameNode 的联系;若 NameNode 10 分钟未收到心跳,则认为该 DataNode 已失效,并将块信息复制到其他 DataNode,以保证副本数量。 | 数据块副本在多个 DataNode 上存储,提供数据冗余。如果一个 DataNode 失效,其他 DataNode 上的副本可以被用来恢复数据。 |
补充例:
1)HDFS 的 NameNode 负责管理文件系统的命名空间,将所有的文件和文件夹的元数据 保存在一个文件系统树中,这些信息也会在硬盘上保存成以下文件(C)
A.日志 B.命名空间镜像 C.两者都是
2)下面哪个节点负责 HDFS 的数据存储(C)。
A、NameNode B、ResourceManager
C、DataNode D、SecondaryNameNode
3)HDFS 的 NameNode 负责管理文件系统的命名空间,将所有的文件和文件夹的元数据 保存在一个文件系统树中,这些信息也会在硬盘上保存成以下文件(C)
A.日志 B.命名空间镜像 C.两者都是
4)在Hadoop中,下列哪个进程通常与NameNode在同一节点上启动(B)。
A、SecondaryNameNode B、Jobtracker
C、DataNode D、TaskTracker
5)在Hadoop中,集群会启动哪些进程,他们的作用分别是什么?
NameNode:这是Hadoop的主节点,负责管理HDFS(Hadoop分布式文件系统)的元数据,包括文件系统的目录结构、文件到数据块的映射以及数据块的位置等。NameNode不存储数据块的实际内容。
DataNode:这些是HDFS的工作节点,负责存储实际的数据块。DataNode周期性地向NameNode发送心跳信号和数据块报告,以确保它们的健康状态和数据的一致性。
ResourceManager:这是YARN(Yet Another Resource Negotiator)的主节点,负责全局资源管理与调度。它管理集群资源并协调各个应用程序的运行。
NodeManager:这是YARN的工作节点,负责具体的资源管理,会在本地节点上监控容器(Containers)的资源使用情况。NodeManager也负责启动和管理应用程序的容器。
Secondary NameNode:虽然这个进程的名字包含“NameNode”,但它并不是一个备份的NameNode。它的主要作用是定期合并NameNode的元数据(fsimage和edits文件),以减少NameNode的内存使用和提高容错能力。
四 HDFS运行机制(核心)
1.RPC远程过程调用协议:(选择,填空,简答)TCP/IP 协议(目前网上聊天⽤)或 UDP(客户端可靠协议但是信息传输效率不高)。
在OSI网络通信模型中,RPC跨域了传输层和应用层。
(1 一个完整的RPC架构里面包含了四个核心的组件:(相对不是那么重要)
1.客户端(Client):服务的调用方。2.客户端存根(Client Stub):存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。3.服务端(Server):真正的服务提供者。4.服务端存根(Server Stub):接收客户端发送过来的消息,将消息解包,并调用本地的方法。
(2 Hadoop的RPC机制(分为四部分):(必须背过)
序列化层:Client与Server端通信传递的信息采用Hadoop提供的序列化类或自定义的Writable类型。
函数调用层:Hadoop RPC通过动态代理以及Java反射实现函数调用。
网络传输层:Hadoop RPC采用了基于TCP/IP的Socket机制。
服务器端框架层:RPC Server利用Java NIO以及事件驱动的I/O模型,提高RPC Server并发处理能力。
补充例:
Hadoop的RPC机制同其他RPC框架一样,可分为四个部分,请简述这四层的名称及各自的实现机制。
答案就是上方。
Hadoop RPC的实现模型主要特点有透明性、高性能和可控性。通过动态代理、反射——动态加载类、序列化、非阻塞的异步IO(NIO)实现。
Hadoop的RPC总体架构:Hadoop RPC = 动态代理 + 定制的二进制流。
(再细9.9成不会考,但是就怕万一,想再细了解看:博客)
2.HDFS文件写入(超级重要,简体题必考,所有图都要背过!!!!)
(1 HDFS读取文件流程
① 使用HDFS 提供的 Client, 向远程的NameNode 发起 RPC 读文件请求。
② NameNode 会视情况返回文件的部分或者全部数据块列表, 对于每个数据块, NameNode都会返回有该数据块副本的 DataNode 地址。
③Client会选取最近的DataNode来读取数据块; 如果 Client本身就是 DataNode, 那么将从本地直接获取数据。
④读取完当前数据块后, 关闭当前的 DataNode 连接, 并为读取下一个数据块寻找最佳的DataNode。
⑤当读完数据块列表后, 且文件读取还没有结束, Client会继续向NameNode 获取下一批数据块列表。
⑥每读取完一个数据块, 都会进行校验和验证, 如果读取 DataNode 时出现错误, Client会通知NameNode, 然后再从下一个拥有该数据块副本的DataNode 继续读取。
(2 写入示例
将64M的block1数据块按64k的package为单位划分。
然后client将第一个package发送给Rack1机架上的host2结点。
当host2结点接收完成后,将第一个package发送给Rack2机架上的host1与此同时client向host2发送第二个package。
当host1结点接收完成后,将第一个package发送给Rack2机架上的host3,与此同时host2向host1发送第二个pabckage。
以此类推,直到将block1全部发送完成。
当block1全部发送完成后,host2,host1,host3向NameNode节点发送通知,NameNode记录并将消息发送给host2,host2再向client发送消息通知client数据块block1已经发送完成,NameNode需要等待client确认。
client收到host2发送的消息后,向NameNode发送确认消息,至此,block1才真正完成了写入的过程。
数据块block1发送完成后,再向host7,host8,host4发送block2,发送的过程与block1相似,直到全部数据块发送完成。
(3 使用HDFS API写文件:
public class FileSystemCat {public static void main(String[] args) throws Exception {String localPath = args[0];String dfsPath = args[1];InputStream in = null;OutputStream out = null;Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(dfsPath), conf);try {in = new BufferedInputStream(new FileInputStream(localPath));out = fs.create(new Path(dfsPath), new Progressable() {@Overridepublic void progress() {System.out.print(" . ");}});IOUtils.copyBytes(in, out, 4096, false);} catch (Exception e) {IOUtils.closeStream(in);IOUtils.closeStream(out);}}
}
(4 使用HDFS API读取文件:
public class FileSystemCat {public static void main(String[] args) throws Exception {String uri = "hdfs://10.10.155.110:9000/output/wordcount/part-r-00000";Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(uri), conf);InputStream in = null;try {in = fs.open(new Path(uri));IOUtils.copyBytes(in, System.out, 4096, false);} catch (Exception e) {e.printStackTrace();IOUtils.closeStream(in);}}
}
补充例:
1)假设当前环境有NameNode节点1个、DataNode节点3个、Client Node节点1个,请画出HDFS文件写入的流程图。
2)下面代码片段为使用HDFS API写文件的过程,请补全代码的空白处。
public class FileSystemCat {public static void main(String[] args) throws Exception {String localPath = args[0];String dfsPath=args[1];InputStream in = null;OutputStream out=null;__________(1)__________ ;FileSystem fs = ________(2) ________(URI.create(dfsPath), conf);try {in = new BufferedInputStream(________(3) ________);out=fs.create(new Path(dfsPath),new Progressable() {@Overridepublic void progress() {// 反馈写入进度 System.out.print(" . ");}});IOUtils. ________(4) ________;} catch (Exception e) {e.printStackTrace();IOUtils.closeStream(in);IOUtils.closeStream(out);}}
}
就是上方代码
3.HDFS文件的一致模型:(考的概率不大)
所解决的问题:写入HDFS的文件内容对其他读者可能不是立即可见的,即使数据已存储,文件长度可能仍显示为0。跨块数据写入时,只有完全写入并同步的数据块对新读者可见,正在写入的块不可见。
解决方案:要在HDFS中确保数据可见性,可以调用<font style="color:rgb(6, 6, 7);">sync()</font>
方法强制数据节点同步缓存数据。关闭文件时会自动执行<font style="color:rgb(6, 6, 7);">sync()</font>
。不调用<font style="color:rgb(6, 6, 7);">sync()</font>
可能导致数据丢失。需要根据应用需求平衡数据一致性和性能,合理调用<font style="color:rgb(6, 6, 7);">sync()</font>
。例如,写入一定数据后调用<font style="color:rgb(6, 6, 7);">sync()</font>
。创建文件后,需调用<font style="color:rgb(6, 6, 7);">hsync()</font>
或<font style="color:rgb(6, 6, 7);">close()</font>
才能读取文件信息。
示例:当创建一个文件后,立即读取文件信息,此时文件信息是不存在的。只有当调用hsync()方法或调用了close()方法后,才能立即读取到文件信息。
Path p=new Path("/home/temp/a.txt");
FSDataOutputStream out=fs.create(p);
out.write("content".getBytes("UTF-8"));
out.hflush();
out.hsync();
assertThat(fs.getFileStatus(p).getLen(),is(((long)"content".len
gth())));
Path p=new Path("/home/temp/a.txt");
fs.create(p);
assertThat(fs.exists(p),is(true));
Path p=new Path("/home/temp/a.txt");
OutputStream out=fs.create(p);
out.write("content".getBytes("UTF-8"));
out.close();
assertThat(fs.getFileStatus(p).getLen(),is(((long)"content".len
gth())));
- HDFS的HA机制(简答)
HDFS 的 HA 机制 7*24h 运行
在 Hadoop 2.x 及以后版本中,新增了对高可靠性(HA)的支持,实现方式是:配置了一对“活动-备⽤”(active - standby)NameNode。当活动的 NameNode 失效时,备⽤的NameNode 就会接管它的任务并开始服务于来自客户端的请求,而不必中断整个服务。
HDFS NameNode的高可用整体架构主要由以下几个关键组成部分构成:
Active NN 和 Standby NN:主/备 NN,只有主 NN 才能对外提供读写服务。
主备切换控制器 ZKFailoverController:作为独立进程运行,对 NN 的主备切换进行总体控制。
ZooKeeper 集群:为主备切换控制器提供主备选举支持。
共享存储系统:主备 NN 通过共享存储系统实现元数据同步。
DN 节点:DN 会同时向主 NN 和备 NN 上报数据块的位置信息。
(5 NameNode 的主备切换实现:(了解即可)
补充例:下面关于Hadoop HA机制描述错误的是(D)。
A、通常由两个NameNode组成,一个处于active状态,另一个处于standby状态
B、Active NameNode对外提供服务,而Standby NameNode则不对外提供服务,仅同步Active NameNode的状态
C、需要配合Zookeeper才能实现HA
D、在NameNode节点失败时,可以快速手动进行切换
6 Federation机制(最好背过,考的概率也不大)
(1 优点:
扩展性和隔离性:支持多个NameNode水平扩展整个文件系统的namespace。可按照应用程序的用户和种类分离namespace volume,进而增强了隔离性。
通用存储服务:Block Pool抽象层为HDFS的架构开启了创新之门。分离block storage layer使得:
新的文件系统(non-HDFS)可以在block storage上构建
新的应用程序(如HBase)可以直接使用block storage层
分离的block storage层为将来完全分布式namespace打下基础
设计简单:Federation 整个核心设计的大部分改变是在DataNode、Config和Tools中,而NameNode本身的改动非常少,这样NameNode原先的健壮性不会受到影响。可以迅速满足需求,另外Federation具有良好的向后兼容性,已有的单NameNode的部署配置不需要任何改变就可以继续工作。、
(2 不足:
单点故障问题:HDFS Federation并没有完全解决单点故障问题。如果某个NameNode挂掉了,其管理的相应的文件便不可以访问。Federation中每个NameNode仍然像之前HDFS上实现一样,配有一个SecondaryNameNode,以便主NameNode挂掉一下,用于还原元数据信息。
负载均衡问题:HDFS Federation采用Client Side Mount Table分摊文件和负载,该方法需要人工介入以达到理想的负载均衡。
五 访问HDFS文件系统(核心)
1.HDFS命令行接口:(选择,填空,简答)又一超级重点hadoop fs … / hadoop dfs …
hdfs dfs …(两种皆可)
下面是常用命令:(黄色背景的一定要记住)
<font style="background-color:#FBDE28;">hadoop dfs -ls <path></font> | 列出指定路径的文件或目录内容 |
---|---|
hadoop dfs -lsr <path> | 递归地列出指定路径的目录内容 |
hadoop dfs -df <path> | 查看指定路径的目录使用情况 |
hadoop dfs -du <path> | 显示指定目录中所有文件及子目录的大小 |
<font style="background-color:#FBDE28;">hadoop dfs -count [-q] <path></font> | 显示指定目录下的目录数及文件数,添加<font style="background-color:#FBDE28;">-q</font> 可查看文件索引情况 |
<font style="background-color:#FBDE28;">hadoop dfs -mv <src> <dst></font> | 将HDFS上的文件移动到目标文件夹 |
<font style="background-color:#FBDE28;">hadoop dfs -rm [-skipTrash] <path></font> | 删除HDFS上的文件,移动到回收站;<font style="background-color:#FBDE28;">-skipTrash</font> 则直接删除 |
hadoop dfs -rmr [-skipTrash] <path> | 删除HDFS上的目录及其下文件,移动到回收站;-skipTrash 则直接删除 |
hadoop dfs -expunge | 清空HDFS回收站 |
<font style="background-color:#FBDE28;">hadoop dfs -put <localsrc> <dst></font> | 将本地文件上传到HDFS的指定目录 |
<font style="background-color:#FBDE28;">hadoop dfs -get [-ignoreCrc] [-crc] <src> <localdst></font> | 将HDFS文件下载到本地,<font style="background-color:#FBDE28;">-ignoreCrc</font> 复制CRC检验失败的文件, <font style="background-color:#FBDE28;">-crc</font> 复制CRC信息 |
hadoop dfs -copyToLocal [-ignoreCrc] [-crc] <src> <localdst> | 功能类似于get |
hadoop dfs -moveToLocal [-crc] <src> <localdst> | 将HDFS文件移动到本地目录,-crc 移动文件及CRC信息 |
<font style="background-color:#FBDE28;">hadoop dfs -mkdir <path></font> | 在HDFS上创建目录 |
hadoop dfs -touchz <path> | 在HDFS上创建一个0字节的空文件 |
hadoop dfs -text <path> | 输出HDFS上指定文本文件的内容 |
<font style="background-color:#FBDE28;">hadoop dfs -cat <path></font> | 浏览HDFS上指定文件的内容 |
hadoop dfs -setrep [-R] [-w] <rep> <path> | 设置文件的复制因子,-R 表示递归 |
hadoop dfs -test -[ezd] <path> | 检查HDFS上的文件:-e 检查文件是否存在, -z 检查文件是否0字节, -d 检查是否是目录 |
hadoop dfs -stat [format] <path> | 显示HDFS上文件或目录的统计信息 |
<font style="background-color:#FBDE28;">hadoop dfs -chmod [-R] <MODE> <path></font> | 改变HDFS上指定文件的权限,<font style="background-color:#FBDE28;">-R</font> 表示递归执行 |
hadoop dfs -chown [-R] [OWNER][:[GROUP]] <path> | 改变HDFS上指定文件的所属用户,-R 表示递归执行 |
hadoop dfs -chgrp [-R] GROUP <path> | 改变HDFS上指定文件的所属组别,-R 表示递归执行 |
<font style="background-color:#FBDE28;">hadoop dfs -help</font> | 显示所有<font style="background-color:#FBDE28;">dfs</font> 命令的帮助信息 |
hadoop dfs -copyFromLocal <localsrc> <dst> | 功能类似于put |
hadoop dfs -moveFromLocal <localsrc> <dst> | 将本地文件移动到HDFS指定目录 |
注意事项- hadoop
和hdfs
命令在功能上是相似的,但推荐使用hdfs dfs ...
命令,因为它专门用于HDFS,更加明确。
2.常用API:(简答,编程,红字必背)
(1 Hadoop有一个抽象的文件系统概念,HDFS只是其中的一个实现。类org.apache.hadoop.fs.FileSystem定义了Hadoop中的一个文件系统接口,并且该抽象类有几个具体实现。
文件系统 | URL方案 | Java 实现类 | 描述 |
---|---|---|---|
Local file | fs | fs.LocalFileSystem | 使用了客户端校验的本地磁盘文件系统。 |
HDFS | hdfs | hdfs.DistributedFileSystem | Hadoop 的分布式文件系统。 |
HFTP | hftp | hdfs.HftpFileSystem | 在 HTTP 上提供对 HDFS只读访问的文件系统。 |
HSFTP | hsftp | hdfs.HsftpFileSystem | 在 HTTPS 上提供对 HDFS只读访问的文件系统。 |
WebHDFS | Webhdfs | hdfs.web.WebHdfsFileSystem | 基于 HTTP 对 HDFS 提供安全读写访问的文件系统。 |
HAR | har | fs.HarFileSystem | 一个构建在其他文件系统之上用于文件存档的文件系统。 |
HFS (KFS) | kfs | fs.kfs.KosmosFileSystem | CloudStore 是类似于 HDFS 或 Google 的 GFS 的文件系统,用 C++ 编写。 |
FTP | ftp | fs.ftp.FTPFileSystem | 由 FTP服务器支持的文件系统。 |
S3(原生) | S3n | fs.s3native.NativeS3FileSystem | 由 Amazon S3 支持的文件系统。 |
(2 从Hadoop URL中读取数据:
例:以标准输出方式显示Hadoop文件系统中的文件。(类似于Unix中的cat命令)
public class URLCat {// 静态块:设置 URL 的流处理工厂,用于处理 HDFS URLstatic {// 将 Hadoop 的 FsUrlStreamHandlerFactory 绑定到 java.net.URLURL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());}public static void main(String[] args) throws Exception {InputStream in = null; // 定义输入流,用于读取数据try {// 打开 HDFS 上的文件,URL 是从命令行参数传入的in = new URL(args[0]).openStream();// 使用 IOUtils 工具类,将输入流内容复制到标准输出IOUtils.copyBytes(in, System.out, 4096, false);} finally {// 关闭输入流,防止内存泄漏IOUtils.closeStream(in);}}
}
编译上述代码,导出为URLCat.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/URLCat.jar com.hdfsclient.URLCat hdfs://master:9000/input/sample.txt
(3 通过FileSystem API读取数据:
虽然从Hadoop URL中读取数据是最简单的方式,但是有时可能无法在应用中设置URLStreamHandlerFactory实例,在实际开发中,访问HDFS最常用的方式还是使用FileSystem API来读取数据。
public class FileSystemCat {public static void main(String[] args) throws Exception {String uri = "hdfs://master:9000/input/sample.txt";Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(uri), conf);InputStream in = null;try {in = fs.open(new Path(uri));IOUtils.copyBytes(in, System.out, 4096, false);} finally {IOUtils.closeStream(in);}}
}
编译上述代码,导出为FileSystemCat.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/FileSystemCat.jar com.hdfsclient.FileSystemCat
(4 写入数据
FileSystem类创建文件的方法,常用的有两类:create()和append()方法。
例:将本地文件复制到HDFS文件系统。
public class FileCopyFromLocal {public static void main(String[] args) {String localSrc = "/home/hadoop/files/sample.txt";String dst = "hdfs://master:9000/input/hadoop/sample.txt";InputStream in = null;OutputStream out = null;try {in = new BufferedInputStream(new FileInputStream(localSrc));Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(dst), conf);out = fs.create(new Path(dst), new Progressable() {@Overridepublic void progress() {System.out.print(" . ");}});IOUtils.copyBytes(in, out, 4096, true);} catch (IOException e) {e.printStackTrace();} finally {IOUtils.closeStream(in);IOUtils.closeStream(out);}}
}
编译上述代码,导出为xxx.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/xxx.jarcom.hdfsclient.FileCopyFromLocal
(5 删除数据
使用FileSystem类的delete方法可以永久删除文件或目录。例:删除HDFS上的文件或目录。
public class DeleteFile {public static void main(String[] args) {String uri = "hdfs://master:9000/input/hadoop/sample.txt";Configuration conf = new Configuration();try {FileSystem fs = FileSystem.get(URI.create(uri), conf);Path delete = new Path(uri);boolean isDeleted = fs.delete(delete, false);// 是否递归删除文件夹及文件夹下的文件// boolean isDeleted = fs.delete(delete, true);System.out.println(isDeleted == true ? "删除成功" : "删除失败");} catch (Exception e) {e.printStackTrace();}}
}
编译上述代码,导出为xxx.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/xxx.jar com.hdfsclient.DeleteFile
(6 HDFS创建目录
FileSystem提供了一个实例方法mkdirs()来创建目录,该方法可以一次性创建除父目录之外所有必要的。如果目录都已经创建成功,则返回true。例:显示在HDFS上创建一个目录。
public class CreateDir {public static void main(String[] args) {String uri = "hdfs://master:9000/input/hadoop/tmp";Configuration conf = new Configuration();try {FileSystem fs = FileSystem.get(URI.create(uri), conf);Path dfs = new Path(uri);fs.mkdirs(dfs);} catch (Exception e) {e.printStackTrace();}}
}
编译上述代码,导出为xxx.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/xxx.jar com.hdfsclient.CreateDir
(7 查询文件系统
文件元数据类FileStatus封装了文件系统中文件和目录的元数据,包括文件长度、块大小、备份、修改时间、所有者以及权限信息等。
1) 查看HDFS中某个文件是否存在。
public class CheckFileIsExist {public static void main(String[] args) {String uri = "hdfs://master:9000/input/hadoop/sample.txt";Configuration conf = new Configuration();try {FileSystem fs = FileSystem.get(URI.create(uri), conf);Path path = new Path(uri);boolean isExists = fs.exists(path);System.out.println(isExists == true ? "文件存在" : "文件不存在");} catch (Exception e) {e.printStackTrace();}}
}
编译上述代码,导出为xxx.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/xxx.jar com.hdfsclient.CheckFileIsExist
2) 列出HDFS中某个目录下的文件或目录名称。
public class ListFiles {public static void main(String[] args) {String uri = "hdfs://192.168.52.25:9000/gl";Configuration conf = new Configuration();try {FileSystem fs = FileSystem.get(URI.create(uri), conf);Path path = new Path(uri);FileStatus[] status = fs.listStatus(path);for (FileStatus s : status) {System.out.println(s.getPath().toString());}fs.close();} catch (Exception e) {e.printStackTrace();}}
}
编译上述代码,导出为xxx.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/xxx.jar com.hdfsclient.ListFiles
3) 查看HDFS中文件存储位置信息。
public class LocationFile {public static void main(String[] args) {String uri = "hdfs://192.168.52.25:9000/gl/sample.txt";Configuration conf = new Configuration();try {FileSystem fs = FileSystem.get(URI.create(uri), conf);Path path = new Path(uri);FileStatus status = fs.getFileStatus(path);BlockLocation[] blocks = fs.getFileBlockLocations(status, 0, status.getLen());for (int i = 0; i < blocks.length; i++) {String[] hosts = blocks[i].getHosts();System.out.println("block_" + i + "_location:" + hosts[0]);}fs.close();} catch (Exception e) {e.printStackTrace();}}
}
编译上述代码,导出为xxx.jar文件,拷贝到/home/files目录下,执行下面的命令:
# hadoop jar /home/files/xxx.jar com.hdfsclient.LocationFile
补充例:请编写代码完成使用HDFS API读取文件并打印到控制台输出,提示:可使用FileSystem读取文件,使用IOUtils工具类,将读取的文件流直接写入到system.out输出流。
public class FileSystemCat {public static void main(String[] args) throws Exception {String uri = "hdfs://master:9000/output/wordcount/part-r-00000";//…// 在此处编写代码//…}
}
答案再上面。
03 使⽤其他常⽤接口 (了解就好,红色必备)
Hadoop文件系统的接口是通过Java API提供的,所以其他非Java应用程序访问Hadoop文件系统会比较麻烦。Thriftfs定制功能模块中的Thrift API通过把Hadoop文件系统包装成一个Apache Thrift服务来弥补这个不足,从而使任何具有Thrift绑定的语言都能轻松地与Hadoop文件系统(例如HDFS)进行交互。Thrift是一个软件框架,最初由Facebook开发用作系统内各语言之间的RPC通信。
非常注意点:其他语言也可以编译Hadoop,不是仅java。
补充例:
下列关于 Hadoop API 的说法错误的是 (A)
A.Hadoop 的文件 API 不是通⽤的,只⽤于 HDFS 文件系统
B.Configuration 类的默认实例化方法是以 HDFS 系统的资源配置为基础的
C.FileStatus 对象存储文件和目录的元数据
D.FSDataInputStream 是 java.io.DataInputStream 的子类
六 Hadoop I/O详解(重点)
1 数据完整性(不画红的了解就行)(简答)(1 常用错误检验码:CRC-32(循环冗余检验),任何大小的数据输入均计算得到一个32位的证书校验和。HDFS会对写入的所有数据计算校验和,并在读取数据时验证校验和。(特注:校验和的计算代价是相当低的,一般只是增加少许额外的读/写文件时间。对于大多数应用来说,这样的额外开销可以保证数据完整性是可以接受的。)
本地文件上传到HDFS集群时的校验
将HDFS集群文件读取到本地时的校验:客户端读取HDFS数据时,NameNode指定数据块位置。DataNode用CRC-32校验读出的数据,如校验和不匹配,表明数据损坏,DataNode通知NameNode。NameNode随后指引客户端从其他副本读取数据,确保数据完整性。
(2 检验数据完整性:(背过)
核心问题1:HDFS是如何验证数据完整性的?
1.DataNode负责在收到数据后存储该数据及其验证校验和。在收到客户端的数据或复制其他DataNode的数据时执行这个操作。正在进行写操作的客户端将数据及其检验和发送到由一系列DataNode线成的管线,管线中最后一个DataNode负责验证校验和,如果检测到错误,客户端便会收到一个ChecksumException异常,该异常是IOException异常子类。客户端应以应用程序特定的方式来处理,例如重试这个操作。
2.客户端从DataNode读取数据时,也会计算校验和,将会与DataNode中存储的校验和进行比较。每个DataNode均持久保存有一个用于验证的校验和日志,所以它知道每个数据块的最后一次验证时间。客户端验证完之后会告诉DataNode并更新日志。保存这些统计信息对于检测损坏的磁盘很有价值。
3.客户端在读取数据块时会验证校验和,每个DataNode也会在后台线程中运行一个DataBlockScanner进程,从而定期验证存储在这个DataNode上的所有的数据块。这也是解决物理存储媒体上位损坏(位衰减)的有效措施。
核心问题2:客户端发现有Block坏掉了,该如何来恢复这个损坏的Block呢?
客户端在读取Block时,如果检测到错误,首先向NameNode报告已损坏的Block及其正在尝试读操作的这个DataNode,再抛出ChecksumException异常。
NameNode将这个Block副本标记为已损坏,这样NameNode就不会把客户端指向这个Block,也不会复制这个Block到其他的DataNode。
NameNode会安排这个Block的一个完好的副本复制到另外一个DataNode上,恢复副本因子的水平。
最后,NameNode将已损坏的Block副本删除。
2.文件压缩(选择,填空,简答)(除(6以外 必须全部背过,必考)
(1 压缩好处:减少存储文件所需要的磁盘空间;加速数据在网络和磁盘上的传输。
(2 压缩基本原则:计算密集型的job,少用压缩;IO密集型的job,多用压缩。
(3 压缩 MapReduce 的一种优化策略:通过压缩编码对 Mapper 或者 Reducer 的输出进行压缩,以减少磁盘 IO, 提高 MR 程序运行速度(但相应增加了 cpu 运算负担) 。
(4 常见Hadoop不同压缩格式特性:
压缩工具 | 压缩能力 | 压缩速度 | 解压缩速度 | 备注 |
---|---|---|---|---|
gzip | 一般 | 一般 | 一般 | 空间/时间性能平衡 |
bzip2 | 强 | 慢 | 一般 | 压缩能力强,速度慢 |
LZO | 较弱 | 快 | 快 | 压缩速度优化 |
LZ4 | 较弱 | 非常快 | 非常快 | 压缩速度和解压缩速度均优 |
Snappy | 较弱 | 非常快 | 非常快 | 解压缩速度比LZO高 |
(5 常见的4种压缩格式比较:(注:在MapReduce处理压缩的数据时,压缩格式是否支持切分(splitting)是非常重要的。)
格式 | 压缩率 | 速度 | Split支持 | 应用场景 |
---|---|---|---|---|
gzip压缩 | 中 | 快 | 否 | 文件压缩之后在130M以内的(1个块大小内),可以考虑用gzip压缩格式.例如:一天或者一个小时的日志压缩成一个gzip文件,运行MapReduce程序时通过多个gzip文件达到并发。Hive、Streaming和MapReduce程序的处理方式和文本处理完全一样,压缩之后原来的程序不需要做任何修改。 |
lzo压缩 | 低 | 中 | 否 | 压缩后大于200M的文件,适合大文件压缩,优点随文件大小增加而更明显。 |
snappy压缩 | 低 | 中 | 否 | 当MapReduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式;或者作为一个MapReduce作业的输出和另外一个MapReduce作业的输入。 |
bzip2压缩 | 高 | 慢 | 是 | 适合对速度要求不高,但对压缩率要求较高的时候,可以作为MapReduce作业的输出格式;或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情况;或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持split,而且兼容之前的应用程序(即应用程序不需要修改)的情况。 |
补充例:Hadoop压缩格式中,bzip压缩的优缺点及应用场景?
答案在表格4中.
(6 压缩格式选取:(了解,不大可能考)
使用容器文件格式,例如顺序文件(SequenceFile)、RCFile或者Avro数据文件,所有这些文件格式同时支持压缩和切分。通常最好与一个快速压缩工具联合使用,例如LZO、LZ4,或者Snappy。
使用支持切分的压缩格式,例如bzip2,或者使用通过索引实现切分的压缩格式,例如LZO。
在应用中将文件切分成块,并使用任意一种压缩格式为每个数据块建立压缩文件。这种情况下, 需要合理选择数据块的大小,以确保压缩后数据块的大小近似于HDFS块的大小。
存储未经压缩的文件。
(对于大文件不要使用不支持切分整个文件的压缩格式,因为会失去数据的本地特性,进而造成MapReduce应用的效率低下。)
3 文件序列化和反序列化:(选择)(考不多)
(1 理解就看下图即可。
(2 序列化原因:因为要跨机器 RPC(进程间通讯)1. 保证安全 2. 序列值传输速)快,体积变小
(3 常见 writable 实现类
类型 | Writable类 | 描述 |
---|---|---|
基本数据类型 | BooleanWritable | 存储单个布尔值 |
ByteWritable | 存储单个字节 | |
ShortWritable | 存储单个短整型 | |
IntWritable | 存储单个整型 | |
VIntWritable | 存储可变长度的整型,优化存储空间 | |
FloatWritable | 存储单个浮点数 | |
LongWritable | 存储单个长整型 | |
VLongWritable | 存储可变长度的长整型,优化存储空间 | |
DoubleWritable | 存储单个双精度浮点数 | |
文本和字符串 | Text | 存储字符串,使用UTF-8编码 |
Writable集合类 | ArrayWritable | 存储Writable 对象的数组 |
ArrayPrimitiveWritable | 存储基本类型的数组,例如整型数组 | |
TwoDArrayWritable | 存储二维Writable 对象数组 | |
MapWritable | 存储键值对映射,键和值都是Writable 对象 | |
SortedMapWritable | 类似于MapWritable ,但保持有序 | |
EnumMapWritable | 存储枚举类型的键和Writable 值的映射 |
(4 序列化框架(了解,不重要)
MapReduce支持除Writable类型外的任何键值类型,条件是必须提供方式来转换这些类型与二进制表示。
特性 | 序列化IDL | Avro框架 |
---|---|---|
定义方式 | IDL文件 | JSON模式 |
语言支持 | 多语言 | 多语言 |
模式演变 | 复杂 | 易于管理 |
序列化性能 | 较高 | 高效 |
数据压缩 | 需额外实现 | 内置支持 |
数据格式 | 二进制/文本 | 二进制/JSON |
默认值支持 | 支持 | 支持 |
使用场景 | RPC通信 | 大数据处理 |
补充例:以下关于序列化Writable的说法正确的是?(ABCD)
A、反序列化也称反串行化,它是指将字节流转回结构化对象的逆过程。
B、Hadoop中使用自己开发的类:IntWritable、FloatWritable、Text等,都是Writable的实现类。
C、序列化和反序列化在分布式数据处理中,主要于进程间通信和永久存储两个领域。
D、Writable接口是一个序列化对象的接口,能够将数据写入流或者从流中读出。
4.Hadoop基于文件的数据结构(了解即可)
(1 HDFS上的小文件问题:文件由许多记录(Records)组成,可以通过调用HDFS的<font style="color:rgba(6, 8, 31, 0.88);">sync()</font>
方法(与<font style="color:rgba(6, 8, 31, 0.88);">append()</font>
方法结合使用)定期生成一个大文件。也可以编写程序合并这些小文件。
(2 MapReduce上的小文件问题:需要通过某种容器将文件分组,Hadoop提供了几种选择:HAR File、SequenceFile、MapFile,以及HBase。
(3 SequenceFile 存储
特性 | 描述 |
---|---|
概述 | 存储二进制键值对(key-value pairs),用于高效数据序列化和压缩 |
键值对存储 | 每个记录由键(key)和值(value)组成,支持不同类型的数据 |
压缩支持 | 可选择数据压缩以减少存储空间和提高I/O性能,下面是两种压缩模式。 |
- 记录压缩:对每条记录的值进行压缩 | |
- 块压缩:将一连串记录统一压缩成一个块 | |
分割支持 | 支持Hadoop输入格式,可被MapReduce作业读取,易于并行处理 |
写入和读取 | 支持随机访问,适合高效读取大规模数据集 |
类型安全 | 通过指定序列化和反序列化的类,实现类型安全 |
七 MapReduce编程模型(核心)
1.MapReduce基础(选择,填空) (必考)(1 MapReduce:采用分而治之的思想,将数据处理过程拆分为主要的Map(映射)和Reduce(化简)两步。
(2 MapReduce优点:易于编程;良好的扩展性;高容错性;适合PB级别以上的大数据的分布式离线批处理
(3 MapReduce缺点:MapReduce的执行速度慢(这里补充一句:MapReduce的瓶颈主要在磁盘的I/O);MapReduce过于底层;不是所有算法都能用MapReduce实现,不是所有算法都能实现并行。
2.WordCount实例分析(所有提都考)(超级重点)
(1 Hadoop的MapReduce中,map和reduce函数遵循如下常规格式:
map:(k1,v1)–> list(k2,v2)
reduce:(k2,list(v2))–> list(k3,v3)
一般来说,map函数输入的键/值类型(k1和v1)不同于输出类型(k2和v2)。reduce函数的输入类型必须与map函数的输出类型相同,但是reduce函数的输出类型(k3和v3)可以不同于输入类型。
如果使用了combine函数,它与reduce函数的形式相同,不同之处是它的输出类型是中间的键值对类型(k2,v2),这些中间值可以输入reduce函数:
map:(k1,v1)–> list(k2,v2)
combine:(k2,list(v2))–> list(k2,v2)
reduce:(k2,list(v2))–> list(k3,v3)
combine函数与reduce函数通常是一样的,在这种情况下,k3与k2类型相同,v3与v2类型相同。
补充例:1.MapReduce数据处理模型非常简单,map和reduce函数的输入和输出是键/值对,下面选项中关于map和reduce输入和输出描述错误的是()。
A、map:(k1,v1)–> list(k2,v2)
B、combine:(k2,list(v2))–> k2,list(v2)
C、reduce:(k2,list(v2))–> list(k3,v3)
D、以上都不对
2.在MapReduce编程模型中,键值对<key,value>的key必须实现下列哪个接口?(A)
A、WritableComparable B、Comparable
C、Writable D、LongWritable
补充:
接口 | 描述 | 是否符合键的要求 |
---|---|---|
WritableComparable | 继承自 Writable 和 Comparable ,提供读写序列化功能和比较功能。 | 是 |
Comparable | 仅提供比较功能,不具备序列化能力。 | 否 |
Writable | 提供读写序列化功能,但不支持比较功能。 | 否 |
LongWritable | 是具体的Writable实现,封装了long 类型的值,但不代表所有可能的键类型。 | 否(但需要实现WritableComparable) |
(2 编写Mapper类
代码说明:Mapper类读取输入并执行map函数。
Mapper类必须继承org.apache.hadoop.mapreduce.Mapper类,并且实现map函数。Mapper类的4个泛型类型分别代表了:map函数输入键/值对的类型和输出键/值对的类型;map函数的3个参数的作用分别是?
public static class Map extends Mapper<LongWritable,Text,Text,IntWritable>{private final static IntWritable one= new IntWritable(1);private Text word= new Text();//LongWritable是输入数据的键,代表行偏移量;//Text是输入数据的值,代表该行的内容;//Context为map函数的输出域,用于将计算的中间结果输出public void map(LongWritable key,Text value,Context context){StringTokenizer tokenizer= new StringTokenizer(value.toString());while(tokenizer.hasMoreTokens()){word.set(tokenizer.nextToken());try{context.write(word, one);}catch(Exception e){e.printStackTrace();}}}
}
(3 编写Reducer类
代码说明:Reducer类读取Mapper的输出作为reduce函数的输入并执行reduce函数。
Reducer类必须继承org.apache.hadoop.mapreduce.Reducer类,并且实现reduce函数。Reducer类的4个泛型类型分别代表:reduce函数的输入键值对类型和输出键值对类型;reduce函数的3个参数的作用分别是?
public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable>{private IntWritable result= new IntWritable();//Text是输入数据的键,代表一个词;//Iterable<IntWritable>是输入数据的值,代表该词的计数;//Context为reduce函数的输出域,用于将计算的最终结果输出public void reduce(Text key,Iterable<IntWritable> values,Context context){int sum=0;for(IntWritable val: values){sum+= val.get();}result.set(sum);try{context.write(key,result);}catch(Exception e){e.printStackTrace();}}
}
(4 编写Driver类
public class WordCount{public static void main(String[] args){Configuration conf = new Configuration();//代码1Job job = null;//代码2job = Job.getInstance(conf, "wordcount");//代码3String[] otherArgs = null;try{otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();if (otherArgs.length != 2){System.err.println("Usage: wordcount <in> <out>");System.exit(1);}} catch(IOException e){e.printStackTrace();}job.setJarByClass(WordCount.class);//代码4job.setMapperClass(Map.class);//代码5//job.setCombinerClass(IntSumReducer.class);//代码6job.setReducerClass(Reduce.class);//代码7job.setOutputKeyClass(Text.class);//代码8job.setOutputValueClass(IntWritable.class);//代码9try{FileInputFormat.addInputPath(job, new Path(otherArgs[0]));//代码10FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));//代码11job.submit();} catch(Exception e){e.printStackTrace();}}
}
(5 实验补充:
Hadoop框架自带一个MapReduce作业,用于统计文档中单词出现的次数。下面代码是运行Hadoop自带的MapReduce的过程,请补全下面代码的空白处。
1) 启动Hadoop
进入/home/hadoop/hadoop-3.1.3目录。 cd /home/hadoop/hadoop-3.1.3
启动Hadoop集群。
使用jps查看集群守护进程是否已经全部启动。
2) 在本地创建一个测试文件
在/home/hadoop下创建目录files,并进入该目录。
创建并写入一个文件file.txt。
3) 将本地测试文件上传到HDFS
转到/home/hadoop/hadoop-3.1.3目录下。cd /home/hadoop/hadoop-3.1.3
在HDFS文件系统中创建 /input/wordcount目录。
将第3步创建的一个文件,上传到HDFS文件系统中。
查看文件是否上传成功。
4) 运行系统自带的MapReduce作业
步骤 1:启动Hadoop
进入Hadoop目录并启动集群的命令:
# cd /home/hadoop/hadoop-3.1.3
# sbin/start-dfs.sh
# sbin/start-yarn.sh
使用jps查看集群守护进程是否已经全部启动:
# jps 步骤 2:在本地创建一个测试文件
在/home/hadoop下创建目录files并进入该目录:
# mkdir files
# cd files
创建并写入一个文件file.txt:
# echo "Hello Hadoop World" > file.txt 步骤 3:将本地测试文件上传到HDFS
转到/home/hadoop/hadoop-3.1.3目录下:
# cd /home/hadoop/hadoop-3.1.3
在HDFS文件系统中创建/input/wordcount目录:
# bin/hdfs dfs -mkdir -p /input/wordcount
将第2步创建的文件上传到HDFS文件系统中:
# bin/hdfs dfs -put /home/hadoop/files/file.txt /input/wordcount/ 查看文件是否上传成功:
# bin/hdfs dfs -ls /input/wordcount/ 步骤 4:运行系统自带的MapReduce作业
运行MapReduce作业统计单词出现的次数:
# bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /input/wordcount/file.txt /output/wordcount_result
查看作业输出的结果:
# bin/hdfs dfs -cat /output/wordcount_result/part-r-00000
补充例:
1)下列选项中,Hadoop 集群的主要瓶颈是(B)。
A、CPU B、磁盘 IO C、网络 D、内存
2)下列关于 MapReduce 说法不正确的是__C_。
A. MapReduce 是一种计算框架
B.MapReduce 来源于 google 的学术论文
C. MapReduce 程序只能⽤ java 语言编写
D. MapReduce 隐藏了并行计算的细节,方便使⽤
3)MapReduce 框架提供了一种序列化键/值对的方法,支持这种序列化的类能够在 Map 和Reduce 过程中充当键或值,以下说法错误的是(C)
A. 实现 Writable 接口的类是值
B. 实现 WritableComparable接口的类可以是值或键
C. Hadoop 的基本类型 Text 并不实现 WritableComparable接口
D. 键和值的数据类型可以超出 Hadoop 自身支持的基本类型
- Hadoop非常擅长处理非结构化文本数据,Hadoop提供了用于处理文本的不同的InputFormat类,以下说法中错误的是(A)。
A、TextInputFormat是默认InputFormat,每条记录是一行输入,键是TextWritable类型
B、通常情况下,文件中的每一行的键/值对,使用某个分界符进行分隔,比如制表符。如果要正确处理这类文件,可以使用KeyValueTextInputFormat比较合适
C、通过TextInputFormat和KeyValueTextInputFormat,每个mapper收到的输入行数不同。行数取决于输入分片的大小和行的长度
D、如果希望mapper收到固定行数的输入,需要将NLineInputFormat作为InputFormat
5)Hadoop Streaming 支持脚本语言编写简单 MapReduce 程序,以下是一个例子:
bin/hadoop jar contrib/streaming/hadoop-0.20-streaming.jar—input input/filename—output output—mapper ‘dosth.py 5’—file dosth.py—D mapred.reduce.tasks=1
以下说法不正确的是(D)
A. Hadoop Streaming 使⽤ Unix 中的流与程序交互
B. Hadoop Streaming 允许我们使⽤任何可执行脚本语言处理数据流
C. 采⽤脚本语言时必须遵从 UNIX 的标准输入 STDIN,并输出到 STDOUT
D. Reduce 没有设定,上述命令运行会出现问题(补充:没有设定特殊的 reducer,默认使⽤ IdentityReducer)
八 MapReduce的工作机制与YARN平台(重点)
1 YARN平台解析(选择、简答) (了解有印象即可,不大考)(1 YARN架构分析(极简版):
YARN是为了处理HDFS上的数据而设计的,它把资源管理从JobTracker分离成ResourceManager(RM)和ApplicationMaster(AM)。RM负责整个集群的资源监控、分配和管理,NM(NodeManager)负责维护单个节点上的资源和任务执行,AM负责单个应用程序的调度、协调和与RM协商资源。这使得YARN灵活且可扩展。
(2 ResourceManager(RM):
RM主要由两个组件构成:调度器(Scheduler)和应用程序管理器(ASM)。调度器:根据资源需求和限制条件,将资源以Container形式分配给应用程序,但不处理具体应用任务。应用程序管理器:管理应用程序的生命周期,包括提交、资源协商、监控和故障重启。
(3 ApplicationMaster(AM):
详细功能:与调度器协商资源;与NodeManager合作,在合适的Container中运行对应的组件task,并监控这些task执行;如果Container出现故障,ApplicationMaster会重新向调度器申请其他资源;计算应用程序所需的资源量,并转化成调度器可识别的协议信息包
特点:
在AM出现故障后,应用管理器会负责重启它,但由AM自己从之前保存的应用程序执行状态中恢复应用程序。
一个应用通过ApplicationMaster可以请求非常具体的资源:资源名称(包括主机名称、机架名称,以及可能的复杂的网络拓扑);内存量;CPU(核数/类型);其他资源,如disk/network、I/O、CPU等资源。
(4 基于YARN的MapReduce 2运行机制(不清楚考不考,有空闲自己去了解,说实话考的话,很过分)
补充例:
YARN的基本思想是将hadoop中哪个进程,拆分成为两个独立的进程:ResourceManager和ApplicationMaster。(B)
A、TaskTracker B、JobTracker C、NameNode D、DataNode
在Hadoop中,下面哪个进程负责MapReduce任务调度(B)。
A、NameNode B、Jobtracker C、SecondaryNameNode D、TaskTracker
2.Shuffle和排序
(1 Shuffle:MapReduce 确保每个 Reducer 的输入都是按键排序的。系统执行排序的过程,即将 map 输出作为输入传给 Reducer 的过程,称为 Shuffle。
(2 Shuffle 过程:
Map 端:
1、 每个输入分片由一个Map任务处理,默认分片大小为HDFS的块大小(一般为128M),可调整。
2、 数据在写入磁盘前,按Reduce任务数量划分为相应的分区,保证每个Reduce任务对应一个分区。
3、 当 Map 任务输出最后一个记录时,可能会有很多的溢出文件,这时需要将这些文件合并。
4、 将分区中的数据拷贝给相对应的 Reduce 任务。
Reduce 端:
1、 Reduce 会接收到不同 Map 任务传来的数据,并且每个 Map 传来的数据都是有序的。
2、 随着溢写文件的增多,后台线程会将这些文件合并成一个更大的有序的文件,这样做是为了给后面的合并节省时间。
3、 合并的过程中会产生许多的中间文件(写入磁盘了),但 MapReduce 会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到 Reduce 函数。
4、 在 Reduce 阶段,对已排序输出中的每个键调⽤ Reduce 函数。
(2 Shuffle过程配置调优:(了解,不大可能考,)
总的原则是给Shuffle过程尽量多提供内存空间。但是,有一个平衡问题,也就是要确保map函数和reduce函数能得到足够的内存来运行。这就是为什么编写map函数和reduce函数时尽量少用内存的原因,它们不应该无限使用内存,例如,应避免在Map中堆积数据。
运行Map任务和Reduce任务的JVM,其内存大小由mapred.child.java.opts属性设置。任务节点上的内存大小应该尽量大。
在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗;
在Map端,可以通过避免多次溢出写磁盘来获得最佳性能,一次是最佳的情况。如果能估算Map输出大小,可以合理地设置ip.sort.*属性来尽可能减少溢出写的次数。如果可以,就要增加io.sort.mb的值。
(3 在MapReduce计算框架中,主要使用两种排序算法:快速排序和归并排序。
在Map任务和Reduce任务的Shuffle过程中,共发生三次排序操作:
第一次排序:当map函数输出时,数据首先写入内存环形缓冲区。达到阀值后,后台线程将数据划分为分区并按键进行内排序(使用快速排序)。
第二次排序:在Map任务完成前,磁盘上存在多份已分区和排序好的溢写文件。这些溢写文件被合并为一个已分区且已排序的输出文件,只需进行一次排序,以保持整体有序。
第三次排序:在Shuffle的Reduce阶段,多个Map任务的输出文件被合并。由于经过第二次排序,此时只需再做一次排序,确保最终输出文件整体有序。
补:速记:
第一次排序:内存缓冲区内排序(快速排序)。
第二次排序:文件合并阶段(归并排序)。
第三次排序:仍在文件合并阶段(归并排序)。
例:在MapReduce任务的shuffle过程中,一共发生了3次排序操作,其中第2次排序和第3次排序都是在文件合并阶段发生的,使用的是下列哪种排序算法(C)。
A、快速排序 B、冒泡排序 C、归并排序 D、倒序排序
九 MapReduce的高级概念(了解)
1. 计数器与排序(选择)(1 内置计数器:
常见MapReduce内置计数器如下:(标红背过)
计数器类别 | 描述 |
---|---|
File System Counters | 监控文件系统相关的操作和使用情况,如读取和写入的字节数。 |
Job Counters | 详细记录作业执行过程中各种统计信息,包括输入输出记录数量、总Map和Reduce任务数等。 |
Map-Reduce Framework | 监控MapReduce框架内部的统计信息,包括分片数量、Shuffle和Sort过程中的各种状态。 |
Shuffle Errors | 记录在Shuffle过程中发生的错误数量,帮助识别和排查数据传输问题。 |
File Input Format Counters | 监控与输入文件格式相关的统计信息,如读取记录的数量、处理错误等。 |
File Output Format Counters | 监控与输出文件格式相关的统计信息,例如成功写入的记录数量和字节数等。 |
补充例:MapReduce任务内置了大量计数器,其中不包括(D)。
A、文件系统计数器(File System Counters) B、作业计算器
C、Shuffle计算器 D、词频计算器
(2 用户自定义的Java计数器
计数器常见的方法有以下几个:
String getName():Get the name of the counter
String getDisplayName():Get the display name of the counter
long getValue():Get the current value
void setValue(long value):Set this counter by the given value
void increment(long incr):Increment this counter by the given value
(3 用户自定义的Streaming计数器
(4 二次排序实现:
自定义Key:所有自定义key应该实现接口WritableComparable,因为它是可序列化并且可比较的。
自定义分区:自定义分区函数类DefinedPartition,是key的第一次比较,完成对所有key的排序。
自定义比较器:这是Key的第二次比较,对所有的Key进行排序,即同时完成IntPair中的first和second排序。在Job中通过setSortComparatorClass()方法来设置key的比较器。如果没有使用自定义的DefinedComaparator类,则默认使用Key中compareTo()方法对Key排序。
自定义分组:在Reduce阶段,构造一个与 Key 相对应的 Value 迭代器的时候,只要first相同就属于同一个组,放在一个Value迭代器。
主体程序实现
2.联接:
(1 reduce side join
reduce side join 是一种最简单的 join 方式,其主要思想如下: 在 Map 阶段,map 函数同时读取两个文件 File1 和 File2,为了区分两种来源的 key/value 数据对,对每条数据打一个标签(tag),比如:tag=1 表示来自文件 File1,tag=2 表示来自文件 File2。即:Map 阶段的主要任务是对不同文件中的数据打标签。在 Reduce 阶段,reduce 函数获取 key 相同的来自File1 和 File2 文件的 value list, 然后对于同一个 key,对 File1 和 File2 中的数据进行 join(笛卡尔乘积)。即:Reduce 阶段进行实际的连接操作。之所以存在 reduce side join,是因为在 map 阶段不能获取所有需要的 join 字段,即:同一个 key 对应的字段可能位于不同 map中。reduce side join 是非常价效的,因为 Shuffle 阶段要进行大量的数据传输。
(2 map side join
map side join 是针对以下场景进行的优化:两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多份,让每个 map task 内存中存在一份(比如存放到 hashtable 中),然后只扫描大表:对于大表中的每一条记录 key/value,在 hash table 中查找是否有相同的 key 的记录,如果有,则连接后输出即可。
核心思想:将小表进行分布式存存,在 map-task 阶段读取存存文件数据存储到内存数据结构中,以供 reduce 阶段连接查找。
适⽤场景:有一个或者多个小表(文件)
优点:将小表存存,可以高效查询;由于在 map 阶段进行连接,所以将会大大减小 map到 reduce 端的数据传输,从而减少不必要的 shuffle 耗时,提高整个 mr 的执行效率
缺点:如果业务全是大表不适合
(3 SemiJoin
SemiJoin,也叫半连接,是从分布式数据库中借鉴过来的方法。它的产生动机是:对于 reduce side join,跨机器的数据传输量非常大,这成了 join 操作的一个瓶颈,如果能够在 Map 端过滤掉不会参加 join 操作的数据,则可以大大节省网络 IO。简单来说:就是将小表中参与join 的 key 单独抽出来通过 DistributedCach 分发到相关节点,然后将其取出放到内存中(可以放到 HashSet 中),在 map 阶段扫描连接表,将 join key 不在内存 HashSet 中的记录过滤掉,让那些参与 join 的记录通过 shuffle 传输到 reduce 端进行 join 操作,其他的和 reduce join 都是一样的。
补充例:
1.在两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多份,让每个map task内存中存在一份(比如存放到hash table中),然后只扫描大表。在这种场景下可以考虑使用以下哪种join方式(A)。
A、map side join B、reduce side join
C、semiJoin D、map to reduce join
2.Hadoop中有一个distcp程序,以下说法正确的是(D)。
A、distcp一般用于在两个HDFS集群中传输数据
B、distcp可用于Hadoop文件系统并行复制大量数据
C、distcp复制数据时会跳过目标路径已有的文件,但是可通过-overwrite选项进行覆盖
D、以上说法都是正确的
定义 | distcp (Distributed Copy)是Hadoop提供的工具,用于在HDFS集群之间进行大规模并行数据复制。 |
---|---|
功能特性 | - 并行处理:利用MapReduce框架的分布式架构进行数据复制。 - 目标路径处理: 默认情况下跳过目标路径中已存在的文件,使用 -overwrite 选项可强制覆盖。 |
使用场景 | - 跨集群数据迁移 - 大数据集复制 |
常用选项 | - -overwrite 强制覆盖已有文件 其他参数:可指定源路径和目标路径、设置副本数量等。 |