面试难题总结

基础部分

常见shell命令

常见HDFS命令

序号命令命令解释
1hdfs dfs -cat |wc -l查看下HDFS文件的行数
2hdfs dfs -ls /查看当前目录信息
3hdfs dfs -put /本地路径 /hdfs路径上传文件
4hdfs dfs -get /hdfs路径 /本地路径下载文件到本地
5hdfs dfs -mkdir /hello创建文件夹
6hdfs dfs -rm /aa.txt删除hdfs文件
7hdfs dfs -df /查看hdfs的总空间

HDFS小文件优化方法

  1. 采用har归档
  2. 采用CombineTextInputFormat
  3. JVM重用

Yarn的提交过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CHdtmFef-1625979998807)(https://static01.imgkr.com/temp/34c29d7e425c4670b93b892ba2df591a.png)]

数仓部分

Sql的执行流程:

① From

② Join on

③ Where

④ Group by

⑤ Avg sum

⑥ Having

⑦ Select

⑧ Distinct

⑨ Order by

数仓分层

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6u1biWiR-1625979998810)(https://static01.imgkr.com/temp/3b1021725d2a4763ab5859b789032776.png)]

数层分层的好处

  1. 把复杂的问题简单化
  2. 减少重复开发
  3. 隔离原始数据

建模思想

  1. 应该简历那些表(维度和事实的划分)
  2. 应该有那些字段
  3. 那些表之间应该有关系

关系建模和维度建模

维度建模:

  1. 维度建模简单,join少,表结构简单,查询性好
  2. 维度模型面向业务好理解
  3. 维度模型更适合多维度分析

维度表和事实表的区别

维度表:(描述信息)

  • 内容固定
  • 数据量少
  • 字段多

事实表:(维度外键和度量值)

  • 内容每天都有大量的新增或改动数据

  • 数据量大

  • 字段少

    注:一个业务时间对应一个事实表,主要构成由:维度外键,度量值

Hive表字段类型

  • 数量类型为bigint
  • 金额类型为decimal(16,2)16位有效数字,其中小数部分为2位
  • 字符串(名字,描述,信息等)类型位String
  • 主键类型位String
  • 时间戳类型位bigint

拉链表的制作

  1. 将初始化的用户表全量导入并增加,开始时间(数仓搭建时间),结束时间(9999-99-99)

  2. 将新增及变化数据拿到加上开始时间和结束时间,合并到原边内

  3. 合并完成后将历史数据的结束日期改为昨天时间

    注:用户拉链表的分区时以数据结束时间

常见的指标需求

PV

UV

日活

月活

新增访问

取TOP10热门品类

连续三周的活跃用户

七天连续三天

Hive小文件产生的原因和解决办法

原因:

动态分区插入数据,产生大量的小文件,导致map数量巨增

reduce数量越多小文件越多

解决方法:

  1. 在map执行前合并小文件,减少map数 CombineHiveInputFormat

  2. merge->输出合并小文件

​ ->SET hive.merge.mapfiles=true 在map 任务结束时合并小文件

​ ->SET hive.merge.size.per.task=268435456 默认256m

​ ->SET hive.merge.mapredfiles=true;默认false,在map-reduce任务结束时合并小文件

  1. 开启JVM重用

Hive的优化措施

  • 表的优化
    • 小表join大表
    • GroupBy
    • Count(Distinct)去重统计
    • 行类过滤
  • 数据倾斜
    • 合理的MapTask数量
    • 小文件合并
    • 合理的ReduceTask数量
    • 开启并行执行
    • 开启严格模式
    • 推测执行
    • 开启map端和reduce端压缩
    • jvm重用

说一下hive中SortBy,OrderBy,DistrbuteBy,ClusterBy是什么意思

sortBy:不是全局排序,其在数据进入reducer前完成排序

orderBy:会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有效)。只有一个reducer,会导致当输入规模较大时,需要较长的计算时间

distributeBy:按照指定的字段对数据进行划分输出到不同的reduce中

clusterBy:除了具有distributeBy的功能外还兼具sortBy的功能

