Hadoop 中的面试题

1、MapTask并行机度是由什么决定的?
由切片数量决定的。

2、MR是干什么的?
MR将用户编写的业务逻辑代码和自带的默认组件结合起来组成一个完整的分布式应用程序放到hadoop集群上运行。
MR的实例进程:
driver(mr的job提交客户端)
MRAppMaster
MapTask
ReduceTask
combiner和partition的作用:
combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量
partition的默认实现是hashpartition,是map端将数据按照reduce个数取余,进行分区,不同的reduce来copy自己的数据。
partition的作用是将数据分到不同的reduce进行计算,加快计算效果。

3、什么是shuffle
map阶段处理的数据如何传递给reduce阶段,是mapreduce框架中最关键的一个流程,这个流程就叫shuffle;
shuffle: 洗牌、发牌——(核心机制:数据分区,排序,缓存);
具体来说:就是将maptask输出的处理结果数据,分发给reducetask,并在分发的过程中,对数据按key进行了分区和排序;
MR原理(详细解释参照:MR运行原理剖析):
InputFormat来读取数据,按行读取,返回KV值传到map方法中,
context.write方法将处理后数据输出到outputCollector中,
当outputCollector中的数据累计到一定数量后再将数据传到内存的环形缓冲区做处理,
当环形缓冲区中的数据累积到一定数量后再将数据通过Splier多次溢出到本地磁盘的多个文件中,期间会对各个溢出的数据进行分区、排序
然后对多个文件进行merge(归并排序)形成一个输出结果大文件
ruduceTask根据自己的分区号去各个mapTask机器上取输出结果文件
将得到的各个结果文件进行merge,然后进入reduce阶段,
context.write将最终结果输出到outPutformat上,进而输出到本地文件中。
举一个简单的例子说明mapreduce是怎么来运行的 ?

4、什么是yarn?
Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而mapreduce等运算程序则相当于运行于操作系统之上的应用程序。
namenode的safemode是怎么回事?如何才能退出safemode?
namenode在刚启动的时候元数据只有文件块信息,没有文件所在datanode的信息,需要datanode自己向namenode汇报。如果namenode发现datanode汇报的文件块信息没有达到namenode内存中所有文件块的总阈值的一个百分比,namenode就会处于safemode。
只有达到这个阈值,namenode才会推出safemode。也可手动强制退出。

5、hadoop的优化?
1)优化的思路可以从配置文件和系统以及代码的设计思路来优化
2)配置文件的优化:调节适当的参数,在调参数时要进行测试
3)代码的优化:combiner的个数尽量与reduce的个数相同,数据的类型保持一致,可以减少拆包与封包的进度
4)系统的优化:可以设置linux系统打开最大的文件数预计网络的带宽MTU的配置
5)为 job 添加一个 Combiner,可以大大的减少shuffer阶段的maoTask拷贝过来给远程的 reduce task的数据量,一般而言combiner与reduce相同。
6)在开发中尽量使用stringBuffer而不是string,string的模式是read-only的,如果对它进行修改,会产生临时的对象,二stringBuffer是可修改的,不会产生临时对象。
7)修改一下配置:以下是修改 mapred-site.xml 文件
a、修改最大槽位数:槽位数是在各个 tasktracker 上的 mapred-site.xml 上设置的,默认都是 2

mapred.tasktracker.map.tasks.maximum
2


mapred.tasktracker.reduce.tasks.maximum
2

b、调整心跳间隔:集群规模小于 300 时,心跳间隔为 300 毫秒
mapreduce.jobtracker.heartbeat.interval.min 心跳时间
mapred.heartbeats.in.second 集群每增加多少节点,时间增加下面的值
mapreduce.jobtracker.heartbeat.scaling.factor 集群每增加上面的个数,心跳增多少
c、启动带外心跳
mapreduce.tasktracker.outofband.heartbeat 默认是 false
d、配置多块磁盘
mapreduce.local.dir
e、配置 RPC hander 数目
mapred.job.tracker.handler.count 默认是 10,可以改成 50,根据机器的能力
f、配置 HTTP 线程数目
tasktracker.http.threads 默认是 40,可以改成 100 根据机器的能力
g、选择合适的压缩方式,以 snappy 为例:

mapred.compress.map.output
true


mapred.map.output.compression.codec
org.apache.hadoop.io.compress.SnappyCodec

6(好)、两个文件合并的问题:给定a、b两个文件,各存放50亿个url,每个url各占用64字节,内存限制是4G,如何找出a、b文件共同的url?
1)主要的思想是把文件分开进行计算,在对每个文件进行对比,得出相同的URL,因为以上说是含有相同的URL所以不用考虑数据倾斜的问题。详细的解题思路如下:
a、可以估计每个文件的大小为5G*64=300G,远大于4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。
b、遍历文件a,对每个url求取hash(url)%1000,然后根据所得值将url分别存储到1000个小文件(设为a0,a1,…a999)当中。这样每个小文件的大小约为300M。
b、遍历文件b,采取和a相同的方法将url分别存储到1000个小文件(b0,b1….b999)中。这样处理后,所有可能相同的url都在对应的小文件(a0 vs b0, a1 vs b1….a999 vs b999)当中,不对应的小文件(比如a0 vs b99)不可能有相同的url。然后我们只要求出1000对小文件中相同的url即可。
c、比如对于a0 vs b0,我们可以遍历a0,将其中的url存储到hash_map当中。然后遍历b0,如果url在hash_map中,则说明此url在a和b中同时存在,保存到文件中即可。
d、如果分成的小文件不均匀,导致有些小文件太大(比如大于2G),可以考虑将这些太大的小文件再按类似的方法分成小小文件即可

