大数据面试题

1. 下面哪个程序负责 HDFS 数据存储?

a)NameNode  b)Jobtracker  c)Datanode d)secondaryNameNode e)tasktracker

答案 C datanode

 

2. HDfS 中的 block 默认保存几份?

a)3 份 b)2 份 c)1 份 d)不确定

答案 A 默认 3 份

 

3. 下列哪个程序通常与NameNode在一个节点启动?

a)SecondaryNameNode b)DataNode c)TaskTracker d)Jobtracker

答案 D

 

4. HDFS 默认 Block Size

1.x是64M;  2.x是128M

 

5. 下列哪项通常是集群的最主要瓶颈?

a)CPU   b)网络 c)磁盘 IO  d)内存

答案:C 磁盘

首先集群的目的是为了节省成本,用廉价的 pc 机,取代小型机及大型机。小型机和大型机有什么特点?

1).cpu 处理能力强

2).内存够大,所以集群的瓶颈不可能是 a 和 d

3).如果是互联网有瓶颈,可以让集群搭建内网。每次写入数据都要通过网络(集群是内网),然后还要写入 3 份数据,所以 IO 就会打折扣。

 

6. 关于 SecondaryNameNode 哪项是正确的?

a)它是 NameNode 的热备     

b)它对内存没有要求

c)它的目的是帮助 NameNode 合并编辑日志,减少 NameNode 启动时间

d)SecondaryNameNode 应与 NameNode 部署到一个节点

答案 C。

 

7. 下列哪项可以作为集群的管理?

a)Puppet b)Pdsh c)Cloudera Manager d)Zookeeper

答案 ABD

具体可查看什么是 Zookeeper,Zookeeper 的作用是什么,在 Hadoop 及 hbase 中具体作用是什么。

 

8. Client 端上传文件的时候下列哪项正确?

a)数据经过 NameNode 传递给 DataNode

b)Client 端将文件切分为 Block,依次上传

c)Client 只上传数据到一台 DataNode,然后由 NameNode 负责 Block 复制工作

答案 B

分析:Client 向 NameNode 发起文件写入的请求。NameNode 根据文件大小和文件块配置情况,返回给 Client 它所管理部分 DataNode 的信息。Client 将文件划分为多个 Block,根据 DataNode 的地址信息,按顺序写入到每一个DataNode 块中。具体查看HDFS 体系结构简介及优缺点。

 

9. 下列哪个是 Hadoop 运行的模式

a)单机版 b)伪分布式 c)分布式

答案 ABC                      单机版,伪分布式只是学习用的。

 

10. Hadoop的核心配置是什么?

Hadoop的核心配置通过两个xml文件来完成:1,hadoop-default.xml;2,hadoop-site.xml。这些文件都使用xml格式,因此每个xml中都有一些属性,包括名称和值,但是当下这些文件都已不复存在。

10.1 那当下又该如何配置?

Hadoop现在拥有3个配置文件:1,core-site.xml;2,hdfs-site.xml;3,mapred-site.xml。这些文件都保存在conf/子目录下。

 

11. hadoop中Combiner的作用?

combiner是reduce的实现,在map端运行计算任务,减少map端的输出数据。

combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量

作用就是优化。

但是combiner的使用场景是: mapreduce的map和reduce两者的输入输出一样,否则不能使用Combiner。

 

12. 简述hadoop安装。

 

13. 请列出hadoop进程名

 

14. 解决下面的错误

  1. 权限问题,可能曾经用root启动过集群。(例如hadoop搭建的集群,是tmp/hadoop-hadoop/.....)
  2. 可能是文件夹不存在
  3. 解决: 删掉tmp下的那个文件,或改成当前用户

 

15. 简述hadoop的调度器

 

16. hive有哪些保存元数据的方式,个有什么特点。

  1. 内存数据库derby,安装小,但是数据存在内存,不稳定。
  2. mysql数据库,数据存储模式可以自己设置,持久化好,查看方便。

 

17. combiner和partition的作用

combiner是reduce的实现,在map端运行计算任务,减少map端的输出数据。作用就是优化。

但是combiner的使用场景是mapreduce的map输出结果和reduce输入输出一样。

partition的默认实现是hashpartition,是map端将数据按照reduce个数取余,进行分区,不同的reduce来copy自己的数据。