hive自定义UDF函数的流程(写过 事件处理函数对日期进行处理)

  1. 写一个类继承方法 (org.apache.hadoop.hive.ql.)UDF类
  2. 覆盖方法evaluate();
  3. 打JAR包
  4. 通过hive命令JAR添加到Hive的类路径
  5. 注册函数 hive>create temporary function xxx as ‘xxx’;
  6. 使用函数
  7. [可选] drop临时函数

HiveSQL优化措施

Spark部分

Spark为什么比Mapreduce快

  1. 基于内存计算,减少低效的磁盘交互
  2. 高效的调度算法,基于DAG
  3. 容错机制Lingage,主要DAG和Lianage,即使Spark不使用内存技术,也大大快于Mapreduce

Spark运行详细流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQJyKO63-1625979998813)(https://static01.imgkr.com/temp/d60ddb0ec21f4d528deaafc980013db9.png)]

Spark常用算子

转换算子

map mappatiation flatMap glom groupBy filter distinct sort by union

行动算子

reduce collect count first take fold countByKey foreach

wordcount程序

import scala.io.Source

object testWC {
  def main(args: Array[String]): Unit = {
    // 读取D:\Demo\hadoop\input\word.txt
    val so_1 = Source.fromFile("D:\\Demo\\hadoop\\input\\word.txt").mkString
    val so_2 = Source.fromFile("D:\\Demo\\hadoop\\input\\wor.txt").mkString
    // 放入list集合
    val list = List(so_1,so_2)
    val word: List[String] = list.flatMap(x => x.split("\n")).flatMap(x => x.split("\\s"))
    //
    val tuples: List[(String, Int)] = word.map((_,1))
    // 对key进行分组
    val map = tuples.groupBy(_._1) // x=>x._1
    // Map(String,List(
    // 开始统计分组后相同单词的个数,统计list集合的长度
    // val res: Map[String, Int] = map.map(x=>(x._1,x._2.size))
    // 第二种
    val res: Map[String, Int] = map.mapValues(_.size)
    // println(res)
    // map.mapValues(x=>x.size)
    // 排序
    val reverse = res.toList.sortBy(_._2).reverse
    // 打印
    reverse.foreach(println)
  }
}
//例子2
val lines=List("hello tom hello jerry","hello tom hello kitty hello china")
    //方法一:
    val wc=lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).map(t=>(t._1,t._2.size)).toList.sortBy(_._2).reverse
    //方法二:
    val wc2=lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.size)
    //方法三:
    val wc3=lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.foldLeft(0)(_+_._2))
    //如果是在spark上:
//    val wc4=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).sortBy(_._2,false).collect


spark三大数据结构

① RDD : 弹性分布式数据集

② 累加器:分布式共享只写变量

③ 广播变量:分布式共享只读变量

累加器和广播变量

累加器

累加器用来把Executor端变量信息聚合到Driver端。在Driver程序中定义的变量,在Executor端的每个Task都会得到这个变量的一份新的副本,每个task更新这些副本的值后,传回Driver端进行merge

广播变量

广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个Spark操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,广播变量用起来都很顺手。在多个并行操作中使用同一个变量,但是 Spark会为每个任务分别发送。

Spark阶段的划分

① 从hdfs读取文件后,创建RDD对象

② DAGScheduler模块介入运算,计算RDD之间的依赖关系

RDD之间的依赖关系就形成了DAG

③ 每个Job被划分为多个Stage,划分Stage的一个主要依据是当前计算因子的输入是否确定的,如果是则将其划分在同一个Stage,避免多个Stage之间的消息传递开销

Spark如何防止内存溢出

导致原因:

  • Map执行中内存溢出
  • Shuffle后的内存溢出

主要包含操作有

Map执行中内存溢出代表了所有map类型的操作包括:flatMap,filter,mapPatitions等。

Shuffle后内存溢出的shuffle操作包括:join,reduceByKey,repartition等操作。

