hadoop
- Hadoop的功能以及模块
- 下面哪个程序负责 HDFS 数据存储?
- hdfs 中的 block 默认保存几份?
- 下列哪个程序通常与NameNode 在一个节点启动?
- HDFS 默认 Block Size
- Client 端上传文件的时候下列哪项正确
- 下面与 HDFS 类似的框架是?
- Ganglia 不仅可以进行监控,也可以进行告警。(正确)
- Nagios 不可以监控 Hadoop 集群,因为它不提供 Hadoop支持。(错误 )
- 如果 NameNode 意外终止,SecondaryNameNode 会接替它使集群继续工作。(错误 )
- Cloudera CDH 是需要付费使用的。(错误)
- NameNode 负责管理 metadata,client 端每次读写请求,它都会从磁盘中读取或则会写入 metadata信息并反馈 client 端。(错误)
- NameNode 本地磁盘保存了 Block 的位置信息。( 个人认为正确)
- DataNode 通过长连接与 NameNode 保持通信。错误
- Hadoop 自身具有严格的权限管理和安全措施保障集群正常运行。(错误)
- Slave 节点要存储数据,所以它的磁盘越大越好。(错误)
- hadoop dfsadmin –report 命令用于检测 HDFS 损坏块。(错误)
- Hadoop 默认调度器策略为 FIFO(正确 )
- 集群内每个节点都应该配 RAID,这样避免单磁盘损坏,影响整个节点运行。(错误)
- Hadoop 环境变量中的 HADOOP_HEAPSIZE 用于设置所有 Hadoop 守护线程的内存。它默认是 200 GB。( 错误)
- DataNode 首次加入 cluster 的时候,如果 log 中报告不兼容文件版本,那需要 NameNode执行―Hadoopnamenode -format‖操作格式化磁盘。(错误 )
- Block Size 是不可以修改的。(错误)
- Hadoop 支持数据的随机读写。(错)
- 因为 HDFS 有多个副本,所以 NameNode 是不存在单点问题的。(错误 )
- Hadoop 是 Java 开发的,所以 MapReduce 只支持 Java 语言编写。(错误 )
- 每个 map 槽就是一个线程。(错误)
- Mapreduce 的 input split 就是一个 block。(错误)
- hdfs的体系结构
- 简要描述如何安装配置一个apache开源版本hadoop,只描述即可,无需列出完整步骤,能列出步骤更好。
- 启动hadoop集群时报下图错误,分析什么原因:
- 请列出hadoop的进程名称
- Hadoop的核心配置是什么?
- “jps”命令的用处?
- 杀死一个 job?
- 加入一个新的存储节点和删除一个计算节点?
- 请列出你所知道的 hadoop 调度器,并简要说明其工作方法?
- hadoop框架中怎么来优化
- datanode在什么情况下不会备份
- combiner出现在那个过程
- 3个datanode中有一个datanode出现错误会怎样?
- hadoop 的 namenode 宕机,怎么解决
- 一个datanode 宕机,怎么一个流程恢复
- 请简述 hadoop 怎么样实现二级排序?
- 如何使用MapReduce实现两个表join,可以考虑一下几种情况:(1)一个表大,一个表小(可放到内存中);(2)两个表都是大表?
- MapReduce中排序发生在哪几个阶段?这些排序是否可以避免?为什么?
- 请简述 mapreduce 中,combiner,partition 作用?
- 用mapreduce怎么处理数据倾斜问题?
- hadoop中Combiner的作用?
- Mapreduce 的 map 数量 和 reduce 数量 怎么确定 ,怎么配置
- 在hadoop中文件的压缩带来了两大好处:
- mapreduce的调度模式()
- Hadoop的三大分布式模块及功能分别是什么?
- 什么情况下需要编译Hadoop?
- SecondaryNameNode
- hdfs写流程
- hdfs读流程
- 举一个简单的例子说明mapreduce是怎么来运行的 ?
- mr之shuffle详解
- mr流程图
- yarn流程
- HDFS的HA架构
- 行式存储VS列式存储
- Hadoop集群中其中一台DataNode节点的磁盘快满了怎么处理?
Hadoop的功能以及模块
功能:Hadoop解决的问题
- 大数据
存储
- 大数据
计算
模块
- Hadoop Common: The common utilities that support the other Hadoop modules.
- Hadoop的通用组件,用于连接各个模块的应用
- Hadoop Distributed File System (HDFS™): A distributed file system that provides high-throughput access to application data.
- HDFS,
分布式文件系统
,用于提供高吞吐量的数据访问 - 实现大数据的存储,提供大数据的读写访问
- HDFS,
- Hadoop MapReduce: A YARN-based system for parallel processing of large data sets.
分布式计算模型
,用于并行化的处理大量数据,基于Yarn- MapReduce程序运行在YARN,由YARN提供分布式CPU和内存资源
- Hadoop YARN: A framework for job scheduling and cluster resource management.
分布式资源管理和任务调度框架
- 资源管理:
将多台机器的资源构建成一个整体,CPU、内存
对外提供统一的运行资源平台
- 资源容器
- 负责给在YARN中运行的程序提供资源
- 任务调度
- 多个MapReduce程序
谁先运行,谁后运行
每个程序使用多少资源
下面哪个程序负责 HDFS 数据存储?
- a)NameNode
- b)Jobtracker
- c)
Datanode
- d)secondaryNameNode
- e)tasktracker
hdfs 中的 block 默认保存几份?
- a)
3份
- b)2份
- c)1份
- d)不确定
下列哪个程序通常与NameNode 在一个节点启动?
- a)SecondaryNameNode
- b)DataNode
- c)
TaskTracker
- d)Jobtracker
- 注:haoop1.X
分析:
hadoop 的集群是基于 master/slave 模式,namenode 和 jobtracker 属于 master,datanode 和 tasktracker属于 slave,master 只有一个,而 slave 有多个。SecondaryNameNode 内存需求和 NameNode 在一个数量级上,所以通常 secondary NameNode(运行在单独的物理机器上)和 NameNode 运行在不同的机器上。
JobTracker 和 TaskTracker
JobTracker 对应于 NameNode
TaskTracker 对应于 DataNode
DataNode 和 NameNode 是针对数据存放来而言的
JobTracker 和 TaskTracker 是对于 MapReduce 执行而言的
mapreduce 中几个主要概念,mapreduce 整体上可以分为这么几条执行线索:
jobclient,JobTracker 与 TaskTracker。
1、JobClient 会在用户端通过 JobClient 类将应用已经配置参数打包成 jar 文件存储到 hdfs,并把路径提交到 Jobtracker,然后由 JobTracker 创建每一个 Task(即 MapTask 和 ReduceTask)并将它们分发到各个 TaskTracker 服务中去执行
2、JobTracker 是一个 master 服务,软件启动之后 JobTracker 接收 Job,负责调度 Job 的每一个子任务 task运行于 TaskTracker 上,并监控它们,如果发现有失败的 task 就重新运行它。一般情况应该把 JobTracker 部署在单独的机器上。
3、TaskTracker 是运行在多个节点上的 slaver 服务。TaskTracker 主动与 JobTracker 通信,接收作业,并负责直接执行每一个任务。TaskTracker 都需要运行在 HDFS 的 DataNode 上
HDFS 默认 Block Size
- a)32MB
- b)64MB
- c)
128MB
- 注:旧版本是64MB
Client 端上传文件的时候下列哪项正确
- a)数据经过 NameNode 传递给 DataNode
- b)
Client 端将文件切分为 Block,依次上传
- c)Client 只上传数据到一台 DataNode,然后由 NameNode 负责 Block 复制工作
Client 向 NameNode 发起文件写入的请求。
NameNode 根据文件大小和文件块配置情况,返回给 Client 它所管理部分 DataNode 的信息。
Client 将文件划分为多个 Block,根据 DataNode 的地址信息,按顺序写入到每一个 DataNode 块中。
下面与 HDFS 类似的框架是?
- A NTFS
- B FAT32
- C
GFS
- D EXT3
Ganglia 不仅可以进行监控,也可以进行告警。(正确)
- 解析:
- ganglia 作为一款最常用的 Linux 环境中的监控软件,它擅长的的是从节点中按照用户的需求以较低的代价采集数据。但是 ganglia 在预警以及发生事件后通知用户上并不擅长。最新的ganglia 已经有了部分这方面的功能。但是更擅长做警告的还有 Nagios。Nagios,就是一款精于预警、通知的软件。通过将 Ganglia 和Nagios 组合起来,把 Ganglia 采集的数据作为 Nagios 的数据源,然后利用 Nagios 来发送预警通知,可以完美的实现一整套监控管理的系统。
Nagios 不可以监控 Hadoop 集群,因为它不提供 Hadoop支持。(错误 )
- 分析:Nagios 是集群监控工具,而且是云计算三大利器之一
如果 NameNode 意外终止,SecondaryNameNode 会接替它使集群继续工作。(错误 )
- 分析:
SecondaryNameNode不是NameNode备份
- 功能:
在不影响NameNode对外提供服务的情况下,偷偷将内存元数据与文件元数据进行同步,加快下一次NameNode启动的进度
- 补充:
NameNode的备份还叫NameNode
- 一个是active的NameNode
- 一个是standby的NameNode
Cloudera CDH 是需要付费使用的。(错误)
- 分析:
- 第一套付费产品是 Cloudera Enterpris,Cloudera Enterprise 在美国加州举行的 Hadoop 大会 (HadoopSummit) 上公开,以若干私有管理、监控、运作工具加强 Hadoop 的功能。收费采取合约订购方式,价格随用的 Hadoop 叢集大小变动。
NameNode 负责管理 metadata,client 端每次读写请求,它都会从磁盘中读取或则会写入 metadata信息并反馈 client 端。(错误)
- 分析:
NameNode 不需要从磁盘读取 metadata,所有数据都在内存中,硬盘上的只是序列化的结果,只有每次namenode 启动的时候才会读取。
- 1)文件写入
- Client 向 NameNode 发起文件写入的请求。
- NameNode 根据文件大小和文件块配置情况,返回给 Client 它所管理部分 DataNode 的信息。
- Client 将文件划分为多个 Block,根据 DataNode 的地址信息,按顺序写入到每一个 DataNode 块中。
- 2)文件读取
- Client 向 NameNode 发起文件读取的请求
- NameNode 返回文件存储的 DataNode 的信息。
- Client 读取文件信息。
NameNode 本地磁盘保存了 Block 的位置信息。( 个人认为正确)
- 分析:
- DataNode 是文件存储的基本单元,它将 Block 存储在本地文件系统中,保存了 Block 的 Meta-data,同时周期性地将所有存在的 Block 信息发送给 NameNode。
DataNode 通过长连接与 NameNode 保持通信。错误
- 分析:
- 通过
心跳机制
。
- 通过
- 补充:
- (1)
长连接
- Client 方与 Server 方先建立通讯连接,连接
建立后不断开
,然后再进行报文发送和接收。这种方式下由于通讯连接一直存在,此种方式常用于点对点通讯。
- Client 方与 Server 方先建立通讯连接,连接
- (2)
短连接
- Client 方与 Server 每进行一次报文收发交易时才进行通讯连接,交易
完毕后立即断开连接
。此种方式常用于一点对多点通讯,比如多个 Client 连接一个 Server.
- Client 方与 Server 每进行一次报文收发交易时才进行通讯连接,交易
- (1)
Hadoop 自身具有严格的权限管理和安全措施保障集群正常运行。(错误)
Slave 节点要存储数据,所以它的磁盘越大越好。(错误)
- 分析:
- 一旦 Slave 节点宕机,数据恢复是一个难题
hadoop dfsadmin –report 命令用于检测 HDFS 损坏块。(错误)
- 分析:
- hadoop dfsadmin -report
- 可以快速定位出哪些节点 down 掉了
- HDFS 的容量以及使用了多少
- 以及每个节点的硬盘使用情况。
- 当然 NameNode 有个 http 页面也可以查询,但是这个命令的输出更适合我们的脚本监控 dfs 的使用状况
Hadoop 默认调度器策略为 FIFO(正确 )
FIFO:先进先出
- YARN中构建一个队列【管道:一头进,一头出】
- 所有提交的任务都按照提交的时间放到队列中
- 先放入的程序,享有整个YARN中的所有资源,
哪怕你用不了,那也是你的
- 直到先放进去的程序运行完成,才会运行第二个程序
- 特点
- 单队列,先进先出
运行的程序,享有所有资源
- 程序
不能并行也不能并发
并行:多个程序在不同的队列中同时运行
并发:在一个队列中多个程序同时运行
- 这种方式是Hadoop默认的调度方式
Capacity:容量调度机制
- YARN中构建多个队列,每个队列是FIFO
- 将整个YARN的资源分配到不同的队列中
- YARN:24core 24GB
- 队列1:12core 12GB
- 队列2:12Core 12GB
- 运行程序时,可以指定将程序提交到哪个队列中运行
- 特点
多队列,但是每个队列内部还是FIFO
- 并行运行多个程序,每个程序运行在不同的队列中
- 支持资源的动态抢占:
如果队列1的资源不够,队列2的资源非常充足,借队列2的资源来运行
- 程序1:队列1:13core13GB
- 队列2没有程序,队列1可以跟队列2借,程序
执行完成以后还回去
- 这种方式是Apache版本的Hadoop默认的调度方式
Fair:公平调度机制
- 这种方式是CDH版本的默认调度方式,也是工作中普遍使用的方式
- YARN中构建多个队列,每个队列是公平的共享资源的
- 每个队列里是可以同时运行多个程序的
- 支持一个队列中并发运行多个程序
- 第一个程序:会享有这个队列的所有资源
- 第二个程序:将当前空闲的资源与第二个程序进行平分
- |
- 让每个程序都能拿到资源
- 特点
多队列,队列内部的每个程序共享资源
允许一个队列中并发运行,运行多个队列并行运行
- 也
支持队列间的资源的动态抢占
指定队列程序的优先级
集群内每个节点都应该配 RAID,这样避免单磁盘损坏,影响整个节点运行。(错误)
- 分析:
- 首先明白什么是 RAID:磁盘阵列(Redundant Arrays of Independent Disks,RAID),有“独立磁盘构成的具有冗余能力的阵列”之意。
- 这句话错误的地方在于
太绝对
,具体情况具体分析。 - 因为
hadoop 本身就具有冗余能力
,所以如果不是很严格不需要都配备 RAID。
Hadoop 环境变量中的 HADOOP_HEAPSIZE 用于设置所有 Hadoop 守护线程的内存。它默认是 200 GB。( 错误)
- 分析:
- hadoop 为各个守护进程(namenode,secondarynamenode,jobtracker,datanode,tasktracker)统一分配的内存在 hadoop-env.sh 中设置,参数为 HADOOP_HEAPSIZE,默认为 1000M。
DataNode 首次加入 cluster 的时候,如果 log 中报告不兼容文件版本,那需要 NameNode执行―Hadoopnamenode -format‖操作格式化磁盘。(错误 )
- 分析:
- 这个报错是说明 DataNode 所装的 Hadoop 版本和其它节点不一致,应该检查 DataNode 的 Hadoop 版本
Block Size 是不可以修改的。(错误)
- 解析:
- Hadoop 的基础配置文件是 hadoop-default.xml,默认建立一个 Job 的时候会建立 Job 的 Config,Config
- 首先读入hadoop-default.xml的配置,然后再读入hadoop-site.xml的配置(这个文件初始的时候配置为空),
- hadoop-site.xml 中主要配置需要覆盖的 hadoop-default.xml 的系统级配置。具体配置可以参考下:
<property>
<name>dfs.block.size</name>
//block 的大小,单位字节,后面会提到用处,必须是 512 的倍数,因为采用 crc 作文件完整性校验,默认配置 512 是 checksum 的最小单元。
<value>5120000</value>
<description>The default block size for new files.</description>
</property>
Hadoop 支持数据的随机读写。(错)
- 分析:
- lucene 是支持随机读写的,而
hdfs 只支持随机读
。但是 HBase 可以来补救。 HBase 提供随机读写,来解决 Hadoop 不能处理的问题
。HBase 自底层设计开始即聚焦于各种可伸缩性问题:表可以很―高‖,有数十亿个数据行;也可以很―宽‖,有数百万个列
;水平分区并在上千个普通商用机节点上自动复制。表的模式是物理存储的直接反映,使系统有可能提高高效的数据结构的序列化、存储和检索。
- lucene 是支持随机读写的,而
因为 HDFS 有多个副本,所以 NameNode 是不存在单点问题的。(错误 )
- 分析:
副本针对DataName而讲的
Hadoop 是 Java 开发的,所以 MapReduce 只支持 Java 语言编写。(错误 )
- 分析:
支持c++等语言,需要通过接口。
每个 map 槽就是一个线程。(错误)
- 分析:
- 一个task对应一个线程
- 分析:首先我们知道什么是 map 槽,map 槽→map slot,
map slot 只是一个逻辑值
(org.apache.hadoop.mapred.TaskTracker.TaskLauncher.numFreeSlots ),而不是对应着一个线程或者进程
Mapreduce 的 input split 就是一个 block。(错误)
-
分析:
应该是一个block数组
-
1、运行mapred程序;
-
2、本次运行将生成一个Job,于是JobClient向JobTracker申请一个JobID以标识这个Job;
-
3、JobClient将Job所需要的资源提交到HDFS中一个以JobID命名的目录中。这些资源包括JAR包、配置文件、InputSplit、等;
-
4、JobClient向JobTracker提交这个Job;
-
5、JobTracker初始化这个Job;
-
6、JobTracker从HDFS获取这个Job的Split等信息;
-
7、JobTracker向TaskTracker分配任务;
-
8、TaskTracker从HDFS获取这个Job的相关资源;
-
9、TaskTracker开启一个新的JVM;
-
10、TaskTracker用新的JVM来执行Map或Reduce;
-
InputSplit也是一个interface,具体返回什么样的implement,这是由具体的InputFormat来决定的。InputSplit也只有两个接口函数:
- long getLength() throws IOException;
- String[] getLocations() throws IOException;
-
这个interface仅仅描述了Split有多长,以及存放这个Split的Location信息(也就是这个Split在HDFS上存放的机器。它可能有多个replication,存在于多台机器上)。除此之外,就再没有任何直接描述Split的信息了。比如:Split对应于哪个文件?在文件中的起始和结束位置是什么?等等重要的特征都没有描述到。
-
为什么会这样呢?因为关于Split的那些描述信息,对于MapReduce框架来说是不需要关心的。框架只关心Split的长度(主要用于一些统计信息)和Split的Location(主要用于Split的调度,后面会细说)。
-
而Split中真正重要的描述信息还是只有InputFormat会关心。在需要读取一个Split的时候,其对应的InputSplit会被传递到InputFormat的第二个接口函数getRecordReader,然后被用于初始化一个RecordReader,以解析输入数据。也就是说,描述Split的重要信息都被隐藏了,只有具体的InputFormat自己知道。它只需要保证getSplits返回的InputSplit和getRecordReader所关心的InputSplit是同样的implement就行了。这就给InputFormat的实现提供了巨大的灵活性。
hdfs的体系结构
- 解答:
- hdfs有
namenode、secondraynamenode、datanode
组成。 - 为n+1模式
namenode负责管理datanode和记录元数据
secondraynamenode负责合并日志
datanode负责存储数据
- hdfs有
简要描述如何安装配置一个apache开源版本hadoop,只描述即可,无需列出完整步骤,能列出步骤更好。
- 流程:
- 1.创建hadoop用户和用户组,用来管理hadoop项目
- 2.修改IP
vim /etc/sysconfig/network-scripts/ifcfg-eth0
- 3.修改主机名:
vim /etc/sysconfig/network
- 4.修改host主机名和ip地址映射:
vim /etc/hosts
- 5.查看防火墙状态并关闭防火墙:
#查看防火墙状态
service iptables status
#关闭防火墙
service iptables stop
#查看防火墙开机启动状态
chkconfig iptables --list
#关闭防火墙开机启动
chkconfig iptables off
- 6.安装ssh并配置免密码登录:
ssh-keygen -t rsa
执行完这个命令后,会生成两个文件id_rsa(私钥)、id_rsa.pub(公钥)
将公钥拷贝到要免登陆的机器上
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
或
ssh-copy-id -i localhost
- 7.安装JDK,并配置环境变量
tar -zxvf jdk**.tar.gz -C /user/java/ 修改/etc/profile文件,配置java环境变量
- 8.上传解压hadoop安装包
tar -zxvf hadoop....tar.gz
- 9.配置conf文件夹下的hadoop-env.sh,core-site.xml,hdfs-site.xml,mapred-site.xml,yarn-site.xml,slaves文件
- 10.安装配置zookeeper集群
- 11.格式namenode
hdfs namenode -format
启动hadoop集群时报下图错误,分析什么原因:
- 解答:
- 1、权限问题,可能曾经用root启动过集群。(例如hadoop搭建的集群,是tmp/hadoop-hadoop/…)
- 2、可能是文件夹不存在
- 3、解决: 删掉tmp下的那个文件,或改成当前用户
请列出hadoop的进程名称
- 解答:
- 1.namenode:管理集群,并记录datanode文件信息。
- 2.Secondname:可以做冷备,对一定范围内的数据做快照性备份。
- 3.Datanode:存储数据。
- 4.Jobtracker:管理任务,并将任务分配给tasktracker。
- 5.Tasktracker:任务执行者
Hadoop的核心配置是什么?
- 解答:
- Hadoop的核心配置通过两个xml文件来完成:
- 1.hadoop-default.xml;
- 2.hadoop-site.xml。
- 这些文件都使用xml格式,因此每个xml中都有一些属性,包括名称和值,但是当下这些文件都已不复存在。
那当下又该如何配置?
- 解答:
- Hadoop现在拥有3个配置文件:
- 1,core-site.xml;
- 2,hdfs-site.xml;
- 3,mapred-site.xml。
- 这些文件都保存在conf/子目录下。
“jps”命令的用处?
- 解答:
- 这个命令可以检查Namenode、Datanode、Task Tracker、 Job Tracker是否正常工作。
杀死一个 job?
- jps查询进程
- kill -9 job-id
加入一个新的存储节点和删除一个计算节点?
- 解答:
- 添加新节点:
- 1.将namenode的hadoop文件全部复制到新节点。
- 2.修改每个节点的hosts文件,将节点四的名字加入进去。
- 3.配置ssh免密登录,使得namenode登录新节点的时候不需要输入密码。
- 4.修改各节点的slaves文件,加入新节点的名称。
- 5.单独启动该节点上的Datanode进程和NodeManager进程。
- hadoop-daemon.sh start datanode
- yarn-daemon.sh start nodemanager
- 6.之后再去web ui上去看看,是否添加成功。
- 7.因为添加了新节点之后,其实整个集群的负载均衡机制是偏斜了的,因为你的新节点完全没有数据存在,所以这个时候应该执行一下,start-balancer.sh,重新平衡一下各个节点上数据块的分布
- 移除一个节点:
- 1.修改core-site.xml
- 配置dfs.hosts.exclude
- 2.修改hdfs-site.xml
- 配置dfs.hosts.exclude
- 3.在master上创建并修改excludes文件,添加需要删除节点的IP
- 4.在master上刷新节点配置情况
- hadoop dfsadmin -refreshnodes
- 10.删除 hdfs 上的/tmp/aaa 目录
- hdfs dfs -rmr /tmp/aaa
- 1.修改core-site.xml
请列出你所知道的 hadoop 调度器,并简要说明其工作方法?
- 解答:
- 1.FIFO schedular:先入先出调度器,hadoop1.x默认
- 队列方式将一个一个job任务按照时间先后顺序进行服务
- 1.YARN中构建一个队列【管道:一头进,一头出】
- 2.所有提交的任务都按照提交的时间放到队列中
- 3.先放入的程序,享有整个YARN中的所有资源,哪怕你用不了,那也是你的
- 4.直到先放进去的程序运行完成,才会运行第二个程序
- 特点
- 1.单队列,先进先出
- 2.运行的程序,享有所有资源
- 3.程序不能并行也不能并发
- 并行:多个程序在不同的队列中同时运行
- 并发:在一个队列中多个程序同时运行
- 2.Capacity schedular:容量调度器
- 1.YARN中构建多个队列,每个队列是FIFO
- 2.将整个YARN的资源分配到不同的队列中
- 3.运行程序时,可以指定将程序提交到哪个队列中运行
- 特点
- 1.多队列,但是每个队列内部还是FIFO
- 2.并行运行多个程序,每个程序运行在不同的队列中
- 3.支持资源的动态抢占:如果队列1的资源不够,队列2的资源非常充足,借队列2的资源来运行
- 3.Fair schedular:公平调度
- 1.YARN中构建多个队列,每个队列是公平的共享资源的
- 2.支持一个队列中并发运行多个程序
- 特点
- 1.多队列,队列内部的每个程序共享资源
- 2.允许一个队列中并发运行,运行多个队列并行运行
- 3.也支持队列间的资源的动态抢占
- 4.指定队列程序的优先级
hadoop框架中怎么来优化
- 解答:
- (1) 从应用程序角度进行优化。由于mapreduce是迭代逐行解析数据文件的,怎样在迭代的情况下,编写高效率的应用程序,是一种优化思路。
- (2) 对Hadoop参数进行调优。当前hadoop系统有190多个配置参数,怎样调整这些参数,使hadoop作业运行尽可能的快,也是一种优化思路。
- (3) 从系统实现角度进行优化。这种优化难度是最大的,它是从hadoop实现机制角度,发现当前Hadoop设计和实现上的缺点,然后进行源码级地修改。该方法虽难度大,但往往效果明显。
- (4)linux内核参数调整
1.使用自定义Writable
- 自带的Text很好用,但是字符串转换开销较大,故根据实际需要自定义Writable,注意作为Key时要实现WritableCompareable接口
- 避免output.collect(new Text( ),new Text())
- 提倡key.set( ) value.set( ) output.collect(key,value)
- 前者会产生大量的Text对象,使用完后Java垃圾回收器会花费大量的时间去收集这些对象
2. 使用StringBuilder
- 不要使用Formatter StringBuffer( 线程安全)
- StringBuffer尽量少使用多个append方法,适当使用+
3. 使用DistributedCache加载文件
- 比如配置文件,词典,共享文件,避免使用static变量
4. 充分使用Combiner Parttitioner Comparator。
- Combiner : 对map任务进行本地聚合
- Parttitioner : 合适的Parttitioner避免reduce端负载不均
- Comparator : 二次排序
- 比如求每天的最大气温,map结果为日期:气温,若气温是降序的,直接取列表首元素即可
5. 使用自定义InputFormat和OutputFormat
6. MR应避免
- 静态变量:不能用于计数,应使用Counter
- 大对象:Map List
- 递归:避免递归深度过大
- 超长正则表达式:消耗性能,要在map或reduce函数外编译正则表达式
- 不要创建本地文件:变向的把HDFS里面的数据转移到TaskTracker,占用网络带宽
- 不要大量创建目录和文件
- 不要大量使用System.out.println,而使用Logger
- 不要自定义过多的Counter,最好不要超过100个
- 不要配置过大内存,mapred.child.java.opts -Xmx2000m是用来设置mapreduce任务使用的最大heap量
7.关于map的数目
- map数目过大[创建和初始化map的开销],一般是由大量小文件造成的,或者dfs.block.size设置的太小,对于小文件可以archive文件或者Hadoop fs -merge合并成一个大文件.
- map数目过少,造成单个map任务执行时间过长,频繁推测执行,且容易内存溢出,并行性优势不能体现出来。dfs.block.size一般为256M-512M
- 压缩的Text 文件是不能被分割的,所以尽量使用SequenceFile,可以切分
8.关于reduce的数目
- reduce数目过大,产生大量的小文件,消耗大量不必要的资源,reduce数目过低呢,造成数据倾斜问题,且通常不能通过修改参数改变。
- 可选方案:mapred.reduce.tasks设为-1变成AutoReduce。
- Key的分布,也在某种程度上决定了Reduce数目,所以要根据Key的特点设计相对应的Parttitioner 避免数据倾斜
9.Map-side相关参数优化
- io.sort.mb(100MB):通常k个map tasks会对应一个buffer,buffer主要用来缓存map部分计算结果,并做一些预排序提高map性能,若map输出结果较大,可以调高这个参数,减少map任务进行spill任务个数,降低 I/O的操作次数。若map任务的瓶颈在I/O的话,那么将会大大提高map性能。如何判断map任务的瓶颈?
- io.sort.spill.percent(0.8):spill操作就是当内存buffer超过一定阈值(这里通常是百分比)的时候,会将buffer中得数据写到Disk中。而不是等buffer满后在spill,否则会造成map的计算任务等待buffer的释放。一般来说,调整 io.sort.mb而不是这个参数。
- io.sort.factor(10):map任务会产生很多的spill文件,而map任务在正常退出之前会将这些spill文件合并成一个文件,即merger过程,缺省是一次合并10个参数,调大io.sort.factor,减少merge的次数,减少Disk I/O操作,提高map性能。
- min.num.spill.for.combine:通常为了减少map和reduce数据传输量,我们会制定一个combiner,将map结果进行本地聚集。这里combiner可能在merger之前,也可能在其之后。那么什么时候在其之前呢?当spill个数至少为min.num.spill.for.combine指定的数目时同时程序指定了Combiner,Combiner会在其之前运行,减少写入到Disk的数据量,减少I/O次数。
10.压缩(时间换空间)
- MR中的数据无论是中间数据还是输入输出结果都是巨大的,若不使用压缩不仅浪费磁盘空间且会消耗大量网络带宽。同样在spill,merge(reduce也对有一个merge)亦可以使用压缩。若想在cpu时间和压缩比之间寻找一个平衡,LzoCodec比较适合。通常MR任务的瓶颈不在CPU而在于I/O,所以大部分的MR任务都适合使用压缩。
11. reduce-side相关参数优化
- reduce:copy->sort->reduce,也称shuffle
- mapred.reduce.parellel.copies(5):任一个map任务可能包含一个或者多个reduce所需要数据,故一个map任务完成后,相应的reduce就会立即启动线程下载自己所需要的数据。调大这个参数比较适合map任务比较多且完成时间比较短的Job。
- mapred.reduce.copy.backoff:reduce端从map端下载数据也有可能由于网络故障,map端机器故障而失败。那么reduce下载线程肯定不会无限等待,当等待时间超过mapred.reduce.copy.backoff时,便放弃,尝试从其他地方下载。需注意:在网络情况比较差的环境,我们需要调大这个参数,避免reduce下载线程被误判为失败。
- io.sort.factor:recude将map结果下载到本地时,亦需要merge,如果reduce的瓶颈在于I/O,可尝试调高增加merge的并发吞吐,提高reduce性能、
- mapred.job.shuffle.input.buffer.percent(0.7):reduce从map下载的数据不会立刻就写到Disk中,而是先缓存在内存中,mapred.job.shuffle.input.buffer.percent指定内存的多少比例用于缓存数据,内存大小可通过mapred.child.java.opts来设置。和map类似,buffer不是等到写满才往磁盘中写,也是到达阈值就写,阈值由mapred.job,shuffle.merge.percent来指定。若Reduce下载速度很快,容易内存溢出,适当增大这个参数对增加reduce性能有些帮助。
- mapred.job.reduce.input.buffer.percent (0):当Reduce下载map数据完成之后,就会开始真正的reduce的计算,reduce的计算必然也是要消耗内存的,那么在读物reduce所需要的数据时,同样需要内存作为buffer,这个参数是决定多少的内存百分比作为buffer。默认为0,也就是说reduce全部从磁盘读数据。若redcue计算任务消耗内存很小,那么可以设置这个参数大于0,使一部分内存用来缓存数据。
13 从应用程序角度进行优化
- 解答:
- (1) 避免不必要的reduce任务
如果mapreduce程序中reduce是不必要的,那么我们可以在map中处理数据, Reducer设置为0。这样避免了多余的reduce任务。 - (2) 为job添加一个Combiner
为job添加一个combiner可以大大减少shuffle阶段从map task拷贝给远程reduce task的数据量。一般而言,combiner与reducer相同。 - (3) 根据处理数据特征使用最适合和简洁的Writable类型
Text对象使用起来很方便,但它在由数值转换到文本或是由UTF8字符串转换到文本时都是低效的,且会消耗大量的CPU时间。当处理那些非文本的数据时,可以使用二进制的Writable类型,如IntWritable, FloatWritable等。二进制writable好处:避免文件转换的消耗;使map task中间结果占用更少的空间。 - (4) 重用Writable类型
很多MapReduce用户常犯的一个错误是,在一个map/reduce方法中为每个输出都创建Writable对象。例如,你的Wordcout mapper方法可能这样写:
- (1) 避免不必要的reduce任务
public void map(...) {
…
for (String word : words) {
output.collect(new Text(word), new IntWritable(1));
}
}
这样会导致程序分配出成千上万个短周期的对象。Java垃圾收集器就要为此做很多的工作。更有效的写法是:
class MyMapper … {
Text wordText = new Text();
IntWritable one = new IntWritable(1);
public void map(...) {
for (String word: words) {
wordText.set(word);
output.collect(wordText, one);
}
}
}
- (5) 使用StringBuffer而不是String
当需要对字符串进行操作时,使用StringBuffer而不是String,String是read-only的,如果对它进行修改,会产生临时对象,而StringBuffer是可修改的,不会产生临时对象。
datanode在什么情况下不会备份
- 解答:
- 当备份数为1时。
combiner出现在那个过程
- 解答:
出现在map阶段的map方法后
3个datanode中有一个datanode出现错误会怎样?
这个datanode的数据会在其他的datanode上重新做备份。
hadoop 的 namenode 宕机,怎么解决
- 解答:
- 先分析宕机后的损失,宕机后直接导致client无法访问,内存中的元数据丢失,但是硬盘中的元数据应该还存在,如果只是节点挂了,重启即可,如果是机器挂了,重启机器后看节点是否能重启,不能重启就要找到原因修复了。但是最终的解决方案应该是在设计集群的初期就考虑到这个问题,做namenode的HA。
一个datanode 宕机,怎么一个流程恢复
- 解答:
- Datanode宕机了后,如果是
短暂的宕机,可以实现写好脚本监控,将它启动起来
。如果是长时间宕机了,那么datanode上的数据应该已经被备份到其他机器了,那这台datanode就是一台新的datanode了,删除他的所有数据文件和状态文件,重新启动。
请简述 hadoop 怎么样实现二级排序?
- 解答:
- 在Reduce阶段,先对Key排序,再对Value排序
- 最常用的方法是
将Value放到Key中,实现一个组合Key
,然后自定义Key排序规则
(为Key实现一个WritableComparable)。
如何使用MapReduce实现两个表join,可以考虑一下几种情况:(1)一个表大,一个表小(可放到内存中);(2)两个表都是大表?
- 解答:
- 第一种情况比较简单,
只需将小表放到DistributedCache中即可;
- 第二种情况常用的方法有:
map-side join(要求输入数据有序,通常用户Hbase中的数据表连接),reduce-side join,semi join(半连接)
- 第一种情况比较简单,
MapReduce中排序发生在哪几个阶段?这些排序是否可以避免?为什么?
- 解答:
- 一个MapReduce作业由Map阶段和Reduce阶段两部分组成,这两阶段会对数据排序,从这个意义上说,MapReduce框架本质就是一个Distributed Sort。在Map阶段,在Map阶段,
Map Task会在本地磁盘输出一个按照key排序(采用的是快速排序)的文件(中间可能产生多个文件,但最终会合并成一个)
,在Reduce阶段,每个Reduce Task会对收到的数据排序,这样,数据便按照Key分成了若干组,之后以组为单位交给reduce()处理
。很多人的误解在Map阶段,如果不使用Combiner便不会排序,这是错误的,不管你用不用Combiner,Map Task均会对产生的数据排序(如果没有Reduce Task,则不会排序, 实际上Map阶段的排序就是为了减轻Reduce端排序负载
)。由于这些排序是MapReduce自动完成的,用户无法控制,因此,在hadoop 1.x中无法避免,也不可以关闭,但hadoop2.x是可以关闭的。
- 一个MapReduce作业由Map阶段和Reduce阶段两部分组成,这两阶段会对数据排序,从这个意义上说,MapReduce框架本质就是一个Distributed Sort。在Map阶段,在Map阶段,
请简述 mapreduce 中,combiner,partition 作用?
- 解答:
combiner是reduce的实现,在map端运行计算任务,减少map端的输出数据
。- 作用就是优化。
但是combiner的使用场景是mapreduce的map输出结果和reduce输入输出一样
。
- partition的默认实现是
hashpartitio
n,是map端将数据按照reduce个数取余,进行分区,不同的reduce来copy自己的数据。
- partition的作用是
将数据分到不同的reduce进行计算,加快计算效果
。
- partition的作用是
- 1、
combiner最基本是实现本地key的聚合,对map输出的key排序,value进行迭代
。如下所示:- map: (K1, V1) → list(K2, V2)
- combine: (K2, list(V2)) → list(K2, V2)
- reduce: (K2, list(V2)) → list(K3, V3)
- 2、
combiner还具有类似本地的reduce功能.
- 例如hadoop自带的wordcount的例子和找出value的最大值的程序,combiner和reduce完全一致。如下所示:
- map: (K1, V1) → list(K2, V2)
- combine: (K2, list(V2)) → list(K3, V3)
- reduce: (K3, list(V3)) → list(K4, V4)
- 3、
如果不用combiner,那么,所有的结果都是reduce完成,效率会相对低下。使用combiner,先完成的map会在本地聚合,提升速度。
- 4、
对于hadoop自带的wordcount的例子,value就是一个叠加的数字,所以map一结束就可以进行reduce的value叠加,而不必要等到所有的map结束再去进行reduce的value叠加。
- combiner使用的合适,可以在满足业务的情况下提升job的速度,
如果不合适,则将导致输出的结果不正确。
- combiner使用的合适,可以在满足业务的情况下提升job的速度,
用mapreduce怎么处理数据倾斜问题?
- 解答:
- 数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),
这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜
。
- 数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),
- 用hadoop程序进行数据关联时,常碰到数据倾斜的情况,这里提供一种解决方法。
自己实现partition类,用key和value相加取hash值:
- 方式1:
- 源代码:
public int getPartition(K key, V value,
int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
- 修改后
public int getPartition(K key, V value,
int numReduceTasks) {
return (((key).hashCode()+value.hashCode()) & Integer.MAX_VALUE) % numReduceTasks;
}
- 方式2:
public class HashPartitioner<K, V> extends Partitioner<K, V> {
private int aa= 0;
/** Use {@link Object#hashCode()} to partition. */
public int getPartition(K key, V value,
int numReduceTasks) {
return (key.hashCode()+(aa++) & Integer.MAX_VALUE) % numReduceTasks;
}
hadoop中Combiner的作用?
- 解答:
- combiner是reduce的实现,在map端运行计算任务,
减少map端的输出数据
。 - 作用就是
优化
。 - 但是
combiner的使用场景是mapreduce的map和reduce输入输出一样。
- combiner是reduce的实现,在map端运行计算任务,
Mapreduce 的 map 数量 和 reduce 数量 怎么确定 ,怎么配置
- 解答:
map的数量有数据块决定,reduce数量随便配置
。
在hadoop中文件的压缩带来了两大好处:
- 解答:
- (1)它
减少了存储文件所需的空间
; - (2)
加快了数据在网络上或者从磁盘上或到磁盘上的传输速度
;
- (1)它
mapreduce的调度模式()
- 解答:
- 一个MapReduce作业的生命周期大体分为5个阶段 【1】 :
- 1.
作业提交与初始化
- 2.
任务调度与监控
- 3.
任务运行环境准备
- 4.
任务执行
- 5.
作业完成
- 1.
- 我们假设JobTracker已经启动,那么调度器是怎么启动的?JobTracker在启动时有以下代码:
JobTracker tracker = startTracker(new JobConf());
tracker.offerService();
- 其中offerService方法负责启动JobTracker提供的各个服务,有这样一行代码:
taskScheduler.start();
- taskScheduler即为任务调度器。start方法是抽象类TaskScheduler提供的接口,用于启动调度器。每个调度器类都要继承TaskScheduler类。回忆一下,调度器启动时会将各个监听器对象注册到JobTracker,以FIFO调度器JobQueueTaskScheduler为例:
@Override
public synchronized void start() throws IOException {
super.start();
taskTrackerManager.addJobInProgressListener(jobQueueJobInProgressListener);
eagerTaskInitializationListener.setTaskTrackerManager(taskTrackerManager);
eagerTaskInitializationListener.start();
taskTrackerManager.addJobInProgressListener(
eagerTaskInitializationListener);
}
- 这里注册了两个监听器,其中eagerTaskInitializationListener负责作业初始化,而jobQueueJobInProgressListener则负责作业的执行和监控。当有作业提交到JobTracker时,JobTracker会执行所有订阅它消息的监听器的jobAdded方法。对于eagerTaskInitializationListener来说:
@Override
public void jobAdded(JobInProgress job) {
synchronized (jobInitQueue) {
jobInitQueue.add(job);
resortInitQueue();
jobInitQueue.notifyAll();
}
}
- 提交的作业的JobInProgress对象被添加到作业初始化队列jobInitQueue中,并唤醒初始化线程(若原来没有作业可以初始化):
class JobInitManager implements Runnable {
public void run() {
JobInProgress job = null;
while (true) {
try {
synchronized (jobInitQueue) {
while (jobInitQueue.isEmpty()) {
jobInitQueue.wait();
}
job = jobInitQueue.remove(0);
}
threadPool.execute(new InitJob(job));
} catch (InterruptedException t) {
LOG.info("JobInitManagerThread interrupted.");
break;
}
}
threadPool.shutdownNow();
}
}
- 这种工作方式是一种“生产者-消费者”模式:作业初始化线程是消费者,而监听器eagerTaskInitializationListener是生产者。这里可以有多个消费者线程,放到一个固定资源的线程池中,线程个数通过mapred.jobinit.threads参数配置,默认为4个。
- 下面我们重点来看调度器中的另一个监听器。 jobQueueJobInProgressListener对象在调度器中初始化时连续执行了两个构造器完成初始化:
public JobQueueJobInProgressListener() {
this(new TreeMap<JobSchedulingInfo,
JobInProgress>(FIFO_JOB_QUEUE_COMPARATOR));
}
/**
* For clients that want to provide their own job priorities.
* @param jobQueue A collection whose iterator returns jobs in priority order.
*/
protected JobQueueJobInProgressListener(Map<JobSchedulingInfo,
JobInProgress> jobQueue) {
this.jobQueue = Collections.synchronizedMap(jobQueue);
}
- 其中,第一个构造器调用重载的第二个构造器。可以看到,调度器使用一个队列jobQueue来保存提交的作业。这个队列使用一个TreeMap对象实现,TreeMap的特点是底层使用红黑树实现,可以按照键来排序,并且由于是平衡树,效率较高。作为键的是一个JobSchedulingInfo对象,作为值就是提交的作业对应的JobInProgress对象。另外,由于TreeMap本身不是线程安全的,这里使用了集合类的同步方法构造了一个线程安全的Map。使用带有排序功能的数据结构的目的是使作业在队列中按照优先级的大小排列,这样每次调度器只需从队列头部获得作业即可。
- 作业的顺序由优先级决定,而优先级信息包含在JobSchedulingInfo对象中:
static class JobSchedulingInfo {
private JobPriority priority;
private long startTime;
private JobID id;
...
}
- 该对象包含了作业的优先级、ID和开始时间等信息。在Hadoop中,作业的优先级有以下五种:VERY_HIGH、HIGH、NORMAL、LOW、VERY_LOW。这些字段是通过作业的JobStatus对象初始化的。由于该对象作为TreeMap的键,因此要实现自己的equals方法和hashCode方法:
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != JobSchedulingInfo.class) {
return false;
} else if (obj == this) {
return true;
}
else if (obj instanceof JobSchedulingInfo) {
JobSchedulingInfo that = (JobSchedulingInfo)obj;
return (this.id.equals(that.id) &&
this.startTime == that.startTime &&
this.priority == that.priority);
}
return false;
}
- 我们看到,两个JobSchedulingInfo对象相等的条件是类型一致,并且作业ID、开始时间和优先级都相等。hashCode的计算比较简单:
@Override
public int hashCode() {
return (int)(id.hashCode() * priority.hashCode() + startTime);
}
- 注意,监听器的第一个构造器有一个比较器参数,用于定义 JobSchedulingInfo的比较方式:
static final Comparator<JobSchedulingInfo> FIFO_JOB_QUEUE_COMPARATOR
= new Comparator<JobSchedulingInfo>() {
public int compare(JobSchedulingInfo o1, JobSchedulingInfo o2) {
int res = o1.getPriority().compareTo(o2.getPriority());
if (res == 0) {
if (o1.getStartTime() < o2.getStartTime()) {
res = -1;
} else {
res = (o1.getStartTime() == o2.getStartTime() ? 0 : 1);
}
}
if (res == 0) {
res = o1.getJobID().compareTo(o2.getJobID());
}
return res;
}
};
- 从上面看出,首先比较作业的优先级,若优先级相等则比较开始时间(FIFO),若再相等则比较作业ID。 我们在实现自己的调度器时可能要定义自己的作业队列,那么作业在队列中的顺序(即 JobSchedulingInfo的比较器 )就要仔细定义,这是调度器能够正常运行基础。
- Hadoop中的作业调度采用pull方式,即TaskTracker定时向JobTracker发送心跳信息索取一个新的任务,这些信息包括数据结点上作业和任务的运行情况,以及该TaskTracker上的资源使用情况。JobTracker会依据以上信息更新作业队列的状态,并调用调度器选择一个或多个任务以心跳响应的形式返回给TaskTracker。从上面描述可以看出,JobTracker和taskScheduler之间的互相利用关系:前者利用后者为TaskTracker分配任务;后者利用前者更新队列和作业信息。接下来,我们一步步详述该过程。
- 首先,当一个心跳到达JobTracker时(实际上这是一个来自TaskTracker的远程过程调用 heartbeat方法 ,协议接口是InterTrackerProtocol),会执行两种动作:更新状态和下达命令 【1】 。下达命令稍后关注。有关更新状态的一些代码片段如下:
if (!processHeartbeat(status, initialContact, now)) {
if (prevHeartbeatResponse != null) {
trackerToHeartbeatResponseMap.remove(trackerName);
}
return new HeartbeatResponse(newResponseId,
new TaskTrackerAction[] {new ReinitTrackerAction()});
}
- 具体的心跳处理,由私有函数processHeartbeat完成。该函数中有以下两个方法调用:
updateTaskStatuses(trackerStatus);
updateNodeHealthStatus(trackerStatus, timeStamp);
分别用来更新任务的状态和结点的健康状态。在第一个方法中有下面代码片段:
TaskInProgress tip = taskidToTIPMap.get(taskId);
// Check if the tip is known to the jobtracker. In case of a restarted
// jt, some tasks might join in later
if (tip != null || hasRestarted()) {
if (tip == null) {
tip = job.getTaskInProgress(taskId.getTaskID());
job.addRunningTaskToTIP(tip, taskId, status, false);
}
// Update the job and inform the listeners if necessary
JobStatus prevStatus = (JobStatus)job.getStatus().clone();
// Clone TaskStatus object here, because JobInProgress
// or TaskInProgress can modify this object and
// the changes should not get reflected in TaskTrackerStatus.
// An old TaskTrackerStatus is used later in countMapTasks, etc.
job.updateTaskStatus(tip, (TaskStatus)report.clone());
JobStatus newStatus = (JobStatus)job.getStatus().clone();
// Update the listeners if an incomplete job completes
if (prevStatus.getRunState() != newStatus.getRunState()) {
JobStatusChangeEvent event =
new JobStatusChangeEvent(job, EventType.RUN_STATE_CHANGED,
prevStatus, newStatus);
updateJobInProgressListeners(event);
}
} else {
LOG.info("Serious problem. While updating status, cannot find taskid "
+ report.getTaskID());
}
- 这里的job对象通过从TaskTracker那里得到的task状态信息中抽取出来。注意,这里拷贝了原有作业状态的一个副本,然后修改这个副本的相关信息,调用的是updateJobStatus方法,更新任务的状态信息和JobInProgress的相关信息,如map和reduce任务的进度等,这里不展开了。这些信息的更新可以为调度器的工作提供依据。
- 作业状态的更新是通过updateJobInProgressListeners方法实现,该方法的参数是一个JobStatusChangeEvent对象,表示作业状态变化的事件。这种事件的类型可以是运行状态改变、开始时间改变、优先级改变等等。用户也可以根据需要自定义事件类型。事件对象维护了两个JobStatus对象,分别表示事件发生前后作业的状态。
- 进入该方法后,我们又看到了熟悉的观察者模式:
// Update the listeners about the job
// Assuming JobTracker is locked on entry.
private void updateJobInProgressListeners(JobChangeEvent event) {
for (JobInProgressListener listener : jobInProgressListeners) {
listener.jobUpdated(event);
}
}
- 这次每个监听器要回调jobUpdated方法,表示作业有更新。对于jobQueueJobInProgressListener来说是这样做的:
@Override
public synchronized void jobUpdated(JobChangeEvent event) {
JobInProgress job = event.getJobInProgress();
if (event instanceof JobStatusChangeEvent) {
// Check if the ordering of the job has changed
// For now priority and start-time can change the job ordering
JobStatusChangeEvent statusEvent = (JobStatusChangeEvent)event;
JobSchedulingInfo oldInfo =
new JobSchedulingInfo(statusEvent.getOldStatus());
if (statusEvent.getEventType() == EventType.PRIORITY_CHANGED
|| statusEvent.getEventType() == EventType.START_TIME_CHANGED) {
// Make a priority change
reorderJobs(job, oldInfo);
} else if (statusEvent.getEventType() == EventType.RUN_STATE_CHANGED) {
// Check if the job is complete
int runState = statusEvent.getNewStatus().getRunState();
if (runState == JobStatus.SUCCEEDED
|| runState == JobStatus.FAILED
|| runState == JobStatus.KILLED) {
jobCompleted(oldInfo);
}
}
}
}
- 首先,获取作业更新 前 的状态。然后根据事件的类型,进行相应的处理。比如,如果优先级变化了,则要重新排列队列中作业的顺序。这里直接取出原有作业,重新插入队列。插入后,作业会自动重新排序,体现了TreeMap的优越性。再比如,如果作业状态变为完成,那么就从队列中删除该作业。
private void reorderJobs(JobInProgress job, JobSchedulingInfo oldInfo) {
synchronized (jobQueue) {
jobQueue.remove(oldInfo);
jobQueue.put(new JobSchedulingInfo(job), job);
}
}
- 下面就是调度器中最关键的一步了:任务选择。此时,作业队列中信息已经更新完毕,可以选择一些任务返回给TaskTracker执行了。heartbeat方法接下来会有这样的代码:
List<Task> tasks = getSetupAndCleanupTasks(taskTrackerStatus);
if (tasks == null ) {
tasks = taskScheduler.assignTasks(taskTrackers.get(trackerName));
}
Hadoop的三大分布式模块及功能分别是什么?
- 解答:
- 1.
HDFS:分布式文件系统
- 实现大数据的
存储
- 提供高吞吐量的数据访问
- 实现大数据的
- 2.
MapReduce:分布式计算模型
- 用于并行化处理大量数量,基于yarn
- 3.
Yarn:分布式资源管理和任务调度框架
- 对外提供统一的运行资源平台
- 负责给yarn中运行的程序提供资源
- 决定多个程序运行顺序及所需资源
- 1.
什么情况下需要编译Hadoop?
- 解答:
- 1.
官方版本有阉割,部分功能缺失
- 2.
对官方版本的某些功能不满意
- 1.
SecondaryNameNode
hdfs写流程
- 流程:
- 1-客户端读取配置文件,找到NameNode的地址
- 2-客户端向NameNode发送写入请求
- 3-NameNode会检查是否允许写入将确认同意写入的,结果返回给客户端
- 检查文件是否存在
- 是否有权限
- 存储路径是否存在
- 有没有DataNode可以存储
- 4-客户端会将大文件进行拆分成若干个小文件
- 5-提交第一个块写入的请求给NameNode
- 6-NameNode根据当前集群的情况以及副本的个数,返回三台DataNode的地址
- NameNode会根据副本:3份
- 根据机架感知做基本计算:
- 如果客户端所在的机器也是DataNode会存储一份
- 以后如果客户端这台机器进行读的时候,可以直接从本机快速读取
- 与客户端在同一个机架的另外一台机器也会存储一份
- 如果客户端这台机器宕机,从同机架获取这个块,是最快的
- 另外一个机架的一台机器也会存储一份
- 如果第一个机架全部宕机,另外一个机架照样有一份可以用
- 如果客户端所在的机器也是DataNode会存储一份
- 7-客户端拿到这三台DataNode的地址,通过机架感知,选择最近的一台进行写入块
- 8-客户端将整个块分成很多小的部分,每个部分挨个发送给DataNode
- 9-最近的DataNode接受到写入请求,将这个数据同步给其他两个DataNode
- 10-所有的DataNode写入完成逐级返回ack确认,客户端接受到ack,发送下一个小的部分,直到整个块发送完成
- 11-客户端重复第5步,提交下一个块的写入请求,直到整个文件所有块写完成
hdfs读流程
- 1-客户端向NameNode请求读取一个文件
- 2-NameNode检查元数据
- 3-返回这个文件对应的所有的块的所有的DataNode地址
- 4-客户端根据地址列表,计算出每个块离自己最近的那台DataNode
- 5-到离自己最近的每台机器,取对应的块
- 6-将每个块进行合并
举一个简单的例子说明mapreduce是怎么来运行的 ?
- Input:/wordcount/input/wordcount.txt
将每一行数据变成一个keyvalue
value就是这一行的内容
- Map:
- map:
将value进行分割,得到每个单词,将单词作为key,1作为value输出
- map:
- Shuffle:自动实现的,不用管
- 分组:按照单词做分组,
相同单词的value都在一个迭代器中
- 排序:按照单词做排序
- 分组:按照单词做分组,
- Reduce
- reduce:
对每个单词的迭代器中进行聚合
- reduce:
- Output:/wordcount/output4
mr之shuffle详解
mr流程图
yarn流程
- 1-客户端提交请求给RM
- 2-RM会随机选择一台机器启动这个程序的APPMaster ,负责管理这个程序
- 3-APPMaster启动以后会向RM申请资源和指令
- 4-RM将每台机器要启动的Task和能使用的资源封装在Container中返回给APPMaster
- 5-APPMaster会通知对应的NodeManager启动MapTask并执行
- 6-所有的MapTask执行完成通知APPMaster
- 7-APPMaster启动ReduceTask
- 8-Reduce到每个MapTask机器上取数据,执行处理
- 9-Reduce执行结束通知APPMaster
- 10-APPMaster将结果返回给ResourceManager
HDFS的HA架构
行式存储VS列式存储
行式存储
- 优点:insert/update比较方便
- 缺点:
- 不同类型数据存放在同一个block中,压缩性能不好;
- 针对条件是某列的查询会读取所有数据
列式存储
- 优点:
- 同类型数据存放在同一个block中,压缩性能好
- 查询时只有涉及的列会被读取
- 任何列都能做为索引
- 缺点
- 针对全表查询,需要数据重组
- insert/update比较麻烦
Hadoop集群中其中一台DataNode节点的磁盘快满了怎么处理?
基本策略就是首先迁移数据,删除无用数据,都弄完还是不能满足,就只能加磁盘。
- 场景1: DN节点单块磁盘坏了
- 数据移走,移到空闲盘,然后做均衡让DN自己去识别
- 场景2:DN节点的所有盘都快满了
- 方法一:删除数据 ,rebalance
- 方法二:加磁盘,不能直接加,因为还是会往旧磁盘写数据,越写越多,需要调整往多磁盘写数据的策略,默认是轮询写,需要改为优先写剩余磁盘空间多的磁盘策略
- 场景3:应用程序误放在DN节点上,把系统盘或者数据盘占满了
- 联系应用owner,停程序,把数据移走,之后要么改程序要么做软连接
- 场景4:不要的数据
- 节点退集群后,直接删除