partition的作用是将数据分到不同的reduce进行计算,加快计算速度。

 

18. hive内部表和外部表的区别

内部表:加载数据到hive所在的hdfs目录,删除时,元数据和数据文件都删除

外部表:不加载数据到hive所在的hdfs目录,删除时,只删除表结构。

 

19. hbase的rowkey怎么创建好?列族怎么创建比较好?

hbase存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分利用排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)

一个列族在数据底层是一个文件,所以将经常一起查询的列放到一个列族中,列族要尽量少,减少文件的寻址时间。

 

20. ​​​​​​​用mapreduce怎么处理数据倾斜问题?

数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜。

用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;

  }

 

21. ​​​​​​​我们开发job时,是否可以去掉reduce阶段。

可以。设置reduce数为0 即可。

 

​​​​​​​22. datanode在什么情况下不会备份

datanode在强制关闭或者非常断电不会备份。

 

​​​​​​​23. combiner出现在那个过程

出现在map阶段的map方法后。

 

​​​​​​​24. hdfs的体系结构

hdfs有namenode、secondraynamenode、datanode组成。

为n+1模式

namenode负责管理datanode和记录元数据

secondraynamenode负责合并日志

datanode负责存储数据

 

​​​​​​​25. 3个datanode中有一个datanode出现错误会怎样?

这个datanode的数据会在其他的datanode上重新做备份。

 

26. ​​​​​​​描述一下hadoop中,有哪些地方使用了缓存机制,作用分别是什么?

在mapreduce提交job的获取id之后,会将所有文件存储到分布式缓存上,这样文件可以被所有的mapreduce共享。

 

​​​​​​​27. 如何确定hadoop集群的健康状态

通过页面监控,脚本监控(监控相关进程是否存活)。

 

28. ​​​​​​​​​​​​​​生产环境中为什么建议使用外部表?

1) 因为外部表不会加载数据到hive,减少数据传输、数据还能共享。

2) hive不会修改数据,所以无需担心数据的损坏

3) 删除表时,只删除表结构、不删除数据。

 

29. 如何检查namenode是否正常运行?重启namenode的命令是什么?

通过节点信息和浏览器查看,通过脚本监控

如何namenode还在运行,则

hadoop-daemon.sh stop namenode

hadoop-daemon.sh start namenode

否则:

hadoop-daemon.sh start namenode

 

30. 避免namenode故障导致集群拓机的方法是什么?

HA高可用

 

31. hbase数据库对行键的设计要求是什么?

行健以字典序排列,设计时充分利用这个特点,将经常一起查询的行健设计在一起,例如时间戳结尾,用户名开头(位置相关性)

 

32. ​​​​​​​一个datanode 宕机,怎么一个流程恢复

datanode 宕机后,其数据会重新备份到其它可用的datanode上,因此将datanode数据删除,重新当成新节点加入即可。

 

33. ​​​​​​​Hbase 的特性,以及你怎么去设计 rowkey 和 columnFamily ,怎么去建一个table

hbase是列式数据库,rowkey是字典序的,设计时的规则同上。

每个列族是一个文件,将经常一起查询的列放到同一个列族中,减少文件的寻址时间。

 

34. ​​​​​​​Mapreduce 的 map 数量 和 reduce 数量 怎么确定 ,怎么配置

map的数量有数据块决定,reduce数量可以通过参数配置。

 

35. 给定a,b两个文件,每个文件中有50亿个url,每个url为64字节,内存限制为4G,怎样找出两个文件中共同的url?

可以估计每个文件的大小为50亿×64=298G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。

  1. 将文件存储到hdfs中,这样每个文件为64M或者是128M
  2. 分别对两个文件的url进行去重、排序输出,这样能排除a文件中相同的url,b文件也一样
  3. 对a、b两个文件处理后的结果进行wordcount,并且在reduce中判断单词个数,个数为2的时候输出,这样就找到了a、b文件中的相同url。

此计算步骤中的每一步加载到内存中的文件大小都不会超过64M,远远小于4G。

 

36. 1亿个数据获取前100个最大值

topk,强调使用treemap是为了节省内存计算空间。

 

37. 多线程实现方式 Thread和Runnable的区别

在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。

