1、Hadoop1.x和Hadoop2.x的区别:
a、1.x:Common(辅助工具)、HDFS(数据存储)、MapReduce(计算+资源调度)
b、2.x:Common(辅助工具)、HDFS(数据存储)、MapReduce(计算)、Yarn(资源调度)
答:在hadoop1.x时代中,hadoop中的mapreduce同时处理业务逻辑运算和资源调度,耦合性较大,
在hadoop2.x时代中,增加了yarn。分担了1.x版本的资源调度的工作,mapreduce只负责计算,性能也有所提升。
2、NameNode(NN):存储文件的元数据,如文件名,文件目录结构,文件属性(生成文件时间、副本数、文件权限),以及每个文件的块列表和块所在的DataNode等。
DataNode(DN):在本地文件系统存储文件块数据,以及块数据的校验和。
Secondary NameNode(2NN):用来监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS元数据的快照。
并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务,
辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode。
在紧急情况下,可辅助恢复NameNode。
Yarn(资源调度):包括 RM(resourceManager所有机器的资源的分配和调度)、NM(NodeManager 管理某个服务器的资源)、AM(applicationMaster负责数据的切分,为应用程序申请资源并分配给内部
的任务,任务的监控和容错)、Container(是yarn的资源抽象,封装了某个节点上的多维度资源,如内存、cpu、磁盘、网络等)
3、MapReduce:map阶段并行处理数据
reduce阶段对map结果进行汇总
4、HDFS的优缺点:
优点:a、高容错性
1)数据自动保存多个副本。通过增加副本的形式,提高容错性
2)某一个副本丢失以后,它可以自动恢复
b、适合处理大数据
1)数据规模:能够处理数据规模达到GB、TB,甚至PB级别的数据
2)文件规模:能够处理百万规模以上的文件数量,数量相当之大
c、可构建在廉价机器上、通过多副本机制,提高可靠性。
缺点:a、不适合低延时数据访问,比如毫秒级的存储数据,是做不到的
b、无法高校的对大量小文件进行存储
1)存储大量小文件的话,它会占用NameNode大量的内存来存储文件目录和块信息,是不可取的,因为NameNode的内存总是有限的。
2)小文件存储的寻址时间会超过读取时间(小文件量大,导致遍历的时间就长),违反了HDFS的设计目标。
c、不支持并发写入,文件随机修改。
1)一个文件只能有一个写,不允许多个线程同时写;
2)只支持数据append(追加),不支持文件的随机修改。
5、寻址时间:HDFS中找到目标文件块(block)所需要的时间。
原理:
文件块越大,寻址时间越短,但磁盘传输时间越长;
文件块越小,寻址时间越长,但磁盘传输时间越短。
一、为什么HDFS中块(block)不能设置太大,也不能设置太小?
1. 如果块设置过大,
一方面,从磁盘传输数据的时间会明显大于寻址时间,导致程序在处理这块数据时,变得非常慢;
另一方面,mapreduce中的map任务通常一次只处理一个块中的数据,如果块过大运行速度也会很慢。
2. 如果块设置过小,
一方面存放大量小文件会占用NameNode中大量内存来存储元数据,而NameNode的内存是有限的,不可取;
另一方面文件块过小,寻址时间增大,导致程序一直在找block的开始位置。
因而,块适当设置大一些,减少寻址时间,那么传输一个由多个块组成的文件的时间主要取决于磁盘的传输速率。
二、 HDFS中块(block)的大小为什么设置为128M?
1. HDFS中平均寻址时间大概为10ms;
2. 经过前人的大量测试发现,寻址时间为传输时间的1%时,为最佳状态;
所以最佳传输时间为10ms/0.01=1000ms=1s
3. 目前磁盘的传输速率普遍为100MB/s;
计算出最佳block大小:100MB/s x 1s = 100MB
所以我们设定block大小为128MB。
ps:实际在工业生产中,磁盘传输速率为200MB/s时,一般设定block大小为256MB
磁盘传输速率为400MB/s时,一般设定block大小为512MB
6、HDFS namenode容错机制
1 远程备份组成元数据持久状态的文件
将持久状态写入本地磁盘的同时,写入一个远程的网络文件系统NFS(网络文件系统Network File System,NFS),操作是实时且原子性的
搭建DFS共享网络文件系统,即使A服务器磁盘坏了,也不影响B服务器提供服务。
2 运行secondary namenode(辅助namenode)
辅助namenode主要是合并edits和fsimage,并保存合并后的fsimage
namenode出现故障时,启用辅助namenode,因为辅助namenode上的fsimage未包含最近的edits文件,所以一般是将远程NFS上的元数据信息拷贝到辅助namenode上作为主namenode运行
一,NameNode
HDFS集群有两类节点以管理者和工作者的工作模式运行,namenode就是其中的管理者。它管理着文件系统的命名空间,维护着文件系统树及整棵树的所有文件和目录。这些信息以两个文件的形式保存于内存或者磁盘,这两个文件是:命名空间镜像文件fsimage和编辑日志文件edit logs ,同时namenode也记录着每个文件中各个块所在的数据节点信息。
namenode对元数据的操作过程
图中有两个文件:
(1)fsimage:文件系统映射文件,也是元数据的镜像文件(磁盘中),存储某段时间namenode内存元数据信息。
(2)edits log:操作日志文件。
这种工作方式的特点:
(1)namenode始终在内存中存储元数据(metedata),使得“读操作”更加快、
(2)有“写请求”时,向edits文件写入日志,成功返回后才修改内存,并向客户端返回。
(3)fsimage文件为metedata的镜像,不会随时同步,与edits合并生成新的fsimage。
从以上特点可以知道,edits文件会在集群运行的过程中不断增多,占用更多的存储空间,虽然有合并,但是只有在namenode重启时才会进行。并且在实际工作环境很少重启namenode,
这就带来了一下问题:
(1)edits文件不断增大,如何存储和管理?
(2)因为需要合并大量的edits文件生成fsimage,导致namenode重启时间过长。
(3)一旦namenode宕机,用于恢复的fsiamge数据很旧,会造成大量数据的丢失。
二,Secondary NameNode
上述问题的解决方案就是运行辅助namenode–Secondary NameNode,为主namenode内存中的文件系统元数据创建检查点,Secondary NameNode所做的不过是在文件系统中设置一个检查点来帮助NameNode更好的工作。它不是要取代掉NameNode也不是NameNode的备份,
SecondaryNameNode有两个作用,一是镜像备份,二是日志与镜像的定期合并。两个过程同时进行,称为checkpoint(检查点)。
镜像备份的作用:备份fsimage(fsimage是元数据发送检查点时写入文件);
日志与镜像的定期合并的作用:将Namenode中edits日志和fsimage合并,防止如果Namenode节点故障,namenode下次启动的时候,会把fsimage加载到内存中,应用edits log,edits log往往很大,导致操作往往很耗时。(这也是namenode容错的一套机制)
Secondary NameNode创建检查点过程
Secondarynamenode工作过程
(1)SecondaryNameNode通知NameNode准备提交edits文件,此时主节点将新的写操作数据记录到一个新的文件edits.new中。
(2)SecondaryNameNode通过HTTP GET方式获取NameNode的fsimage与edits文件(在SecondaryNameNode的current同级目录下可见到 temp.check-point或者previous-checkpoint目录,这些目录中存储着从namenode拷贝来的镜像文件)。
(3)SecondaryNameNode开始合并获取的上述两个文件,产生一个新的fsimage文件fsimage.ckpt。
(4)SecondaryNameNode用HTTP POST方式发送fsimage.ckpt至NameNode。
(5)NameNode将fsimage.ckpt与edits.new文件分别重命名为fsimage与edits,然后更新fstime,整个checkpoint过程到此结束。
SecondaryNameNode备份由三个参数控制fs.checkpoint.period控制周期(以秒为单位,默认3600秒),fs.checkpoint.size控制日志文件超过多少大小时合并(以字节为单位,默认64M), dfs.http.address表示http地址,这个参数在SecondaryNameNode为单独节点时需要设置。
从工作过程可以看出,SecondaryNameNode的重要作用是定期通过编辑日志文件合并命名空间镜像,以防止编辑日志文件过大。SecondaryNameNode一般要在另一台机器上运行,因为它需要占用大量的CPU时间与namenode相同容量的内存才可以进行合并操作。它会保存合并后的命名空间镜像的副本,并在namenode发生故障时启用。
SecondaryNameNode的namesecondary/current目录和主namenode的current目录的布局相同。
好处:在主namenode发生故障时(假设没有及时备份数据),可以从SecondaryNameNode恢复数据。
2.故障恢复方法
方法一:将SecondaryNameNode中数据拷贝到namenode存储数据的目录;
方法二:使用-importCheckpoint选项启动namenode守护进程,从而将SecondaryNameNode用作新的主namenode。
如果手动的话,在生产上采用安全模式(safe mode) hdfs dfsadmin 命令去开启安全模式
计算切片问题
129M的文件分成2块存储(在集群中的HDFS)
本地模式中默认的blocksize:32M,集群模式是128M。
while (((double) bytesRemaining)/splitSize > 1.1) {}
默认的切片splitSize是128M。129/128 小于1.1,则就切成一片(一个mapTask任务线程)
141M/128M 刚好大于 1.1 那么就分为两片,两个mapTask任务数去执行
YARN中一些术语:
两个独立的守护进程:RM和AM
resource manager ,RM:负责管理整个集群上所有应用程序计算资源的分配。
application master ,AM:每一个应用程序的AM负责相应的d调度和协调,监视整个任务的生命周期,RM和AM协商集群的计算资源。
容器,containers:每个容器都有一个特定的内存上限,在这些容器上运行特定应用程序的进程,每个任务对应一个Containers,且只能在该container中运行。
container是由集群ji节点上运行的节点管理器监视,以确保应用程序使用的资源不会超过分配给它的资源。
节点管理器,node manager:管理每个节点上的资源和任务,主要有两个作用:
定期向RM汇报该节点的资源使用情况和各个container的运行状态;
接收并处理AM的任务启动、停止等请求
YARN工作流程机制:
(0)Mr程序提交到客户端所在的节点
(1)yarnrunner向Resourcemanager申请一个application。
(2)rm将该应用程序的资源路径返回给yarnrunner
(3)该程序将运行所需资源提交到HDFS上
(4)程序资源提交完毕后,申请运行mrAppMaster
(5)RM将用户的请求初始化成一个task
(6)其中一个NodeManager领取到task任务。
(7)该NodeManager创建容器Container,并产生MRAppmaster
(8)Container从HDFS上拷贝资源到本地
(9)MRAppmaster向RM 申请运行maptask容器
(10)RM将运行maptask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器。
(11)MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动maptask,maptask对数据分区排序。
(12)MRAppmaster向RM申请2个容器,运行reduce task。
(13)reduce task向maptask获取相应分区的数据。
(14)程序运行完毕后,MR会向RM注销自己。
map-reduce计算模型是Hadoop解决海量数据处理的战略布局,排序器/组合器/合并器是Hadoop解决计算节点性能的战术实现
一、排序器(Sorter)
对于Hadoop中排序器的设计,我不得不得先向Hadoop的设计大牛们深深的鞠上一躬,它牛B了,太精彩了。他们将排序问题抽象成了一个框架,或者说是一个排序模型:
上面的排序模型将排序问题描述成这样的一个过程:排序器不断地对待排序的记录集进行某两条记录的比较与交换。也就是说,任何一种排序算法只对带排序的记录集进行两种基本操作:比较两条记录的大小、交换两条记录在带排序记录集中的位置,这就是Hadoop大牛们对排序问题的精简定义,这样的定义来源于他们对问题在最本质上的了解。我不得不说只有对问题有了最深入、最本质的了解之后才能设计出最抽象、最准确的解决方案,对已实现的解决方法的不断重构只能治标不能治本。在Sorter中实现某种排序算法,在Sortable中实现某种可排序的数据集,这样使得排序算法与待排序的数据集分开,排序算法永远也不知道也不需要知道它正在对哪个数据类型的数据集进行排序。而Hadoop在其内部这是这样设计的。
Hadoop关于可排序的数据集定义了一个抽象接口IndexedSortable,也就是说任何能够排序的数据集必须要实现两个方法,一是能够比较它的数据集中任意两项的大小,二是能够交换它的数据集中任意两项的位置;排序算法的实现定义了一个抽象接口IndexedSorter,它定义了两个方法,其中的一个方法还可以报告当前排序的完成进度。
二、组合器(Combiner)
Hadoop在其内部利用组合器来局部合并具有相同key的key-value记录,组合器的设计大致同排序器的设计一样,也是将合并操作和待合并的数据分开,这个组合器框架设计如下: Hadoop中的合并器一般合并的key-value数据来自与内存,然后把合并后的结果按照一定的组织格式写入磁盘文件作为中间数据,待最后汇总合并,我们把每一次合并后的这种中间结果看做一个段。在Hadoop中是这样实现这个组合框架的:
Hadoop中的组合器的实现主要用来处理key-value类型的数据,它先把带合并的所有的key-value结合按照key值来聚合,这样就使得相同key值的key-value记录被保存到同一个迭代器(Iterator)中,然后把一个个迭代器结构组合器来处理,最后每一迭代器的处理结果被交给了收集器(Collector)来保存。
三、合并器(Merger)
这里的合并器(Merger)不同于上面介绍的组合器(Combiner),它主要是正对上面组合器生成的最后结果进行合并,也就是合并所有的中间段,这个框架在Hadoop内部是这样设计的:
Hadoop中合并器(Merger)的设计类似于它的组合器(Combiner),唯一不同的就是这个聚合迭代器的来源略有不同,合并器中的每一个迭代器来自于所有的中间段中属于相同类的key-value,所以对每一中间段,合并器都生成了一个对应的段读取器来读取段(SegmentReader)中的key-value值。主要看一下与段读取器(SegmentReader)相关的实现类:
四、总结
在本文,我系统的介绍了Hadoop对排序器/组合器/合并器的设计,Hadoop对它们的设计可以说是站在一个好高的层次,因此我们就可以把这些框架移植到其它引用场景下,甚至无需修改任何代码。
MepReduce面试题:MapReduce中排序发生在哪几个阶段?这些排序是否可以避免?为什么?
如果任务没有设置reducer个数,为0的话,则整个map过程中不会sort
答:1.map最后阶段进行partition分区,一般使用job.setPartitionerClass设置的类,如果没有自定义Key的hashCode()方法进行分区。在map阶段写出到环形缓冲区,在环形缓冲区溢写时会进行一次排序, 每个分区内部调用job.setSortComparatorClass设置的key的比较函数类进行排序,如果没有则使用Key的实现的compareTo方法。
2.在归并每一个maptask的环形缓冲区的所有溢写文件的时候也会再次进行排序
3.当reduce接收到所有map传输过来的数据之后,对每一个分区的数据进行merge并排序,调用job.setSortComparatorClass设置的key比较函数类对所有数据对排序,如果没有则使用Key的实现的compareTo方法。
4.紧接着使用job.setGroupingComparatorClass设置的分组函数类,进行分组,同一个Key的value放在一个迭代器里面。如果未指定GroupingComparatorClass则则使用Key的实现的compareTo方法来对其分组。
Hadoop1.0中不可避免 hadoop2.0中可以关闭,将reducetask设置为0
MapReduce中的数据流动
最简单的过程: map - reduce
定制了partitioner以将map的结果送往指定reducer的过程: map - partition - reduce
增加了在本地先进行一次reduce(优化)的过程: map - combine - partition - reduce
map端执行自定义的mapper后---》执行sort(先按分区排序、如果在同一个区下,则按key排序,默认使用快排)---》执行combiner组合器----》
将排序后的buffer生成一个或者多个文件(spill溢写到临时目录)名为spill0.out-----》将1个或多个溢spill写文件合并meger生成file.out文件,
reduce端---》将多个file.out合并成map_0.out.merged文件(排序后的)
注:排序先是按照从大到小排序的,然后写入的时候重新存入新的缓存数组中,不过是从小到大的顺序重新存入,最后关闭的时候,写入到磁盘产生spill0.out的有序文件。
如果一个map任务,split切片数为1,溢写出两个spill0.out和spill1.out已排好序的文件,在合并merger的时候,分别读取出由配置的"io.file.buffer.size"的参数值
4096个缓冲字节数
如果超过0.8的阈值,则会通知spillThread线程溢出写入到临时文件中,如果不超过,,在最后的关闭output时候调用MapOutputBuffer的flush也会溢写到文件
JobSumitter-->LocalJobRunner.run()-->MapTaskRunnable.run()-->MapTask.run()-->MapTask.runNewMapper(),创建MapOutputBuffer采集器new NewOutputCollector()
-->调用用户写的map方法,context.write()方法内部最终调用的是MapOutputBuffer.collect()方法,该方法去写入并判断是否超过默认的100M的阈值100*0.8=80M,如果超过
80M,那么就唤醒spillThread溢写的线程去往磁盘就写,当然了,在溢写的之前先进行对溢写的数据进行排序,这样,每个溢写文件都是有序的,这个spillThread线程是在new MapOutputBuffer()的构造方法里去开启的,wait()状态,溢写线程边写入磁盘,主线程
也在继续往缓存中写入数据,缓存默认是100M,如果溢写还没完成,缓存已经都使用完毕,那么主线程就等待溢写线程完成后才回去唤醒主线程继续,当主线程都读取完毕后再次
调用MapOutputBuffer的flush()也就是最后的sortAndSpill()排序且溢写到磁盘(如果reducer个数不止一个,在此会对元数据kvmeta数据进行分区操作),
--->megerparts()方法进行spill文件的合并并且采用归并算法对多个有序的spill文件进行整合成一个fill.out文件,如果有分区(reducer个数不为1)则输出的fill.out文件
是分区后的整合的文件,默认采用hash取模分区,在fill.out的文件头标记出分区标识,(分区有利于减少reduce的压力,以及整合的spill文件也减轻压力,还有map端
的combiner合并器也是有助于减轻reduce的压力)
比较器,对比器
Map端:是如何开始调用的呢?在所有文件都spill溢写出前开始调用sortAndSpill方法,调用sort去排序,则调用自己的对比器,对Key进行排序。
注意:map端是对key排序
1:xml配置属性mapreduce.job.output.key.comparator.class 如果未配置走2.
2:api形式:job.setSortComparatorClass(ComboKeyComparator.class);
3:如果都没有从map缓存获取
WritableComparator.get(getMapOutputKeyClass().asSubclass(WritableComparable.class), this);
获取设置的MapOutputKeyClass作为key的对比器,形如IntWritable类,内部类继承了WritableComparator
如果缓存还没有则创建父类WritableComparator对象作为默认对比器
Reduce端(分组对比器):是如何开始调用的呢?是在reduce的run方法开始遍历context.nextKey()的时候调用分组对比器,将key同一组的分在一起,对自定义key才起作用。
1:xml配置属性mapreduce.job.output.group.comparator.class 如果未配置走2
2:api形式:job.setGroupingComparatorClass(YearGroupComparator.class);
3:在reduce的run方法开始获取分组对比器RawComparator comparator = job.getOutputValueGroupingComparator();
如果都没有配置那么就获取Map端的对比器流程。
combiner就是map端的reduce为了减轻shuffle的网络之间的传输,在map端预先将key作聚合,比如:
hello 1 hello 1 hello 1 ....聚合为 hello 3 直接key 和聚合后的数字3传输即可,极大的减少网络负载。
排序:
部分排序:
reduce就是按照key进行排序。
辅助排序 又称 二次排序:
GroupingComparator分组(辅助排序):对Reduce阶段的数据根据某一个或几个字段进行分组。
全排序操作:
1、定义一个reduce。缺点:会造成数据倾斜。
2、自定义分区函数:自行根据总量来分析
比如100个数,3个reduce,则分了3个分区,对所有的结果进行排序(输出的三个文件合并起来是整个有序的)
可以这样,100/3=33, 0-33--》分区0,33-66--》分区1,66-100--》分区3,这样每个分区都是有序的,整合起来就是有序的
3、采用hadoop的采样机制(TotalOrderPartitioner):原理就是对部分数据采用得出一个区间值,然后根据这个区间进行分区,和自定义分区一样。
InputSampler采样分为三种:
切片采样splitSampler:只采样一个分片中的前n条记录,由于由于并未从所有分片中广泛采样,该采样器并不适合已经排序好的顺序
随机采样randomSampler:
间隔采样IntervalSampler:已一定的j间隔定期从分片中选择键,对已经排序好的数据来说是一个很好的选择。
倒排序:
kv对调
二次排序 又称 辅助排序:对value进行排序。key是一次排序
Key是可以排序的。
需要对value排序。
1.自定义key
2.自定义分区类,按照年份分区
3.定义Key排序对比器(map端的排序)
4.定义分组对比器(reduce端的)
map端join连接操作:
小表+大表:在map端的mapper.setup()可以将小表的数据初始化到内存当中,在map端即可实现join连接输出
reduce端的join连接操作:
大表+大表:解决方式和二次排序类似
输入格式有哪些:
1、TextInputFormat 文本
2、KeyValueTextInputFormat k-v 对
3、SequenceFileInputFormat 序列文件
4、CombineTextInputFormat 合并文本输入格式,合并多个小文件
5、NLineInputFormat 换行输入格式
6、MutliInputFormat 多输入文件
解决数据倾斜skew:
1、定义合成器Combiner类(map端的reduce)在map端 hash分区后,调用Combiner合成将同一key进行聚合累加成一个key 和一个总数,最后在shuffle到reduce端,减轻压力。
2、自定义分区函数,但是一次的job执行统计的话,数据会比较分散,不是一个完整的总数,如果需要统计总数,需要再次对part-r-0000~part-r-0100个文件继续执行一次job。
两次job的执行
网上收集:
2.增加reduce的个数,这适用于第二种情况(唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一),我们知道,这种情况下,
最容易造成的结果就是大量相同key被partition到一个分区,从而一个reduce执行了大量的工作,而如果我们增加了reduce的个数,这种情况相对来说会减轻很多,
毕竟计算的节点多了,就算工作量还是不均匀的,那也要小很多。
3.自定义分区,这需要用户自己继承partition类,指定分区策略,这种方式效果比较显著。
4.重新设计key,有一种方案是在map阶段时给key加上一个随机数,有了随机数的key就不会被大量的分配到同一节点(小几率),待到reduce后再把随机数去掉即可。
5.使用combinner合并,combinner是在map阶段,reduce之前的一个中间阶段,在这个阶段可以选择性的把大量的相同key数据先进行一个合并,可以看做是local
reduce,然后再交给reduce来处理,这样做的好处很多,即减轻了map端向reduce端发送的数据量(减轻了网络带宽),也减轻了map端和reduce端中间
的shuffle阶段的数据拉取数量(本地化磁盘IO速率),推荐使用这种方法。
链式处理 chainMapper
ChainMapper
-----------------
ChainMapper.addMapper(conf, AMap.class, LongWritable.class, Text.class,Text.class, Text.class, true, mapAConf);
可以设置多个mapper类,1个reduce 后面可以0个或者多个mapper,可以很明显的降低IO,因为都是在内存中执行,执行完就立即交给下一个mapper处理
map+ / reduce map*
MapReduce优化方法:
数据输入
Map阶段
Reducer阶段
I/O传输
数据倾斜问题
常用的调优参数
列举几个hadoop 生态圈的组件并做简要描述
Zookeeper:是一个开源的分布式应用程序协调服务,基于zookeeper 可以实现同步服务, 配置维护,命名服务。
Flume:一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。
Hbase:是一个分布式的、面向列的开源数据库, 利用Hadoop HDFS 作为其存储系统。
Hive:基于Hadoop 的一个数据仓库工具,可以将结构化的数据档映射为一张数据库表, 并提供简单的sql 查询功能,可以将sql 语句转换为MapReduce 任务进行运行。
sqoop:
7. 简要描述如何安装配置apache 的一个开源Hadoop,只描述即可,无需列出具体步骤,列出具体步骤更好。
1) 使用root 账户登录
2) 修改IP
3) 修改host 主机名
4) 配置SSH 免密码登录
5) 关闭防火墙
6) 安装JDK
7) 解压hadoop 安装包
8) 配置hadoop 的核心文件hadoop-env.sh,core-site.xml , mapred-site.xml ,hdfs-site.xml,yarn-site.xml
9) 配置hadoop 环境变量
10)格式化hadoop namenode-format
11)启动节点start-all.sh
Hadoop 中需要哪些配置文件,其作用是什么?
1) core-site.xml:
fs.defaultFS:hdfs://cluster1(域名),这里的值指的是默认的HDFS 路径。
hadoop.tmp.dir:/export/data/hadoop_tmp,这里的路径默认是NameNode、DataNode、
secondaryNamenode 等存放数据的公共目录。用户也可以自己单独指定这三类节点的目录。
ha.zookeeper.quorum:hadoop101:2181,hadoop102:2181,hadoop103:2181,这里是ZooKeeper 集群的地址和端口。注意,数量一定是奇数,且不少于三个节点。
2)hadoop-env.sh:
只需设置jdk 的安装路径,如:export JAVA_HOME=/usr/local/jdk。
3)hdfs-site.xml:
dfs.replication:他决定着系统里面的文件块的数据备份个数,默认为3 个。
dfs.data.dir:datanode 节点存储在文件系统的目录。
dfs.name.dir:是namenode 节点存储hadoop 文件系统信息的本地系统路径。
4)mapred-site.xml:
mapreduce.framework.name: yarn 指定mr 运行在yarn 上。
请列出正常工作的Hadoop 集群中Hadoop 都分别需要启动哪些进程,它们的作用分别是什么?
NameNode:它是hadoop 中的主服务器,管理文件系统名称空间和对集群中存储的文件的访问,保存有metadate。
SecondaryNameNode 它不是namenode 的冗余守护进程,而是提供周期检查点和清理任务。帮助NN 合并editslog,减少NN 启动时间。
DataNode 它负责管理连接到节点的存储(一个集群中可以有多个节点)。每个存储数据的节点运行一个datanode 守护进程。
ResourceManager(JobTracker)JobTracker 负责调度DataNode 上的工作。每个DataNode 有一个TaskTracker,它们执行实际工作。
NodeManager(TaskTracker)执行任务
DFSZKFailoverController 高可用时它负责监控NN 的状态,并及时的把状态信息写入ZK 。它
通过一个独立线程周期性的调用NN 上的一个特定接口来获取NN 的健康状态。FC 也有选择谁作为Active NN 的权利,因为最多只有两个节点,目前选择策略还比较简单(先到先得,轮换)。
JournalNode 高可用情况下存放namenode 的editlog 文件.
简述Hadoop 的几个默认端口及其含义
dfs.namenode.http-address:50070
SecondaryNameNode 辅助名称节点端口号:50090
dfs.datanode.address:50010端口
fs.defaultFS:8020 或者9000
yarn.resourcemanager.webapp.address:8088 资源job调度平台
简述hadoop实现Join的几种方法:
1、reduce side join
reduce side join是一种最简单的join方式,其主要思想如下:在map阶段,map函数同时读取两个文件File1和File2,为了区分两种来源的key/value数据对,对每条数据打一个标签(tag),比如:tag=0表示来自文件File1,tag=2表示来自文件File2。即:map阶段的主要任务是对不同文件中的数据打标签。在reduce阶段,reduce函数获取key相同的来自File1和File2文件的value list, 然后对于同一个key,对File1和File2中的数据进行join(笛卡尔乘积)。即:reduce阶段进行实际的连接操作。
2、map side join
之所以存在reduce side join,是因为在map阶段不能获取所有需要的join字段,即:同一个key对应的字段可能位于不同map中。Reduce side join是非常低效的,因为shuffle阶段要进行大量的数据传输。
Map side join是针对以下场景进行的优化:两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多份,让每个map task内存中存在一份(比如存放到hash table中),然后只扫描大表:对于大表中的每一条记录key/value,在hash table中查找是否有相同的key的记录,如果有,则连接后输出即可。
为了支持文件的复制,Hadoop提供了一个类DistributedCache,使用该类的方法如下:
(1)用户使用静态方法DistributedCache.addCacheFile()指定要复制的文件,它的参数是文件的URI(如果是HDFS上的文件,可以这样:hdfs://namenode:9000/home/XXX/file,其中9000是自己配置的NameNode端口号)。JobTracker在作业启动之前会获取这个URI列表,并将相应的文件拷贝到各个TaskTracker的本地磁盘上。
(2)用户使用DistributedCache.getLocalCacheFiles()方法获取文件目录,并使用标准的文件读写API读取相应的文件。
请列出你所知道的hadoop调度器,并简要说明其工作方法?
比较流行的三种调度器有:默认调度器FIFO,计算能力调度器CapacityScheduler,公平调度器Fair Scheduler
1) 默认调度器FIFO
hadoop中默认的调度器,采用先进先出的原则
2) 计算能力调度器CapacityScheduler
选择占用资源小,优先级高的先执行
3) 公平调度器FairScheduler
同一队列中的作业公平共享队列中所有资源
简答说一下hadoop的map-reduce编程模型
首先map task会从本地文件系统读取数据,转换成key-value形式的键值对集合
使用的是hadoop内置的数据类型,比如longwritable、text、bytesWritable等
(inputFormat-->recordreader-->mapper-->partition-->sort(快排、如果自定义key的排序,则使用自定义的,默认TextWritable的)-->combiner(合并)-->spill溢写
-->reducer-->merger-->outputFormat-->RecordWriter)
将键值对集合输入mapper进行业务处理过程,将其转换成需要的key-value在输出
之后会进行一个partition分区操作,默认使用的是hashpartitioner,可以通过重写hashpartitioner的getpartition方法来自定义分区规则
之后会对key进行进行sort排序,grouping分组操作将相同key的value合并分组输出,在这里可以使用自定义的数据类型,
重写WritableComparator的Comparator方法来自定义排序规则,重写RawComparator的compara方法来自定义分组规则
之后进行一个combiner归约操作,其实就是一个本地段的reduce预处理,以减小后面shufle和reducer的工作量
reduce task会通过网络将各个数据收集进行reduce处理,最后将数据保存或者显示,结束整个job
为什么要用flume导入hdfs,hdfs的构架是怎样的
flume可以实时的导入数据到hdfs中,当hdfs上的文件达到一个指定大小的时候会形成一个文件,或者超过指定时间的话也形成一个文件
文件都是存储在datanode上面的,namenode记录着datanode的元数据信息,而namenode的元数据信息是存在内存中的,所以当文件切片很小或者很多的时候会卡死
map-reduce程序运行的时候会有什么比较常见的问题?或者MapReduce 出现单点负载多大,怎么负载平衡?(讲诉数据倾斜的现象)
比如说作业中大部分都完成了,但是总有几个reduce一直在运行
这是因为这几个reduce中的处理的数据要远远大于其他的reduce,可能是因为对键值对任务划分的不均匀造成的数据倾斜
解决的方法可以在分区的时候重新定义分区规则对于value数据很多的key可以进行拆分、均匀打散等处理,或者是在map端的combiner中进行数据预处理的操作
Hive中存放是什么?
表。
存的是和hdfs的映射关系,hive是逻辑上的数据仓库,实际操作的都是hdfs上的文件,HQL就是用sql语法来写的mr程序。
Hive与关系型数据库的关系?
没有关系,hive是数据仓库,不能和数据库一样进行实时的CURD操作、也不支持事务型业务操作是一次写入多次读取的操作,可以看成是ETL工具。
Hadoop性能调优?
调优可以通过系统配置、程序编写和作业调度算法来进行。
hdfs的block.size可以调到128/256(网络很好的情况下,默认为64)
调优的大头:mapred.map.tasks、mapred.reduce.tasks设置mr任务数(默认都是1)
mapred.tasktracker.map.tasks.maximum每台机器上的最大map任务数
mapred.tasktracker.reduce.tasks.maximum每台机器上的最大reduce任务数
mapred.reduce.slowstart.completed.maps配置reduce任务在map任务完成到百分之几的时候开始进入
这个几个参数要看实际节点的情况进行配置,reduce任务是在33%的时候完成copy,要在这之前完成map任务,(map可以提前完成)
mapred.compress.map.output,mapred.output.compress配置压缩项,消耗cpu提升网络和磁盘io
合理利用combiner
注意重用writable对象
Spark Streaming和Storm有何区别?
一个实时毫秒一个准实时亚秒,不过storm的吞吐率比较低。
谈谈Hadoop序列化和反序列化及自定义bean对象实现序列化?
1)序列化和反序列化
(1)序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储(持久化)和网络传输。
(2)反序列化就是将收到字节序列(或其他数据传输协议)或者是硬盘的持久化数据,转换成内存中的对象。
(3)Java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,header,继承体系等),不便于在网络中高效传输。所以,hadoop自己开发了一套序列化机制(Writable),精简、高效。
2)自定义bean对象要想序列化传输步骤及注意事项:。
(1)必须实现Writable接口
(2)反序列化时,需要反射调用空参构造函数,所以必须有空参构造
(3)重写序列化方法
(4)重写反序列化方法
(5)注意反序列化的顺序和序列化的顺序完全一致
(6)要想把结果显示在文件中,需要重写toString(),且用"\t"分开,方便后续用
(7)如果需要将自定义的bean放在key中传输,则还需要实现comparable接口,因为mapreduce框中的shuffle过程一定会对key进行排序
在一个运行的Hadoop 任务中,什么是InputSplit?(☆☆☆☆☆)
FileInputFormat源码解析(input.getSplits(job))
(1)找到你数据存储的目录。
(2)开始遍历处理(规划切片)目录下的每一个文件
(3)遍历第一个文件ss.txt
a)获取文件大小fs.sizeOf(ss.txt);
b)计算切片大小computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
c)默认情况下,切片大小=blocksize
d)开始切,形成第1个切片:ss.txt—0:128M 第2个切片ss.txt—128:256M 第3个切片ss.txt—256M:300M(每次切片时,都要判断切完剩下的部分是否大于块的1.1倍,不大于1.1倍就划分一块切片)
e)将切片信息写到一个切片规划文件中
f)整个切片的核心过程在getSplit()方法中完成。
g)数据切片只是在逻辑上对输入数据进行分片,并不会再磁盘上将其切分成分片进行存储。InputSplit只记录了分片的元数据信息,比如起始位置、长度以及所在的节点列表等。
h)注意:block是HDFS上物理上存储的存储的数据,切片是对数据逻辑上的划分。
(4)提交切片规划文件到yarn上,yarn上的MrAppMaster就可以根据切片规划文件计算开启maptask个数。
MapTask和ReduceTask工作机制(☆☆☆☆☆)
(1)Read阶段:Map Task通过用户编写的RecordReader,从输入InputSplit中解析出一个个key/value。
(2)Map阶段:该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。
(3)Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),
并写入一个环形内存缓冲区中。
(4)Spill阶段:即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,
并在必要时对数据进行合并、压缩等操作。
(5)Combine阶段:当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保最终只会生成一个数据文件。
(1)Copy阶段:ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
(2)Merge阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
(3)Sort阶段:按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。
由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。
(4)Reduce阶段:reduce()函数将计算结果写到HDFS上。
描述mapReduce中shuffle阶段的工作流程,如何优化shuffle阶段(☆☆☆☆☆)
分区,排序,溢写,拷贝到对应reduce机器上,增加combiner,压缩溢写的文件。
描述mapReduce中combiner的作用是什么,一般使用情景,哪些情况不需要,及和reduce的区别?
1)Combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量。
2)Combiner能够应用的前提是不能影响最终的业务逻辑,而且,Combiner的输出kv应该跟reducer的输入kv类型要对应起来。
3)Combiner和reducer的区别在于运行的位置。
Combiner是在每一个maptask所在的节点运行;
Reducer是接收全局所有Mapper的输出结果。
MapReduce 怎么实现 TopN? (☆☆☆☆☆)
可以自定义groupingcomparator,对结果进行最大值排序,然后再reduce输出时,控制只输出前n个数。就达到了topn输出的目的。
Hadoop的缓存机制(Distributedcache)(☆☆☆☆☆)
分布式缓存一个最重要的应用就是在进行join操作的时候,如果一个表很大,另一个表很小,我们就可以将这个小表进行广播处理,即每个计算节点上都存一份,
然后进行map端的连接操作,经过我的实验验证,这种情况下处理效率大大高于一般的reduce端join,广播处理就运用到了分布式缓存的技术。
DistributedCache将拷贝缓存的文件到Slave节点在任何Job在节点上执行之前,文件在每个Job中只会被拷贝一次,缓存的归档文件会被在Slave节点中解压缩。
将本地文件复制到HDFS中去,接着Client会通过addCacheFile()和addCacheArchive()方法告诉DistributedCache在HDFS中的位置。当文件存放到文地时,
JobClient同样获得DistributedCache来创建符号链接,其形式为文件的URI加fragment标识。当用户需要获得缓存中所有有效文件的列表时,
JobConf 的方法 getLocalCacheFiles() 和getLocalArchives()都返回一个指向本地文件路径对象数组。
什么样的计算不能用mr来提速?
1)数据量很小。
2)繁杂的小文件。
3)索引是更好的存取机制的时候。
4)事务处理。
5)只有一台机器的时候。
HDFS的存储机制(☆☆☆☆☆)
HDFS写数据过程
1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
2)NameNode返回是否可以上传。
3)客户端请求第一个 block上传到哪几个datanode服务器上。
4)NameNode返回3个datanode节点,分别为dn1、dn2、dn3。
5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
6)dn1、dn2、dn3逐级应答客户端。
7)客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;
dn1每传一个packet会放入一个应答队列等待应答。
8)当一个block传输完成之后,客户端再次请求NameNode上传第二个block的服务器。(重复执行3-7步)。
HDFS读数据过程
1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet为单位来做校验)。
4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件。
secondary namenode工作机制(☆☆☆☆☆)
1)第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对数据进行增删改查。
2)第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问NameNode是否需要checkpoint。直接带回NameNode是否检查结果。
(2)Secondary NameNode请求执行checkpoint。
(3)NameNode滚动正在写的edits日志。
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint。
(7)拷贝fsimage.chkpoint到NameNode。
(8)NameNode将fsimage.chkpoint重新命名成fsimage。
checkPoint检查点时间设置:
1:通常情况下每隔1小时执行一次
2:一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次
NameNode与SecondaryNameNode 的区别与联系?(☆☆☆☆☆)
1)区别
(1)NameNode负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息。
(2)SecondaryNameNode主要用于定期合并命名空间镜像和命名空间镜像的编辑日志。
2)联系:
(1)SecondaryNameNode中保存了一份和namenode一致的镜像文件(fsimage)和编辑日志(edits)。
(2)在主namenode发生故障时(假设没有及时备份数据),可以从SecondaryNameNode恢复数据。
HAnamenode 是如何工作的? (☆☆☆☆☆)
ZKFailoverController主要职责
1)健康监测:周期性的向它监控的NN发送健康探测命令,从而来确定某个NameNode是否处于健康状态,如果机器宕机,心跳失败,那么zkfc就会标记它处于一个不健康的状态。
2)会话管理:如果NN是健康的,zkfc就会在zookeeper中保持一个打开的会话,如果NameNode同时还是Active状态的,那么zkfc还会在Zookeeper中占有一个类型为短暂类型的znode,
当这个NN挂掉时,这个znode将会被删除,然后备用的NN,将会得到这把锁,升级为主NN,同时标记状态为Active。
3)当宕机的NN新启动时,它会再次注册zookeper,发现已经有znode锁了,便会自动变为Standby状态,如此往复循环,保证高可靠,需要注意,目前仅仅支持最多配置2个NN。
4)master选举:如上所述,通过在zookeeper中维持一个短暂类型的znode,来实现抢占式的锁机制,从而判断那个NameNode为Active状态
Namenode故障处理方法
Namenode故障后,可以采用如下两种方法恢复数据。
方法一:将SecondaryNameNode中数据拷贝到namenode存储数据的目录;
方法二:使用-importCheckpoint选项启动namenode守护进程,从而将SecondaryNameNode中数据拷贝到namenode目录中。
5.8.1 手动拷贝SecondaryNameNode数据:
模拟namenode故障,并采用方法一,恢复namenode数据
1)kill -9 namenode进程
2)删除namenode存储的数据(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)
[atguigu@hadoop102 hadoop-2.7.2]$ rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
3)拷贝SecondaryNameNode中数据到原namenode存储数据目录
[atguigu@hadoop102 dfs]$ scp -r atguigu@hadoop104:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary/* ./name/
4)重新启动namenode
[atguigu@hadoop102 hadoop-2.7.2]$ sbin/hadoop-daemon.sh start namenode
5.8.2 采用importCheckpoint命令拷贝SecondaryNameNode数据
模拟namenode故障,并采用方法二,恢复namenode数据
0)修改hdfs-site.xml中的
1)kill -9 namenode进程
2)删除namenode存储的数据(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)
[atguigu@hadoop102 hadoop-2.7.2]$ rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
3)如果SecondaryNameNode不和Namenode在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到Namenode存储数据的平级目录,并删除in_use.lock文件。
[atguigu@hadoop102 dfs]$ scp -r atguigu@hadoop104:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary ./
[atguigu@hadoop102 namesecondary]$ rm -rf in_use.lock
[atguigu@hadoop102 dfs]$ pwd
/opt/module/hadoop-2.7.2/data/tmp/dfs
[atguigu@hadoop102 dfs]$ ls
data name namesecondary
4)导入检查点数据(等待一会ctrl+c结束掉)
[atguigu@hadoop102 hadoop-2.7.2]$ bin/hdfs namenode -importCheckpoint
5)启动namenode
[atguigu@hadoop102 hadoop-2.7.2]$ sbin/hadoop-daemon.sh start namenode
文件格式:SequenceFile
------------------
1.SequenceFile
Key-Value对方式。
2.不是文本文件,是二进制文件。
3.可切割
因为有同步点。
reader.sync(pos); //定位到pos之后的第一个同步点。
writer.sync(); //写入同步点
4.压缩方式
不压缩
record压缩 //只压缩value
块压缩 //按照多个record形成一个block.
文件格式:MapFile
--------------------
1.Key-value
2.key按升序写入(可重复)。
3.mapFile对应一个目录,目录下有index和data文件,都是序列文件。
4.index文件划分key区间,用于快速定位。