基础部分
常见shell命令
常见HDFS命令
序号 | 命令 | 命令解释 |
---|---|---|
1 | hdfs dfs -cat |wc -l | 查看下HDFS文件的行数 |
2 | hdfs dfs -ls / | 查看当前目录信息 |
3 | hdfs dfs -put /本地路径 /hdfs路径 | 上传文件 |
4 | hdfs dfs -get /hdfs路径 /本地路径 | 下载文件到本地 |
5 | hdfs dfs -mkdir /hello | 创建文件夹 |
6 | hdfs dfs -rm /aa.txt | 删除hdfs文件 |
7 | hdfs dfs -df / | 查看hdfs的总空间 |
HDFS小文件优化方法
- 采用har归档
- 采用CombineTextInputFormat
- 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)]
数层分层的好处
- 把复杂的问题简单化
- 减少重复开发
- 隔离原始数据
建模思想
- 应该简历那些表(维度和事实的划分)
- 应该有那些字段
- 那些表之间应该有关系
关系建模和维度建模
维度建模:
- 维度建模简单,join少,表结构简单,查询性好
- 维度模型面向业务好理解
- 维度模型更适合多维度分析
维度表和事实表的区别
维度表:(描述信息)
- 内容固定
- 数据量少
- 字段多
事实表:(维度外键和度量值)
-
内容每天都有大量的新增或改动数据
-
数据量大
-
字段少
注:一个业务时间对应一个事实表,主要构成由:维度外键,度量值
Hive表字段类型
- 数量类型为bigint
- 金额类型为decimal(16,2)16位有效数字,其中小数部分为2位
- 字符串(名字,描述,信息等)类型位String
- 主键类型位String
- 时间戳类型位bigint
拉链表的制作
-
将初始化的用户表全量导入并增加,开始时间(数仓搭建时间),结束时间(9999-99-99)
-
将新增及变化数据拿到加上开始时间和结束时间,合并到原边内
-
合并完成后将历史数据的结束日期改为昨天时间
注:用户拉链表的分区时以数据结束时间
常见的指标需求
PV
UV
日活
月活
新增访问
取TOP10热门品类
连续三周的活跃用户
七天连续三天
Hive小文件产生的原因和解决办法
原因:
动态分区插入数据,产生大量的小文件,导致map数量巨增
reduce数量越多小文件越多
解决方法:
-
在map执行前合并小文件,减少map数 CombineHiveInputFormat
-
merge->输出合并小文件
->SET hive.merge.mapfiles=true 在map 任务结束时合并小文件
->SET hive.merge.size.per.task=268435456 默认256m
->SET hive.merge.mapredfiles=true;默认false,在map-reduce任务结束时合并小文件
- 开启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函数的流程(写过 事件处理函数对日期进行处理)
- 写一个类继承方法 (org.apache.hadoop.hive.ql.)UDF类
- 覆盖方法evaluate();
- 打JAR包
- 通过hive命令JAR添加到Hive的类路径
- 注册函数 hive>create temporary function xxx as ‘xxx’;
- 使用函数
- [可选] drop临时函数
HiveSQL优化措施
Spark部分
Spark为什么比Mapreduce快
- 基于内存计算,减少低效的磁盘交互
- 高效的调度算法,基于DAG
- 容错机制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的数据如何拉取过来