下面看例子:

  1. package org.thread.demo;  
  2. class MyThread extends Thread{  
  3. private String name;  
  4. public MyThread(String name) {  
  5. super();  
  6. this.name = name;  
  7. }  
  8. public void run(){  
  9. for(int i=0;i<10;i++){  
  10. System.out.println("线程开始:"+this.name+",i="+i);  
  11. }  
  12. }  
  13. }  
  14. package org.thread.demo;  
  15. public class ThreadDemo01 {  
  16. public static void main(String[] args) {  
  17. MyThread mt1=new MyThread("线程a");  
  18. MyThread mt2=new MyThread("线程b");  
  19. mt1.run();  
  20. mt2.run();  
  21. }  

但是,此时结果很有规律,先第一个对象执行,然后第二个对象执行,并没有相互运行。在JDK的文档中可以发现,一旦调用start()方法,则会通过JVM找到run()方法。下面启动start()方法启动线程:

  1. package org.thread.demo;  
  2. public class ThreadDemo01 {  
  3. public static void main(String[] args) {  
  4. MyThread mt1=new MyThread("线程a");  
  5. MyThread mt2=new MyThread("线程b");  
  6. mt1.start();  
  7. mt2.start();  
  8. }  
  9. }; 

这样程序可以正常完成交互式运行。那么为啥非要使用start();方法启动多线程呢?

在JDK的安装路径下,src.zip是全部的java源程序,通过此代码找到Thread中的start()方法的定义,可以发现此方法中使用了private native void start0();其中native关键字表示可以调用操作系统的底层函数,那么这样的技术成为JNI技术(java Native Interface)

Runnable接口

在实际开发中一个多线程的操作很少使用Thread类,而是通过Runnable接口完成。

  1. public interface Runnable{  
  2. public void run();  

例子:

  1. package org.runnable.demo;  
  2. class MyThread implements Runnable{  
  3. private String name;  
  4. public MyThread(String name) {  
  5. this.name = name;  
  6. }
  7. public void run(){  
  8. for(int i=0;i<100;i++){  
  9. System.out.println("线程开始:"+this.name+",i="+i);  
  10. }  
  11. }  
  12. }; 

但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有。此时观察Thread类,有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多线程。(start()可以协调系统的资源):

  1. package org.runnable.demo;  
  2. import org.runnable.demo.MyThread;  
  3. public class ThreadDemo01 {  
  4. public static void main(String[] args) {  
  5. MyThread mt1=new MyThread("线程a");  
  6. MyThread mt2=new MyThread("线程b");  
  7. new Thread(mt1).start();  
  8. new Thread(mt2).start();  
  9. }  

两种实现方式的区别和联系:

在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:

  • 避免点继承的局限,一个类可以继承多个接口。
  • 适合于资源的共享

以卖票程序为例,通过Thread类完成:

  1. package org.demo.dff;  
  2. class MyThread extends Thread{  
  3. private int ticket=10;  
  4. public void run(){  
  5. for(int i=0;i<20;i++){  
  6. if(this.ticket>0){  
  7. System.out.println("卖票:ticket"+this.ticket--);  
  8. }  
  9. }  
  10. }  
  11. }; 

下面通过三个线程对象,同时卖票:

  1. package org.demo.dff;  
  2. public class ThreadTicket {  
  3. public static void main(String[] args) {  
  4. MyThread mt1=new MyThread();  
  5. MyThread mt2=new MyThread();  
  6. MyThread mt3=new MyThread();  
  7. mt1.start();//每个线程都各卖了10张,共卖了30张票  
  8. mt2.start();//但实际只有10张票,每个线程都卖自己的票  
  9. mt3.start();//没有达到资源共享  
  10. }  

如果用Runnable就可以实现资源共享,下面看例子:

  1. package org.demo.runnable;  
  2. class MyThread implements Runnable{  
  3. private int ticket=10;  
  4. public void run(){  
  5. for(int i=0;i<20;i++){  
  6. if(this.ticket>0){  
  7. System.out.println("卖票:ticket"+this.ticket--);  
  8. }  
  9. }  
  10. }  
  11. }  
  12. package org.demo.runnable;  
  13. public class RunnableTicket {  
  14. public static void main(String[] args) {  
  15. MyThread mt=new MyThread();  
  16. new Thread(mt).start();//同一个mt,但是在Thread中就不可以,如果用同一  
  17. new Thread(mt).start();//个实例化对象mt,就会出现异常  
  18. new Thread(mt).start();  
  19. }  
  20. }; 

虽然现在程序中有三个线程,但是一共卖了10张票,也就是说使用Runnable实现多线程可以达到资源共享目的。

 

38. 一个HADOOP环境整合了HBASE和HIVE,是否有必要给HDFS和HBASE都分别配置压缩策略?请给出压缩策略建议。

hdfs在存储的时候不会将数据进行压缩,如果想进行压缩,我们可以在向hdfs上传数据的时候进行压缩。

                    1) 采用压缩流

//压缩文件

    public static void compress(String codecClassName) throws Exception{

        Class<?> codecClass = Class.forName(codecClassName);

        Configuration conf = new Configuration();

        FileSystem fs = FileSystem.get(conf);

        CompressionCodec codec = (CompressionCodec)ReflectionUtils.newInstance(codecClass, conf);

        //指定压缩文件路径

        FSDataOutputStream outputStream = fs.create(new Path("/user/hadoop/text.gz"));

        //指定要被压缩的文件路径

        FSDataInputStream in = fs.open(new Path("/user/hadoop/aa.txt"));

        //创建压缩输出流

        CompressionOutputStream out = codec.createOutputStream(outputStream);  

        IOUtils.copyBytes(in, out, conf);

        IOUtils.closeStream(in);

        IOUtils.closeStream(out);

    }

                    2)采用序列化文件

public void testSeqWrite() throws Exception {

 

Configuration conf = new Configuration();// 创建配置信息

conf.set("fs.default.name", "hdfs://master:9000");// hdfs默认路径

conf.set("hadoop.job.ugi", "hadoop,hadoop");// 用户和组信息

String uriin = "hdfs://master:9000/ceshi2/";// 文件路径

FileSystem fs = FileSystem.get(URI.create(uriin), conf);// 创建filesystem

Path path = new Path("hdfs://master:9000/ceshi3/test.seq");// 文件名

IntWritable k = new IntWritable();// key,相当于int

Text v = new Text();// value,相当于String

SequenceFile.Writer w = SequenceFile.createWriter(fs, conf, path,

k.getClass(), v.getClass());// 创建writer

for (int i = 1; i < 100; i++) {// 循环添加

k.set(i);

v.set("abcd");

w.append(k, v);

}

w.close();

IOUtils.closeStream(w);// 关闭的时候flush

fs.close();

}

hbase为列存数据库,本身存在压缩机制,所以无需设计。

39. 如果要存储海量小文件,请简述方案。

1)将小文件打成har文件存储

2)将小文件合并成大文件(用数据库存储每个小文件的起始位置)

