大数据面试总结
大数据基础部分面试题:
一.你了解Hadoop吗?讲一下Hadoop中HDFS的读写原理。
读:
客户端调用FileSystem的open方法,来打开希望读取的文件。
FileSystem通过Rpc与namenode通信,namenode将获取到的信息整理,并将文件的所有内容发送给FileSystem对象,所有的副本块都会有对应的datanode位置信息;namenode会根据当前的所有节点状态判断最佳datanode位置,并且将此datanode的位置信息封装到传送的信息中。
客户端通过FileSystem返回的流对象,调用read方法,开始读取文件的数据,如果一个文件非常大,数据块数量庞大,namenode不会一次性返回所有的块信息,而是一批一批的返回,并且从第一批开始逐次读取。
对于客户端来讲,读取数据的操作是不透明的,用户并不需要关心底层流在数据块之间的跳转,或者读取失败后的流跳转,底层流对象会从第一个数据块开始,直接调用当前的FileSystem返回的流对象的read方法进行连续读取。
按照顺序每当读完一个数据块,底层流会跳转到下一个数据块读取。
当所有的数据块读取完毕,用户调用FSDataInputStream的close方法进行关流即可。
写:
客户端调用文件系统create()方法,创建一个新文件。
FileSystem通过Rpc通信,与namenode沟通,在HDFS的命名空间创建一个空的文件名称,对应一条元数据记录,namenode会根据文件名称和客户端的操作权限进行校验,如果校验失败,则返回IO异常,如果校验成功就创建临时的数据记录。
create()方法调用后,FileSystem对象返回一个流对象(DFSOutputStream),客户端调用流的write方法进行写入操作,数据源将会被底层流切分成一个一个64kb大小的package,并在内部以数据队列“dataqueue”的形式管理这些package。
保存在DataStreamer队列(dataqueue)里的package将会被写入到对应第一个数据块的最近datanode中,与此同时,package将会从dataqueue里移出,复制到ack queue中等待确认信息的反馈;在传输过程中,namenode返回的每个数据块副本所在的datanode都会彼此之间建立pipeline,写入到pipeline中的第一个datanode的package会通过双工通信,传到第二个,第二个传到第三个,并且每个datanode每次传完一个package都会放入一个到ack queue中。
每一个节点写入package的时候,在完成写入后会反馈一个当前package的写成信息,当最后一个datanode成功存储之后会返回一个ack package,ack queue成功收到datanode返回的ack package后,保存在ack queue中的package才会移出,到此为止才算一个package写入成功。
当所有的数据客户端调用write方法写完后会立刻调用close方法,将内部的所有缓存flush,这时留存在dataqueue里的package也会全部写入到pipeline中。
等到所有的写入完成,会判断当前的文件写入是否成功,判断的条件是所有文件的block的副本数量都达到了最小值(默认情况下是1);
四.Kfaka中topic和partition的关系是什么,如何理解?
topic在逻辑上可以被认为是一个queue。每条消费都必须指定它的topic,可以简单理解为必须指明把这条消息放进哪个queue里。为了使得 Kafka的吞吐率可以水平扩展,物理上把topic分成一个或多个partition,每个partition在物理上对应一个文件夹,
该文件夹下存储 这个partition的所有消息和索引文件。partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。
五.Mapreduce的shuffle过程
当MAP函数开始产生输出时,不是直接将文件写入到磁盘中,而是先将数据写入到缓存中,并对数据进行一系列的优化操作,以减少数据传输的量,并减少REDUCE端的操作。
首先每个MAP会有一个100MB大小的缓冲区,数据从MAP函数输出时会先进入到缓冲区,当到达缓冲区的阈值(80%)时,一个后台线程开始把数据SPILL(溢出)到磁盘中,此时数据仍然会不断的写入到缓存中,若缓冲区已满,数据会阻塞等待数据从缓冲区写入磁盘,
当缓冲区有剩余大小时,才继续写入到缓冲区。
在写入磁盘前,数据会根据REDUCE的数量并按照MAP函数输出的KEY值进行PARTITION分区,这样做的好处是可以将KEY值相同的数据最终汇聚到同一个REDUCE任务中,提高效率。在每个分区中,后台线程会对数据也按照KEY值进行排序,
并且在排序后若存在COMBINER合并任务,会将数据按照合并的要求进行合并,其实COMBINER的过程也就是一个小型的REDUCER,这样做的好处是减少REDUCE端的操作。在讲数据写入磁盘的过程中对数据进行压缩,也是一个很好的选择,
可以加快磁盘写入的效率,并且节约磁盘空间,从而减少传输到REDUCE任务端的数据量。
在REDUCE端会通过心跳机制向jobTracker来获取已经执行完毕的MAP任务,通过HTTP的方式来获得分区文件信息,REDUCE默认存在5个复制线程来对分区中的文件进行复制,在REDUCE端也会村在一个缓冲区,来处理复制过来的文件,若缓冲区同样达到阈值,
会将处理的文件写入磁盘,在缓冲区处理文件时,若在MAP阶段对数据进行了压缩操作,在REDUCE端需要对数据进行解压缩才可以处理。最后数据就会进入REDUCE函数进行合并。最终输出到HDFS文件系统中。
六.Hadoop的调度机制
1.先入先出FIFO
Hadoop 中默认的调度器,它先按照作业的优先级高低,再按照到达时间的先后选择被执行的作业。
2.公平调度器(相当于时间片轮转调度)
为任务分配资源的方法,其目的是随着时间的推移,让提交的作业获取等量的集群共享资源,让用户公平地共享集群。具体做法是:当集群上只有一个任务在运行时,它将使用整个集群,当有其他作业提交时,
系统会将TaskTracker节点空间的时间片分配给这些新的作业,并保证每个任务都得到大概等量的CPU时间。
配置公平调度器
3.容量调度器
支持多个队列,每个队列可配置一定的资源量,每个队列采用 FIFO 调度策略,为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占资源量进行限定。调度时,首先按以下策略选择一个合适队列:
计算每个队列中正在运行的任务数与其应该分得的计算资源之间的比值,选择一个该比值最小的队列;然后按以下策略选择该队列中一个作业:按照作业优先级和提交时间顺序选择 ,同时考虑用户资源量限制和内存限制。但是不可剥夺式。
七.Hive中内部表与外部表的区别:
Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,
不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。
八.Hadoop的二次排序
第一种方法是,Reducer将给定key的所有值都缓存起来,然后对它们再做一个Reducer内排序。但是,由于Reducer需要保存给定key的所有值,可能会导致出现内存耗尽的错误。
第二种方法是,将值的一部分或整个值加入原始key,生成一个组合key。这两种方法各有优势,第一种方法编写简单,但并发度小,数据量大的情况下速度慢(有内存耗尽的危险),
第二种则是将排序的任务交给MapReduce框架shuffle,更符合Hadoop/Reduce的设计思想。我们将编写一个Partitioner,确保拥有相同key(原始key,不包括添加的部分)的所有数据被发往同一个Reducer,
还将编写一个Comparator,以便数据到达Reducer后即按原始key分组。
九.所有的hive任务都会有reducer的执行吗?
答:不是,由于当前hive的优化,使得一般简单的任务不会去用reducer任务;只有稍微复杂的任务才会有reducer任务
举例:使用select * from person ; 就不会有reducer
十.hive表关联查询,如何解决数据倾斜的问题?
倾斜原因:
map输出数据按key Hash的分配到reduce中,由于key分布不均匀、业务数据本身的特、建表时考虑不周、等原因造成的reduce 上的数据量差异过大。
1)、key分布不均匀;
2)、业务数据本身的特性;
3)、建表时考虑不周;
4)、某些SQL语句本身就有数据倾斜;
如何避免:对于key为空产生的数据倾斜,可以对其赋予一个随机值。
解决方案
1>.参数调节:
hive.map.aggr = true
hive.groupby.skewindata=true
有数据倾斜的时候进行负载均衡,当选项设定位true,生成的查询计划会有两个MR Job。
第一个MR Job中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,
这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;
第二个MR Job再根据预处理的数据结果按照Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个Reduce中),最后完成最终的聚合操作。
2>.SQL 语句调节:
1)、选用join key分布最均匀的表作为驱动表。做好列裁剪和filter操作,以达到两表做join 的时候,数据量相对变小的效果。
2)、大小表Join:
使用map join让小的维度表(1000 条以下的记录条数)先进内存。在map端完成reduce.
4)、大表Join大表:
把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null 值关联不上,处理后并不影响最终结果。
5)、count distinct大量相同特殊值:
count distinct 时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。
十一. 请谈一下hive的特点是什么?
hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。
其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
十二. Kafka主要特点:
同时为发布和订阅提供高吞吐量。据了解,Kafka每秒可以生产约25万消息(50 MB),每秒处理55万消息(110 MB)。
可进行持久化操作。将消息持久化到磁盘,因此可用于批量消费,例如ETL,以及实时应用程序。通过将数据持久化到硬盘以及replication防止数据丢失。
分布式系统,易于向外扩展。所有的producer、broker和consumer都会有多个,均为分布式的。无需停机即可扩展机器。
消息被处理的状态是在consumer端维护,而不是由server端维护。当失败时能自动平衡。
支持online和offline的场景。
十三. Spark性能优化主要有哪些手段?
将默认调用的java序列化器改为kyro序列化器(减少序列化数据80%的空间占用(问:为何序列化可以减少存储空间占用(回答:对同类型的数据对象的头进行压缩合并:我感觉这个我回答错误了)));
由于Spark1.6.0的统一内存管理模型,若算法的数据量大,而计算逻辑较为简单,可以增大内存管理中cache块的比例(默认70%(我也一下子想不起来,感觉这个附近)),如果是数据量小而算法逻辑复杂,可以适当减少cache快的比例;
如果因对是集群CPU资源过分盈余,可以采用增加core的数目,但是core的数目增加到一定程度后,依旧无法完全利用CPU的计算资源,可以选择增加Executor的数目,通常环境下,一个Executor推荐设置5个Core的个数,超过5个推荐增加Executor的个数
十四.用mapreduce如何处理数据倾斜问题
数据倾泻产生原因:其次在reduce端默认的分区方式为按照map函数输出key的哈希值,根据哈希值将数据散列在Reduce中,这尽在数据分布比较均衡的情况下比较适用。
首先在MAP函数中增加记录数据倾斜的日志信息,可以通过代码实现,当某个key值超过预先设定的范围就打印该key值的日志
自定义分区方法,可以对原始数据进行抽样的结果来预设定分区的边界,totalOrderPartitioner中的范围分区器可以通过预设的分区值进行分区。另一个自定义分区方法是根据数据输出键的背景知识来自定义分区,假如map输出的键值来自于一本书,其中大部分则肯定是省略词,那么就可以自定义分区将这部分省略次分区到一个REDUCE中,将剩下的键值保存在其他的REDUCE中
执行两次MR的过程,第一次不按照KEY值进行分区,打散数据到REDUCE端,在进行一次MR的操作,这次按照KEY值分区,可以有效的减少数据倾斜的问题。
十五. 列举你知道的常用的hadoop管理和监控的命令
-ls -cat -text -cp -put -chmod -chown
-du -get -copyFromLocal -copyToLocal
-mv -rm - tail -chgrp
十六. 在mr环节中,那些环节需要优化,如何优化,请详细说明。
1、 setNumReduceTasks 适当的设置reduce的数量,如果数据量比较大,那么可以增加reduce的数量
2、适当的时候使用 combine 函数,减少网络传输数据量
3、压缩map和reduce的输出数据
4、使用SequenceFile二进制文件。
5、通过application 的ui页面观察job的运行参数
6、太多小文件,造成map任务过多的问题,应该可以先合并小文件,或者有一个特定的map作为处理小文件的输入
7、map端效率低原因分析
源文件的大小远小于HDFS的块的大小。这意味着任务的开启和停止要耗费更多的时间,就没有足够的时间来读取并处理输入数据。
源文件无法分块。这导致需要通过网络IO从其他节点读取文件块。
一个节点的本地磁盘或磁盘控制器运行在降级模式中,读取写入性能都很差。这会影响某个节点,而不是全部节点。
源文件不来自于HDFS。则可能是Hadoop节点和数据源之间的延迟导致了性能低下。
Map任务从其他数据节点读取数据。可以从JobTracker的map任务细节信息和任务运行尝试中找到输入块的位置。如果输入块的位置不是任务执行的节点,那就不是本地数据了。
十七. 如何用MAPREDUCE实现两张表的连接
方案一:Reduce side join。在Map阶段读取两张表F1,F2,分别对读取的KEY VALUE进行TAG标签,然后输入到REDUCE端,REDUCE端得到数据后按照相同KEY值,对不同标签的相同KEY值进行JOIN。
方案二:由于在REDUCE端进行JOIN效率十分低,因为在MAP端有大量的数据进行SHUFFLE到REDUCE端。所以在以下情况下我们可以考虑在MAP端进行JOIN,若两张表中有一张表比较少,甚至可以放到内存中,那么我们可以利用HADOOP的中DISTRIBUTEDCATCH.ADDCATCHFILE()将文件加载到缓存中,他的参数是URL,在JOBTRACKER加载任务时,会将这个URL下的文件拷贝到各个TASKTRACKER上,并通过DISTRIBUTEDCATCH.GETLOCALCATCHFILE()获取这个文件,从而进行JOIN操作。
十八. fsimage和edit的区别?
Fsimage是在namenode节点中保存了文件系统所有的目录、文件信息,文件信息中包含数据块描述信息,修改时间,访问时间等。对于目录来说包括修改时间,访问权限信息。edit保存的是当对hdfs进行增删改时记录的操作,在HADOOP中存在secoundNamenode节点,当namenode中的小文件太多时,将两个文件发送到secoundNamenode中进行和并,并发送会Namenode来保证当前hdfs中信息的完整。
十九. synchronized和lock的区别
synchronized:在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
lock:需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
二十一. HDFS存储大量的小文件会有什么问题,如何解决?
(1)HDFS不适合大量小文件的存储,因namenode将文件系统的元数据存放在内存中,因此存储的文件数目受限于 namenode的内存大小。HDFS中每个文件、目录、数据块占用150Bytes。如果存放的文件数目过多的话会占用很大的内存
(2)HDFS适用于高吞吐量,而不适合低时间延迟的访问。如果同时存入大量的小文件会花费很长的时间
(3) 流式读取的方式,不适合多用户写入,以及任意位置写入。如果访问小文件,则必须从一个datanode跳转到另外一个datanode,这样大大降低了读取性能。
二十二.Hbase的表设计原则
HBase表的设计 主要是 列族的设计 和 行键的设计
1.列族的设计
在设计hbase表时候,列族不宜过多,越少越好,官方推荐hbase表的列族不宜超过3个。
经常要在一起查询的数据最好放在一个列族中,尽量的减少跨列族的数据访问。
如果有多个列族 多个列族中的数据应该设计的比较均匀
2.行键的设计
hbase表中行键是唯一标识一个表中行的字段,所以行键设计的好不好将会直接影响未来对hbase的查询的性能和查询的便利性
所以hbase中的行键是需要进行设计的
行键设计的基本原则:行键必须唯一必须唯一才能唯一标识数据行键必须有意义这样才能方便数据的查询行键最好是字符串类型因为数值类型在不同的系统中处理的方式可能不同行键最好具有固定的长度不同长度的数据可能会造成自然排序时排序的结果和预期不一致行键不宜过长行键最多可以达到64KB,但是最好是在10~100字节之间,最好不要超过16字节,越短越好,最好是8字节的整数倍。行键的最佳实践:散列原则:行键的设计将会影响数据在hbase表中的排序方式,这会影响region切分后的结果,要注意,在设计行键时应该让经常要查询的数据分散在不同的region中,防止某一个或某几个regionserver成为热点。有序原则:行键的设计将会影响数据在hbase表中的排序方式,所以一种策略是将经常连续查询的条件作为行键最前面的数据,这样一来可以方便批量查询
二十三.Hadoop的压缩算法
Hadoop 对于压缩格式的是自动识别。如果我们压缩的文件有相应压缩格式的扩展名(比如 lzo,gz,bzip2 等)。
Hadoop 会根据压缩格式的扩展名自动选择相对应的解码器来解压数据,此过程完全是 Hadoop 自动处理,我们只需要确保输入的压缩文件有扩展名。
Hadoop 对每个压缩格式的支持, 详细见下表:
压缩格式 工具 算法 扩展名 多文件 可分割性
DEFLATE 无 DEFLATE .deflate 不 不
GZIP gzip DEFLATE .gzp 不 不
ZIP zip DEFLATE .zip 是 是,在文件范围内
BZIP2 bzip2 BZIP2 .bz2 不 是
LZO lzop LZO .lzo 不 是
如果压缩的文件没有扩展名,则需要在执行 MapReduce 任务的时候指定输入格式。
-
Bzip2 压缩效果明显是最好的,但是 bzip2 压缩速度慢,可分割。
-
Gzip 压缩效果不如 Bzip2,但是压缩解压速度快,不支持分割。
-
LZO 压缩效果不如 Bzip2 和 Gzip,但是压缩解压速度最快!并且支持分割!
1.gzip压缩
优点:
压缩率比较高,而且压缩/解压速度也比较快;
hadoop本身支持,在应用中处理gzip格式的文件就和直接处理文本一样;
有hadoop native库;
大部分linux系统都自带gzip命令,使用方便。
缺点:不支持split。
应用场景:
当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用gzip压缩格式。譬如说一天或者一个小时的日志压缩成一个gzip文件,运行mapreduce程序的时候通过多个gzip文件达到并发。
hive程序,streaming程序,和java写的mapreduce程序完全和文本处理一样,压缩之后原来的程序不需要做任何修改。
2.lzo压缩
优点:
压缩/解压速度也比较快,合理的压缩率;
支持split,是hadoop中最流行的压缩格式;
支持hadoop native库;
可以在linux系统下安装lzop命令,使用方便。
缺点:
压缩率比gzip要低一些;
hadoop本身不支持,需要安装;
在应用中对lzo格式的文件需要做一些特殊处理(为了支持split需要建索引,还需要指定inputformat为lzo格式)。
应用场景:
一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点越明显。
3.snappy压缩
优点:
高速压缩速度和合理的压缩率;
支持hadoop native库。
缺点:
不支持split;
压缩率比gzip要低;
hadoop本身不支持,需要安装;
linux系统下没有对应的命令。
应用场景:
当mapreduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式;
或者作为一个mapreduce作业的输出和另外一个mapreduce作业的输入。
4.bzip2压缩
优点:
支持split;
具有很高的压缩率,比gzip压缩率都高;
hadoop本身支持,但不支持native;
在linux系统下自带bzip2命令,使用方便。
缺点:
压缩/解压速度慢;
不支持native。
应用场景:
适合对速度要求不高,但需要较高的压缩率的时候,可以作为mapreduce作业的输出格式;
或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情况;
或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持split,而且兼容之前的应用程序(即应用程序不需要修改)的情况。
二十九.Hive UDF编写错误从哪方面调错?
首先查日志,UDF的日志是保存在Hadoop MR的日志文件中,
其次通过错误提示通过管道符grep |查找问题所在,并针对问题进行改进
在日志文件过大的情况下,可以通过head tail sed 等指令进行分段查找