解决方法:

  • Driver端的内存溢出

    • 可以增大Driver端的内存参数:spark。driver.memory(default 1g)
    • 这个参数用来设置Driver的内存。在Spark程序中, SparkContext,DAGScheduler都是运行在Driver端的。对 应rdd的Stage切分也是在Driver端运行,如果用户自己写的 程序有过多的步骤,切分出过多的Stage,这部分信息消耗 的是Driver的内存,这个时候就需要调大Driver的内存
  • Map端过程产生大量文件对象导致内存溢出

    • 这种溢出的原因是在单个map中产生了大量的对象导致的, 例如:rdd.map(x=>for(i <- 1 to 10000) yield i.toString), 这个操作在rdd中,每个对象都产生了10000个对象,这肯 定很容易产生内存溢出的问题。针对这种问题,在不增加内 存的情况下,可以通过减少每个Task的大小,以便达到每个 Task即使产生大量的对象Executor的内存也能够装得下。具 体做法可以在会产生大量对象的map操作之前调用 repartition方法,分区成更小的块传入map。例如:rdd.repartition(10000).map(x=>for(i <- 1 to 10000) yield i.toString)。 面对这种问题注意,不能使用rdd.coalesce方 法,这个方法只能减少分区,不能增加分区,不会有shuffle 的过程
  • 数据不平衡数据溢出

    • 数据不平衡除了有可能导致内存溢出外,也有可能导致性能 的问题,解决方法和上面说的类似,就是调用repartition重 新分区。这里就不再累赘了
  • 使用rdd.persist(StorageLevel.MEMORY_AND_DISK_SER)代替 rdd.cache()

  • rdd.cache()和rdd.persist(Storage.MEMORY_ONLY)是等价 的,在内存不足的时候rdd.cache()的数据会丢失,再次使用 的时候会重算,而 rdd.persist(StorageLevel.MEMORY_AND_DISK_SER)在内 存不足的时候会存储在磁盘,避免重算,只是消耗点IO时 间

rdd的算子cache和persist的区别

  • cache:缓存数据,默认是缓存在内存中,其本质还是调用 persist
  • persist:缓存数据,有丰富的数据缓存策略。数据可以保存在内 存也可以保存在磁盘中,使用的时候指定对应的缓存级别就可 以了

rdd的算子repartition和coalesce联系与区别

(1)联系: 两者都是用来改变RDD的partition数量的,repartition底 层调用的就是coalesce方法: coalesce(numPartitions, shuffle = true)

(2)区别: repartition一定会发生shuffle,coalesce根据传入的参数 来判断是否发生shuffle 一般情况下增大rdd的partition数量使用repartition,减少 partition数量时使用coalesce

rdd常用算子reduceByKey与groupByKey的区 别

**reduceByKey:**按照key进行聚合,在shuffle之前有combine(预 聚合)操作,返回结果是RDD[k,v]。

groupByKey: 按照key进行分组,直接进行shuffle。对数据进行 全量拉取,不会进行数据的预聚合

开发指导:reduceByKey比groupByKey,建议使用。但是需要注意 是否会影响业务逻辑。

Spark的任务划分

①Application:初始化一个SparkContext即生成一个Application

②Job:一个Action算子就会生成一个Job

③Stage:Stage等于宽依赖的个数加1

④Task:一个Stage阶段中,最后一个RDD的分区个数就是Task的个数

请列举会引起Shuffle过程的Spark算子

reduceBykey:

groupByKey:

…ByKey:

Spark的shuffle过程

(1)shuffle过程的划分

(2)shuffle的中间结果如何存储

:reduceByKey比groupByKey,建议使用。但是需要注意 是否会影响业务逻辑。

Spark的任务划分

①Application:初始化一个SparkContext即生成一个Application

②Job:一个Action算子就会生成一个Job

③Stage:Stage等于宽依赖的个数加1

④Task:一个Stage阶段中,最后一个RDD的分区个数就是Task的个数

请列举会引起Shuffle过程的Spark算子

reduceBykey:

groupByKey:

…ByKey:

Spark的shuffle过程

(1)shuffle过程的划分

(2)shuffle的中间结果如何存储

(3)shuffle的数据如何拉取过来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值