7、用mapreduce怎么处理数据倾斜问题?
数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,
这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,
从而导致某几个节点迟迟运行不完,此称之为数据倾斜。
解决:自己实现partition类,用key和value相加取hash值。

8、Mapreduce 的 map 数量 和 reduce 数量 怎么确定 ,怎么配置?
map的数量有数据块决定,reduce数量随便配置。

9、hdfs的体系结构
hdfs有namenode、secondraynamenode、datanode组成。
namenode负责管理datanode和记录元数据
secondraynamenode负责合并日志
datanode负责存储数据

10、说下对hadoop 的一些理解,包括哪些组件
详谈hadoop的应用,包括的组件分为三类,分别说明hdfs,yarn,mapreduce。

11、按照需求使用spark编写一下程序?
A、当前文件a.text的格式如下,请统计每个单词出现的个数
A,b,c,d
B,b,f,e
A,a,c,f

sc.textFile(“/user/local/a.text”).flatMap(.split(“,”)).map((,1)).ReduceByKey(+).collect()
或:
package cn.bigdata
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
object Demo {
/*
a,b,c,d
b,b,f,e
a,a,c,f
c,c,a,d
* 计算第四列每个元素出现的个数
*/

  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("demo").setMaster("local")
    val sc: SparkContext = new SparkContext(conf)
    val data: RDD[String] = sc.textFile("f://demo.txt")
    //数据切分
    val fourthData: RDD[(String, Int)] = data.map { x =>
      val arr: Array[String] = x.split(",")
      val fourth: String = arr(3)
      (fourth, 1)
    }
    val result: RDD[(String, Int)] = fourthData.reduceByKey(_ + _);
    println(result.collect().toBuffer)
  }
}

B、HDFS中有两个文件a.text与b.text,文件的格式为(ip,username),如:a.text,b.text
a.text
127.0.0.1 xiaozhang
127.0.0.1 xiaoli
127.0.0.2 wangwu
127.0.0.3 lisi

B.text
127.0.0.4 lixiaolu
127.0.0.5 lisi

每个文件至少有1000万行,请用程序完成以下工作,
1)每个文件的个子的IP
2)出现在b.text而没有出现在a.text的IP
3)每个user出现的次数以及每个user对应的IP的个数

代码如下:


1)各个文件的ip数
package cn.bigdata
import java.util.concurrent.Executors
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.FileSystem
import org.apache.hadoop.fs.LocatedFileStatus
import org.apache.hadoop.fs.Path
import org.apache.hadoop.fs.RemoteIterator
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions 


//各个文件的ip数
object Demo2 {
  val cachedThreadPool = Executors.newCachedThreadPool()
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("demo2").setMaster("local")
    val sc: SparkContext = new SparkContext(conf)
    val hdpConf: Configuration = new Configuration
    val fs: FileSystem = FileSystem.get(hdpConf)
    val listFiles: RemoteIterator[LocatedFileStatus] = fs.listFiles(new Path("f://txt/2/"), true)


    while (listFiles.hasNext) {
      val fileStatus = listFiles.next
      val pathName = fileStatus.getPath.getName
      cachedThreadPool.execute(new Runnable() {
        override def run(): Unit = {
          println("=======================" + pathName)
          analyseData(pathName, sc)
        }
      })
    }
2)出现在b.txt而没有出现在a.txt的ip
package cn.bigdata
import java.util.concurrent.Executors
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
/*
 * 出现在b.txt而没有出现在a.txt的ip
 */
object Demo3 {
  val cachedThreadPool = Executors.newCachedThreadPool()
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("Demo3").setMaster("local")
    val sc = new SparkContext(conf)
    val data_a = sc.textFile("f://txt/2/a.txt")
    val data_b = sc.textFile("f://txt/2/b.txt")
    val splitArr_a = data_a.map(_.split(" "))
    val ip_a: RDD[String] = splitArr_a.map(x => x(0))
    val splitArr_b = data_b.map(_.split(" "))
    val ip_b: RDD[String] = splitArr_b.map(x => x(0))
    val subRdd: RDD[String] = ip_b.subtract(ip_a)
    subRdd.saveAsTextFile("f://txt/4/")
  }
} 

3)

package cn.bigdata
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import scala.collection.mutable.Set
/*
 * 每个user出现的次数以及每个user对应的ip数
 */
object Demo4 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("Demo4").setMaster("local")
    val sc = new SparkContext(conf)
    val data: RDD[String] = sc.textFile("f://txt/5/")
    val lines = data.map(_.split(" "))
    val userIpOne = lines.map(x => {
      val ip = x(0)
      val user = x(1)
      (user, (ip, 1))
    })



 val userListIpCount: RDD[(String, (Set[String], Int))] = userIpOne.combineByKey(
      x => (Set(x._1), x._2),
      (a: (Set[String], Int), b: (String, Int)) => {
        (a._1 + b._1, a._2 + b._2)
      },
      (m: (Set[String], Int), n: (Set[String], Int)) => {
        (m._1 ++ n._1, m._2 + n._2)
      }) 


    val result: RDD[String] = userListIpCount.map(x => {
      x._1 + ":userCount:" + x._2._2 + ",ipCount:" + x._2._1.size
    })


    println(result.collect().toBuffer)
        }
    }

猜你喜欢

转载自blog.csdn.net/Victory_Lei/article/details/81835224