Hadoop作为大数据行业的最原始也是应用最为广泛的组件,兼容存储与计算两方面的功能,在大数据岗位的面试中基本也是必问的。
高频问题
HDFS读写流程、Shuffle过程、Map&Reduce流程、Yarn工作机制、Hadoop数据倾斜问题、Hadoop小文件问题
1-Hadoop定义
Hadoop,就是解决⼤数据时代下海量数据的存储和分析计算问题。Hadoop不是指具体的⼀个框架或者组件,它是Apache软件基⾦会下⽤Java语⾔开发的⼀个开源分布式 计算平台,实现在⼤量计算机组成的集群中对海量数据进⾏分布式计算,适合⼤数据的分布式存储和计算,从⽽有效弥补了传统数据库在海量数据下的不⾜。
Hadoop Common:支持其他Hadoop模块的常用工具。
Hadoop分布式文件系统(HDFS™):一种分布式文件系统,可提供对应用程序数据的高吞吐量访问。
Hadoop YARN:作业调度和集群资源管理的框架。
Hadoop MapReduce:一种用于并行处理大型数据集的基于YARN的系统。
上述每个模块有自己独立的功能,而模块之间又有相互的关联。
2-Hadoop常用端口号
hadoop2.x | Hadoop3.x | |
访问HDFS端口 | 50070 | 9870 |
访问MR执行情况端口 | 8088 | 8088 |
历史服务器 | 19888 | 19888 |
客户端访问集群端口 | 9000 | 8020 |
3-Hadoop配置文件以及简单的Hadoop集群搭建
(1)配置文件:
Hadoop2.x core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml slaves Hadoop3.x core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml workers
(2)简单的集群搭建过程:
JDK安装
配置SSH免密登录
配置hadoop核心文件:
格式化namenode
4-HDFS读流程和写流程
第一步:客户端请求namenode需要读取一个文件。 第二步:namenode校验客户端的权限问题以及文件是否存在等问题。如果校验不通过,直接给客户端抛异常即可。如果校验通过,namenode会返回给客户端这个文件的部分或者全部的block块列表元数据。 第三步:客户端拿到部分或者全部的block块列表之后,开始与datanode进行通信。 第四步:客户端可以开启多线程与datanode进行通信,请求读取数据。与datanode建立连接之后,开始读取数据。 第五步:所有的block块全部读取完成之后,客户端将所有的block块进行拼接,形成一个完整的文件。
因为block块数据写入是串行的,但是block块数据的读取是并行的。
并行提高数据访问速度,串行确保数据的完整性
第一步:client 发起文件上传请求,通过 RPC 与 NameNode 建立通讯,NameNode 检查目标文件是否已存在,父目录是否存在,返回是否可以上传;
第二步:client 请求第一个 block 该传输到哪些 DataNode 服务器上;
第三步:NameNode 根据配置文件中指定的备份数量及副本放置策略进行文件分配,返回可用的 DataNode 的地址,如:A,B,C;
第四步:client 请求3台 DataNode 中的一台A上传数据(本质上是一个 RPC 调用,建立 pipeline),A收到请求会继续调用B,然后B调用C,将整个 pipeline 建立完成,后逐级返回 client;
第五步:client 开始往A上传第一个 block(先从磁盘读取数据放到一个本地内存缓存),以 packet 为单位(默认64K),A收到一个 packet 就会传给B,B传给C;A每传一个 packet 会放入一个应答队列等待应答。
第六步:数据被分割成一个个 packet 数据包在 pipeline 上依次传输,在 pipeline 反方向上,逐个发送 ack(ack 应答机制),最终由pipeline中第一个 DataNode 节点A将 pipeline ack 发送给client;
第七步:当一个 block 传输完成之后,client 再次请求 NameNode 上传第二个 block 到服务器,重复上述步骤直到传输完毕
5- Hadoop的Shuffle过程及优化
定义:map 和 reduce 之间混洗的过程。为了让来自相同 Key 的所有数据都在同一个 reduce 中处理, 需要执行一个 all-to-all 的操作, 需要在不同的节点(不同的分区)之间拷贝数据,必须跨分区聚集相同 Key 的所有数据, 这个过程叫做 Shuffle。
优化点如图:
过程:数据首先进入到getPartition()
方法分区,把数据标记好分区,然后写入到环形缓冲区。环形缓冲区达到80%以后反向溢写(给溢写留出时间,不至于等待),溢写之前对数据进行排序,按照key的索引排序(第一次),手段为快速排序。溢写会产生大量的溢写文件,需要对文件进行归并排序(第二次),对溢写的文件也可以先进行combiner操作,最后将文件按照分区存储在磁盘,等待reduce端拉取。溢出写过程按轮询方式将缓冲区中的内容写到mapreduce.cluster.local.dir属性指定的目录中。当整个map任务完成溢出写后,会对磁盘中这个map任务产生的所有临时文件(spill.out文件),相应的缓冲区中的索引区数据溢出为磁盘索引文件spill.out.index,进行归并(第三次)(merge)操作生成最终的正式输出文件
6-Map&Reduce过程
第一阶段:把输入目录下文件按照一定的标准逐个进行逻辑切片,形成切片规划。
默认Split size = Block size(128M),每一个切片由一个MapT ask处理。(getSplits)
第二阶段:对切片中的数据按照一定的规则读取解析返回<key,value>对。
默认是按行读取数据。key是每一行的起始位置偏移量,value是本行的文本内容。(TextInputFormat)
第三阶段:调用Mapper类中的map方法处理数据。
每读取解析出来的一个<key,value> ,调用一次map方法。
第四阶段:按照一定的规则对Map输出的键值对进行分区partition。默认不分区,因为只有一个reducetask。 分区的数量就是reducetask运行的数量。
第五阶段:Map输出数据写入内存缓冲区,达到比例溢出到磁盘上。溢出spill的时候根据key进行排序sort。默认根据key字典序排序。
第六阶段:对所有溢出文件进行最终的merge合并,成为一个文件。
第一阶段:ReduceT ask会主动从MapTask复制拉取属于需要自己处理的数据。
第二阶段:把拉取来数据,全部进行合并merge,即把分散的数据合并成一个大的数据。再对合并后的数据排序。
第三阶段:对排序后的键值对调用reduce方法。键相等的键值对调用一次reduce方法。最后把这些输出的键值对写入到HDFS文件中。
7-Hadoop-MapReduce优化
1)Map阶段
(1)增大环形缓冲区大小。由100m扩大到200m
(2)增大环形缓冲区溢写的比例。由80%扩大到90%
(3)减少对溢写文件的merge次数。(10个文件,一次20个merge)
(4)不影响实际业务的前提下,采用Combiner提前合并,减少 I/O。
2)Reduce阶段
(1)合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致 Map、Reduce任务间竞争资源,造成处理超时等错误。
(2)设置Map、Reduce共存:调整slowstart.completedmaps参数,使Map运行到一定程度后,Reduce也开始运行,减少Reduce的等待时间。
(3)规避使用Reduce,因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。
(4)增加每个Reduce去Map中拿数据的并行数
(5)集群性能可以的前提下,增大Reduce端存储数据内存的大小。
3)IO传输
采用数据压缩的方式,减少网络IO的的时间。安装Snappy和LZOP压缩编码器。
压缩:
(1)map输入端主要考虑数据量大小和切片,支持切片的有Bzip2、LZO。注意:LZO要想支持切片必须创建索引;
(2)map输出端主要考虑速度,速度快的snappy、LZO;
(3)reduce输出端主要看具体需求,例如作为下一个mr输入需要考虑切片,永久保存考虑压缩率比较大的gzip。
4)整体
(1)NodeManager默认内存8G,需要根据服务器实际配置灵活调整,例如128G内存,配置为100G内存左右,yarn.nodemanager.resource.memory-mb。
(2)单任务默认内存8G,需要根据该任务的数据量灵活调整,例如128m数据,配置1G内存,yarn.scheduler.maximum-allocation-mb。
(3)mapreduce.map.memory.mb :控制分配给MapTask内存上限,如果超过会kill掉进程(报:Container is running beyond physical memory limits. Current usage:565MB of512MB physical memory used;Killing Container)。默认内存大小为1G,如果数据量是128m,正常不需要调整内存;如果数据量大于128m,可以增加MapTask内存,最大可以增加到4-5g。
(4)mapreduce.reduce.memory.mb:控制分配给ReduceTask内存上限。默认内存大小为1G,如果数据量是128m,正常不需要调整内存;如果数据量大于128m,可以增加ReduceTask内存大小为4-5g。
(5)mapreduce.map.java.opts:控制MapTask堆内存大小。(如果内存不够,报:java.lang.OutOfMemoryError)
(6)mapreduce.reduce.java.opts:控制ReduceTask堆内存大小。(如果内存不够,报:java.lang.OutOfMemoryError)
(7)可以增加MapTask的CPU核数,增加ReduceTask的CPU核数
(8)增加每个Container的CPU核数和内存大小
(9)在hdfs-site.xml文件中配置多目录
(10)NameNode有一个工作线程池,用来处理不同DataNode的并发心跳以及客户端并发的元数据操作。dfs.namenode.handler.count=20 log2(Cluster Size),比如集群规模为10台时,此参数设置为60。
8-Yarn工作机制
- hadoop向resourcemanager发送请求,resourcemanager接收到请求,把请求交给asm,asm做一系列检查,如果检查后没有异样,asm把请求转发给调度器(scheduler)。
- scheduler为当前的job分配资源,随机的返回一个节点,比如nodemanager02。
- 请求到nodemanager02开启一个container。
- 开启mrappmaster。 mrappmaster向resourcemanager申请资源,为maptask和reducetask申请资源。
- RM向MRappmaster返回当前有资源的节点,比如是01和03节点。返回节点的规则:优先返回有数据的节点,Maptask任务执行个数由切片个数决定,切片---块---hdfs---某一个节点本地,前提条件是这个节点上有可用的资源,数据本地化:可以避免计算的时候数据的网络传输,提升计算性能。
- 去对应的节点上开启container和maptask任务。
- 先去01节点开启container,再在container中开启maptask任务,
- 去03节点开启container,再在container中开启maptask任务。
- 所有的maptask向rmappmaster汇报自己的运行状态和进度。
- mrappmaster会在所有的maptask执行了80%的时候开启reducetask任务。
- mrappmaster到对应的节点上开启reducetask
- 资源回收
- mrappmaster向resourcemanager注销自己。
9-Yarn调度器
1)Hadoop调度器重要分为三类:
FIFO 、Capacity Scheduler(容量调度器)和Fair Sceduler(公平调度器)。
Apache默认的资源调度器是容量调度器;
CDH默认的资源调度器是公平调度器。
2)区别:
FIFO调度器:支持单队列 、先进先出 生产环境不会用。
容量调度器:支持多队列。队列资源分配,优先选择资源占用率最低的队列分配资源;作业资源分配,按照作业的优先级和提交时间顺序分配资源;容器资源分配,本地原则(同一节点/同一机架/不同节点不同机架)
公平调度器:支持多队列,保证每个任务公平享有队列资源。资源不够时可以按照缺额分配。
3)在生产环境下怎么选择?
大厂:如果对并发度要求比较高,选择公平,要求服务器性能必须OK;
中小公司,集群服务器资源不太充裕选择容量。
4)在生产环境怎么创建队列?
- 调度器默认就1个default队列,不能满足生产要求。
- 按照框架:hive /spark/ flink 每个框架的任务放入指定的队列(企业用的不是特别多)
- 按照业务模块:登录注册、购物车、下单、业务部门1、业务部门2
5)创建多队列的好处?
(1)因为担心员工不小心,写递归死循环代码,把所有资源全部耗尽。
(2)实现任务的降级使用,特殊时期保证重要的任务队列资源充足。
业务部门1(重要)=》业务部门2(比较重要)=》下单(一般)=》购物车(一般)=》登录注册(次要)
10-容量调度器(Capacity Scheduler)
Capacity Scheduler是Yahoo开发的多用户调度器。
11-公平调度器(Fair Scheduler)
Fair Schedulere是Facebook开发的多用户调度器。
12-hadoop的优点
⾼可靠性:Hadoop按位存储和处理数据的能⼒值得⼈们信赖 ;
⾼扩展性:Hadoop是在可⽤的计算机集群间分配数据并完成计算任务,这些集群可以⽅便地扩展 到数以千计的节点中 ;
⾼效性:Hadoop能够在节点之间动态地移动数据,并保持各个节点的动态平衡,因此处理速度⾮ 常快 ;
⾼容错性:Hadoop能够⾃动保存数据的多个副本,并且能够⾃动将失败的任务重新分配
低成本:Hadoop是开源的,项⽬的软件成本因⽽得以⼤⼤降低;
13-Hadoop宕机
1)如果MR造成系统宕机。此时要控制Yarn同时运行的任务数,和每个任务申请的最大内存。调整参数:yarn.scheduler.maximum-allocation-mb(单个任务可申请的最多物理内存量,默认是8192MB)
2)如果写入文件过快造成NameNode宕机。那么调高Kafka的存储大小,控制从Kafka到HDFS的写入速度。例如,可以调整Flume每批次拉取数据量的大小参数batchsize。。
14-Hadoop数据倾斜方法
原因:
1)、key分布不均匀 2)、业务数据本身的特性 3)、建表时考虑不周 4)、某些SQL语句本身就有数据倾斜
表现:我们的数据分散度不够,导致大量的数据集中到了一台或者几台服务节点上
1、分析节点资源管理器,如果大部分节点已经执行完成,而个别节点长时间执行不完,很可能发生了数据倾斜;
2、分析执行日志,作业在reduce阶段停留在99%,很长时间完成不了,很可能发生了数据倾斜。
解决:
- 局部聚合加全局聚合。
第一次在map阶段对那些导致了数据倾斜的key 加上1到n的随机前缀,这样本来相同的key 也会被分到多个Reducer中进行局部聚合
第二次mapreduce,去掉key的随机前缀,进行全局聚合。
思想:二次mr,第一次将key随机散列到不同reducer进行处理达到负载均衡目的。第二次再根据去掉key的随机前缀,按原key进行reduce处理。
这个方法进行两次mapreduce,性能稍差。
- 增加Reducer,提升并行度 JobConf.setNumReduceTasks(int)
- 实现自定义分区
- 使用combinner合并,combinner是在map阶段,
在Mapper加上combiner相当于提前进行reduce,即把一个Mapper中的相同key进行了聚合,减少shuffle过程中传输的数据量,以及Reducer端的计算量。
如果导致数据倾斜的key大量分布在不同的mapper的时候,这种方法就不是很有效了。
- 增加jvm内存
根据数据分布情况,自定义散列函数,将key均匀分配到不同Reducer
15-分布式存储(HDFS)与分布式计算(MapReduce)
HDFS就是将⽂件切分成固定⼤⼩的数据块block(⽂件严格按照字节来切,所以若是最后切得剩⼀点点,也 算单独⼀块,hadoop2.x默认的固定⼤⼩是128MB,不同版本,默认值不同.可以通过Client端上传⽂件设置),分而治之:将大文件、大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析;
HDFS 的优点:分布式存储;⽀持分布式和并⾏计算;⽔平可伸缩性;
MapReduce进行大数据计算。MapReduce从它名字上来看就⼤致可以看出个缘由,两个动词Map和Reduce,“Map(展开)”就是将 ⼀个任务分解成为多个任务,然后再集群的不同资源姐节点上进行执行,“Reduce”就是将分解后多任务处理的结果汇总起来,得出最后的分析结 果。MapReduce采⽤"分⽽治之"的思想,简单地说,MapReduce就是"任务的分解与结果的汇总"。
16-NameNode和Second工作机制
1、内存中,会存储所有元数据,但断电会丢失;
2、硬盘中,也会存储所有元数据,但由edits log+fsimage才是所有元数据;
(1) edits log日志文件中,存最新储增删改等操作,每当有这些操作,都会先存到日志文件中,但log有容量限制,并且容量不大(几十兆),每次快满时会把数据计算后刷入fsimage(在secondaryNameNode中操作);
(2) fsimage 镜像文件,镜像文件就是存储大部分元数据(并且是旧数据)。镜像文件的数据不是从内存中的元数据刷入的,因为这样会导致namenode的机器性能下降,而是每隔一段时间通过secondaryNameNode执行edits log的操作然后再刷入fsimage(具体步骤后面再说)
元数据的内容
文件名、文件路径、副本的数量、每一个块的Datanode的位置
fsimage :保存了最新的元数据检查点,包含了整个HDFS文件系统的所有目录和文件的信息。
editlog :主要是在NameNode已经启动情况下对HDFS进行的各种写操作进行记录,HDFS客户端执行所有的写操作都会被记录到editlog中。
- 第一阶段: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。
1.2.18 DataNode工作机制
1)一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
2)DataNode启动后向namenode注册,通过后,周期性(6小时)的向namenode上报所有的块信息。
3)心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。
4)集群运行中可以安全加入和退出一些机器
17-Hadoop小文件解决方案
1)会有什么影响
(1)1个文件块,占用namenode多大内存150字节
1亿个小文件150字节
1 个文件块 150字节
128G能存储多少文件块? 128 102410241024byte/150字节 = 9亿文件块
- hdfs有最大文件数限制;
- 浪费磁盘资源(可能存在空文件);
- hive中进行统计,计算的时候,会产生很多个map,影响计算的速度。
2)怎么解决
(1)采用har归档方式,将小文件归档
(2)采用CombineTextInputFormat
(3)有小文件场景开启JVM重用;如果没有小文件,不要开启JVM重用,因为会一直占用使用到的task卡槽,直到任务完成才释放。
JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间
Spark中同样存在小文件问题,后续的spark面试题会讲到如何解决,一般情况下面试中问到hadoop的小文件后会加问一句spark的小文件。
18-MapReduce与Spark的区别
- Spark 和 Hadoop 的根本差异是多个作业之间的数据通信问题 : Spark 多个作业之间数据通信是基于内存,而 MR 是基于磁盘。Spark处理数据的能力一般是MR的十倍以上
- Spark 只有在 shuffle 的时候将数据写入磁盘,而 MR 中多个 MR 作业之间的数据交互都要依赖于磁盘交互。
- Spark 更擅长函数处理和迭代,模型更加丰富,MR只有map,reduce和join
- Spark中除了基于内存计算外,还有DAG有向无环图来切分任务的执行先后顺序。
19-Hadoop与Spark的区别
- Hadoop和Spark两者都是大数据框架,但是各自应用场景是不同的。Hadoop是一个分布式数据存储架构,它将巨大的数据集分派到一个由普通计算机组成的集群中的多个节点进行存储,降低了硬件的成本。Spark是那么一个专门用来对那些分布式存储的大数据进行处理的工具,它要借助hdfs的数据存储。
- Hadoop的数据处理单位是block,Spark 提供了可供并行处理的数据抽象RDD
- Hadoop 对数据处理只提供了Map和Reduce 两种操作。Spark 提供了两大类算子transformation 和 action,支持的操作更多。
- Hadoop 只支持Map->Reduce 的流程。Spark 则依赖DAG 有向无环图的方式来执行Job。速度更快。
- Spark 提供了Hadoop 所不支持的cache 和 checkpoint 机制。大大的提高了计算速度和程序可靠性。
20-MR实现WordCount
1.Mapper 阶段
(1)用户自定义的 Mapper 要继承自己的父类;
(2)Mapper 的输入数据是 KV 对的形式(KV 的类型可自定义);
(3)Mapper 中的业务逻辑写在 map() 方法中;
(4)Mapper 的输出数据是 KV 对的形式(KV 的类型可自定义)
(5)map() 方法(MapTask 进程)对每一个 <K,V> 调用一次。
输入:单词
输出:<k,v>,即 (单词,数量)。
(1)编写Mapper类
public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
Text k = new Text();
IntWritable v = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 1 获取一行
String line = value.toString();
// 2 切割
String[] words = line.split(" ");
// 3 输出
for (String word : words) {
k.set(word);
context.write(k, v);
}
}
}
2.Reducer 阶段
(1)用户自定义的 Reducer 要继承自己的父类;
(2)Reducer 的输入数据类型对应 Mapper 的输出数据类型,也是 KV;
(3)Reducer 的业务逻辑写在 reduce() 方法中;
(4)ReduceTask 进程对每一组相同 k 的 <k,v> 组调用一次 reduce() 方法。
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
int sum;
IntWritable v = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
// 1 累加求和
sum = 0;
for (IntWritable count : values) {
sum += count.get();
}
// 2 输出
v.set(sum);
context.write(key,v);
}
}
21-mapjoin和reducejoin区别
- join的底层原理
- 两个 map 读取两个表 table1 和 table2,处理成 key-value 的形式。
- 其中 key 是 join on 后面的字段,value 就是表中的其他字段,以及 tag 标记,记录了该 kv 对来自 table1 还是 table2。
- reduce 拉取每个 map 相同的 key 的数据到一个 reduce 中处理。
- reduce 根据 tag 将来自 table1 和 table2 的数据拼接成一条。来自相同的表的数据不拼接。
- Map-side Join(Broadcast join)
小表复制到各个节点上,并加载到内存中;大表分片,与小表完成连接操作。
两份数据中,如果有一份数据比较小,小数据全部加载到内存,按关键字建立索引。大数据文件作为map的输入,对map()函数每一对输入,都能够方便的和已加载到内存的小数据进行连接。把连接结果按key输出,经过shuffle阶段,reduce端得到的就是已经按key分组的,并且连接好了的数据。oo
- Join操作在map task中完成,因此无需启动reduce task
- 适合一个大表,一个小表的连接操作
问题:
- 有一份数据比较小,在map端,能够把它加载在内存,并进行join操作。
- Reduce-side Join(shuffle join)
map端按照连接字段进行hash,reduce端完成连接操作
在map阶段,把关键字作为key输出,并在value中标记出数据是来自data1还是data2。因为在shuffle阶段已经自然按key分组,reduce阶段,判断每一个value是来自data1还是data2,在内部分成两组,做集合的成绩。
- Join操作在reduce task中完成
- 适合两个大表的连接操作
问题:
- map阶段没有对数据瘦身,shuffle的网络传输和排序性能很低。
- reduce端对2个集合做乘积计算,很耗内存,容易导致OOM。
22-只Map不Reduce
1、where查询,简单过滤
2、没有聚合操作
3、格式转换操作
只要计算是针对单条数据和前后数据都没关系,就不需要写reduce
23-Map和Reduce个数如何确定
1、Map个数的确定
map的个数等于split的个数。我们知道,mapreduce在处理大文件的时候,会根据一定的规则,把大文件划分成多个,这样能够提高map的并行度。
2、谁负责划分split 主要是InputFormat。InputFormat类有2个重要的作用: 1)将输入的数据切分为多个逻辑上的InputSplit,其中每一个InputSplit作为一个map的输入。 2)提供一个RecordReader,用于将InputSplit的内容转换为可以作为map输入的k,v键值对。 3、hive中reduce个数的确定 reduce个数的设定极大影响任务执行效率,不指定reduce个数的情况下,Hive会猜测确定一个reduce个数,基于以下两个设定: hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为1000^3=1G) hive.exec.reducers.max(每个任务最大的reduce数,默认为999) 计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1) 即,如果reduce的输入(map的输出)总大小不超过1G,那么只会有一个reduce任务;
2.调整reduce个数方法一: 调整hive.exec.reducers.bytes.per.reducer参数的值; set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
3.调整reduce个数方法二: 直接指定reduce个数 set mapred.reduce.tasks = 15;
4、Hadoop中Reduce个数的确定
在默认情况下,一个MapReduce Job如果不设置Reducer的个数,那么Reducer的个数为1。具体,可以通过在Driver中JobConf.setNumReduceTasks(int numOfReduceTasks)方法来设置Reducer的个数。
- 0.95 * NUMBER_OF_NODES * mapred.tasktracker.reduce.tasks.maximum
- 1.75 * NUMBER_OF_NODES * mapred.tasktracker.reduce.tasks.maximum
其中,NUMBER_OF_NODES 代表集群中计算节点的个数,mapred.tasktracker.reduce.tasks.maximum代表每一个节点所分配的Reducer任务槽的个数。
reducer个数是由partition个数决定。 mapper产生的中间数据经过shuffer过程,根据我们的业务把数据分成若干partition,每个partition的数据由对应的一个reducer来处理。mapreduce决定partition的是:Partitioner类中的intgetPartition(KEY key, VALUE value, int numPartitions)方法,我们来看下默认的分区方法:
24-Hadoop集群存在的问题
- HDFS的单点故障,NameNode单点故障,难以应用于在线场景
- 单个NameNode压力过大,且内存受限,影响系统扩展性
- Yarn的单点故障,Resourcemanager单点故障,导致MR程序无法正常运行
25-Hadoop的高可用
Hadoop实现高可用主要有两种方式,一种是使用共享日志编辑系统(QJM),另一种是基于网络文件系统(NFS)的高可用方案。基于NFS的高可用方案需要额外安装NFS服务器,而QJM的高可用方案不需要安装额外的服务器。两种高可用方案都依赖于Zookeeper。
两个单独的计算机配置为NameNode。在任何时间点,一个NameNode都恰好处于活动状态(Active),而另一个则处于Standby状态。Active NameNode负责集群中的所有客户端操作,而Standby则仅充当从属,并保持足够的状态以在必要时提供快速故障转移。
1.两台NN启动后都会去zk(zookeeper)进行注册,优先注册的为主节点(Active),另外一个为备节点(Standby),
2.主NN对外提供服务,备NN同步主NN元数据,以待切换,通过集群JN(JournalNode)。
备用NN也会帮助主NN合并editsLog文件和fsimage产生新的fsimage,并推送ActiveNN。
3.ZKFailover Controller(ZKFC,与NN在同一机器上)的作用是监控NameNode健康状态,当主NN挂掉之后,备用NN的ZKFC会得到消息,然后会将备用NN状态改为(Active),并是原来的主NN改为备用NN。
4.DN(datenode)会同时把信息报告给主从NN。
26-HDFS如何保证数据可靠性
(1)安全模式
① HDFS刚启动时,NameNode进入安全模式,处于安全模式的NameNode不能做任何的文件操作,甚至内部的副本创建也是不允许的,NameNode这时需要和各个DataNode进行通信,获得DataNode存储的数据块信息,并对数据块信息进行检查,只有通过了NameNode的检查,一个数据块才被认为是安全的。当认为安全的数据块所占比例达到了某个阈值,NameNode才会开始启动;
(2)SecondaryNamenode备份机制
① 在Hadoop中使用SecondaryNameNode来备份NameNode的元数据,以防止在NameNode宕机的时候,能从SecondaryNameNode中恢复出NameNode上的元数据;
② NameNode中保存了整个文件系统的元数据,而SecondaryNameNode的作用就是周期性保存NameNode的元数据。元数据中包括FSImage镜像文件数据和EditLog编辑日志。FSImage相当于HDFS的检查点,NameNode启动时候会读取FSImage的内容到内存,并将其与EditLog日志中的所有修改信息合并生成新的FSImage。在NameNode运行过程中,所有关于HDFS的修改都将写入EditLog日志文件中。这样,如果NameNode宕机,可以通过SecondaryNameNode中保存的FSImage和EditLog数据恢复出NameNode最近的状态,尽量减少数据的损失;
(3)心跳机制和副本重新创建
① 为了保证NameNode和各个DataNode的联系,HDFS采用了心跳机制。NameNode周期性的向各个DataNode发送心跳包,而收到心跳包的DataNode要进行回复。因为心跳包是定时发送的,所以NameNode就把要执行的命令也通过心跳包发送给DataNode,而DataNode收到心跳包,一方面要回复NameNode,另一方面就要开始应用数据的传输;
② 如果检测到DataNode失效,NameNode之前保存在这个DataNode上的数据就变成不可用数据。如果有的副本存储在失效的DataNode上,那么需要重新创建这个副本,放到另外可用的地方去;
(4)数据一致性校验以及数据冗余
① 一般来讲,DataNode与应用交互的大部分情况都是通过网络进行的,而网络数据传输带来的一大问题就是数据是否原样到达。为了保证数据的一致性,HDFS采用了数据校验和(checkSum)机制。创建文件时,HDFS会为这个文件生成一个校验和,校验和文件和文件本身保存在同一空间中。传输数据时会将数据与校验和数据一起传输,应用收到数据后可以进行校验,如果两个校验的结果不同,则文件出错了,这个数据块就变成无效的。如果判定为无效,则需要从其他DataNode上读取副本数据;
27-为什么HDFS文件块(block)大小设定为128M
块(block)的大小可以通过设置dfs.blocksize来实现;
在Hadoop2.x的版本中,文件块的默认大小是128M,老版本中默认是64M;
如果块设置过大, 一方面,从磁盘传输数据的时间会明显大于寻址时间,导致程序在处理这块数据时,变得非常慢; 另一方面,mapreduce中的map任务通常一次只处理一个块中的数据,如果块过大运行速度也会很慢。 如果块设置过小, 一方面存放大量小文件会占用NameNode中大量内存来存储元数据,而NameNode的内存是有限的,不可取; 另一方面文件块过小,寻址时间增大,导致程序一直在找block的开始位置。
- HDFS中平均寻址时间大概为10ms;
- 经过前人的大量测试发现,寻址时间为传输时间的1%时,为最佳状态;
- 所以最佳传输时间为10ms/0.01=1000ms=1s
- 目前磁盘的传输速率普遍为100MB/s;
- 计算出最佳block大小:100MB/s x 1s = 100MB
- 所以我们设定block大小为128MB。
ps:实际在工业生产中,磁盘传输速率为200MB/s时,一般设定block大小为256MB,磁盘传输速率为400MB/s时,一般设定block大小为512MB