3)将小文件序列化到hdfs中

 

40. 说下对hadoop 的一些理解,包括哪些组件

详谈hadoop的应用,包括的组件分为三类,分别说明hdfs,yarn,mapreduce

 

41. ​​​​​​​Kafka direct API

为了WAL的性能损失和exactly-once,spark streaming1.3中使用Kafka direct API。非常巧妙,Spark driver计算下个batch的offsets,指导executor消费对应的topics和partitions。消费Kafka消息,就像消费文件系统文件一样。​​​​​​​

  • 不再需要kafka receivers,executor直接通过Kafka API消费数据
  • WAL不再需要,如果从失败恢复,可以重新消费
  • exactly-once得到了保证,不会再从WAL中重复读取数据

 

42. 假如一个分区的数据主部错误怎么通过hivesql删除hdfs

alter table ptable drop partition (daytime='20140911',city='bj');

元数据,数据文件都删除,但目录daytime= 20140911还在

 

43. 请写出以下的shell命令 

(1)杀死一个job

(2)删除hdfs上的 /tmp/aaa目录

(3)加入一个新的存储节点和删除一个节点需要执行的命令

Answers:

(1)hadoop job –list   得到job的id,然后执     行 hadoop job  -kill  jobId就可以杀死一个指定jobId的job工作了。

         yarn application -kill application_1513303851617_0784 ---yarn集群杀死job方式

(2)hadoop fs  -rmr  /tmp/aaa

  (3)  增加一个新的节点在新的几点上执行

            Hadoop  daemon.sh  start  datanode

            Hadooop  daemon.sh  start   tasktracker/nodemanager

 

43. 简述hadoop实现join的几种方法

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阶段进行实际的连接操作。

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的记录,如果有,则连接后输出即可。

SemiJoin

SemiJoin,也叫半连接,是从分布式数据库中借鉴过来的方法。它的产生动机是:对于reduce side join,跨机器的数据传输量非常大,这成了join操作的一个瓶颈,如果能够在map端过滤掉不会参加join操作的数据,则可以大大节省网络IO。

实现方法很简单:选取一个小表,假设是File1,将其参与join的key抽取出来,保存到文件File3中,File3文件一般很小,可以放到 内存中。在map阶段,使用DistributedCache将File3复制到各个TaskTracker上,然后将File2中不在File3中的 key对应的记录过滤掉,剩下的reduce阶段的工作与reduce side join相同。

 

44. 请简述mapreduce中的combine和partition的作用

combiner是发生在map的最后一个阶段,其原理也是一个小型的reducer,主要作用是减少输出到reduce的数据量,缓解网络传输瓶颈,提高reducer的执行效率。

partition的主要作用将map阶段产生的所有kv对分配给不同的reducer task处理,可以将reduce阶段的处理负载进行分摊

 

45. datanode在什么情况下不会备份数据

在客户端上传文件时指定文件副本数量为1

 

46. combine出现在哪个过程

shuffle过程中

具体来说,是在maptask输出的数据从内存溢出到磁盘,可能会调多次

Combiner使用时候要特别谨慎,不能影响最后的逻辑结果

 

47. 三个datanode中当有一个datanode出现错误时会怎样?

Namenode会通过心跳机制感知到datanode下线

会将这个datanode上的block块在集群中重新复制一份,恢复文件的副本数量

会引发运维团队快速响应,派出同事对下线datanode进行检测和修复,然后重新上线

 

48. MapReduce优化经验

  • 设置合理的map和reduce的个数。合理设置blocksize
  • 避免出现数据倾斜
  • combine函数
  • 对数据进行压缩
  • 小文件处理优化:事先合并成大文件,combineTextInputformat,在hdfs上用mapreduce将小文件合并成SequenceFile大文件(key:文件名,value:文件内容)
  • 参数优化

 

49. java 是传值还是传址?

引用传递。

 

50. 请简述hadoop怎样实现二级排序

   第一种方法是,Reducer将给定key的所有值都缓存起来,然后对它们再做一个Reducer内排序。但是,由于Reducer需要保存给定key的所有值,可能会导致出现内存耗尽的错误。

第二种方法是,将值的一部分或整个值加入原始key,生成一个合成key。这两种方法各有优势,第一种方法可能会更快一些(但有内存耗尽的危险),第二种方法则是将排序的任务交给MapReduce框架,更符合Hadoop/Reduce的设计思想。这篇文章里选择的是第二种。我们将编写一个Partitioner,确保拥有相同key(原始key,不包括添加的部分)的所有数据被发往同一个Reducer,还将编写一个Comparator,以便数据到达Reducer后即按原始key分组。

二次排序

有两种方法进行二次排序,分别为:buffer and in memory sort和 value-to-key conversion。

对于buffer and in memory sort,主要思想是:在reduce()函数中,将某个key对应的所有value保存下来,然后进行排序。 这种方法最大的缺点是:可能会造成out of memory。

对于value-to-key conversion,主要思想是:将key和部分value拼接成一个组合key(实现WritableComparable接口或者调用 setSortComparatorClass函数),这样reduce获取的结果便是先按key排序,后按value排序的结果,需要注意的是,用户需 要自己实现Paritioner,以便只按照key进行数据划分。Hadoop显式的支持二次排序,在Configuration类中有个 setGroupingComparatorClass()方法,可用于设置排序group的key值

 

51. hive中如何定义udf

  • 继承UDF类
  • 重写evaluate方法
  • 打jar包
  • 上传jar包
hive> add jar /home/hadoop/lib/hive-1.0.jar
  • 创建函数
create temporary function my_lower as 'com.example.hive.udf.Lower';
create function my_db.my_lower as 'com.example.hive.udf.Lower';
  • 使用
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值