最新字节一面面经及答案【大厂面经系列】
推荐阅读文章列表
面经及答案
1.有没有做过一些SQL优化,用过布隆过滤器吗 *
我们要明白为什么要做SQL优化?
当然时因为任务跑的慢,那么哪些算子跑的慢呢?
最常见的包括 join、group by、count(distinct)、row_number等等
接下来就一一讲一下针对每一种算子有哪些优化的方法论(这里主要说一下count distinct)
第一种最常见的方法就是两阶段聚合,即使用两层group by(这时候选取key非常重要,可能会因为选取的key倾斜导致代码执行并没有变快)
第二种就是布隆过滤器(bitmap的扩展),详细描述见此文 BitMap在数仓领域的应用
2.谈谈你对数据仓库的理解 *
- 定义:数据仓库是一个面向主题的(司机、乘客、订单)、集成的(来自不同数据源的统一数据规范比如男女的取值,命名规范的统一,字段类型的统一)、非易失(一般不会进行删除和修改操作)且随时间变化(并不是数据会变,而是数据随着时间会不断增多)的数据集合
- 作用:主要用于存储历史数据,然后通过分析整理进而提供数据支持和辅助决策。
3.为什么要对数仓进行分层
- 第一个是将复杂的需求简单化;我们通过将复杂的问题分解为多个步骤来完成,每一层只处理单一的步骤,比较容易和理解
- 第二个是提高数据的复用性;比如在已经得到最终结果之后,又需要中间层的一些数据,我可以直接查询中间层的数据,不必重新进行计算
4.group by和窗口函数的区别
- 窗口函数保留原始数据,会将分组聚合后的结果拼接在原始数据上,最终返回的行数与原始据行数相等。而group by只能得到分组聚合后的数据,最终返回的行数和分组数目相等。
- 窗口函数能够限制对每一组的部分数据进行处理(指定开窗范围),而group by只能对每一组的所有数据进行处理。
5.你知道spark的作业执行流程吗 *
- 当一个 Spark 应用被提交时,首先需要为这个应用构建基本的运行环境,即由Driver创建一个SparkContext对象,SparkContext 会向资源管理器注册并申请运行Executor的资源,SparkContext可以看成是应用程序连接集群的通道。
- 资源管理器为Executor分配资源,并启动Executor进程,Executor运行情况将随着心跳发送到资源管理器上。
- SparkContext根据RDD的依赖关系构建DAG图,并将DAG图提交给 DAG 调度器(DAGScheduler)进行解析,将 DAG 图分解成多个阶段(每个阶段都是一个任务集),并且计算出各个阶段之间的依赖关系,然后把一个个任务集提交到底层的任务调度器(TaskScheduler)进行处理;Executor 向 SparkContext 申请任务,任务调度器将任务分发给 Executor 运行,同时,SparkContext 将应用程序代码发放给 Executor。
- 任务在 Executor 上运行,把执行结果反馈给任务调度器,然后反馈给 DAG 调度器,运行完毕后写入数据并释放所有资源。
6.Spark的内存区域是怎么划分的
- Spark分为堆内内存和堆外内存,堆内内存由JVM统一管理,而堆外内存直接向操作系统进行内存的申请,不受JVM控制
- 堆内内存又分为存储内存、执行内存**(前两种统称为统一内存)、其他内存(前三种统称为可用内存)**和预留内存,存储内存主要存放广播变量和缓存变量,执行内存主要存放shuffle过程的数据,其他内存主要存放RDD的元数据信息,预留内存和其他内存作用相同;预留内存一般为300M,统一内存占比60%,其中存储内存和执行内存的占比时动态变化的
- 堆外内存:减少了垃圾回收的工作,因为垃圾会收会暂停其他的工作
7.听说过双亲委派模型吗
如果一个类加载器收到了类加载的请求,它首先不会尝试加载整个类,而是把这个请求委派给上一层类加载器去完成,每一层的类加载器都是如此,因此最终会传送到最顶层的启动类加载器上。它会尝试加载这个类,只有当它无法完成这个加载请求时,下一层的类加载器才会去尝试加载,如果所有的类加载器都无法加载,就会抛出ClassNotFoundException
8.JVM的垃圾回收算法有哪些 *
- 标记-清除算法:分为标记和清除两个阶段,标记是标记出所有需要回收的对象(也可以反过来,标记出所有存活的对象),标记的时候是基于可达性分析算法实现的;清除就是标记后对所有未被标记的对象进行回收
- 标记-复制算法:复制就是将可用内存按容量分为大小相等的两块,每次只使用其中一块,当这一块的内存用完了,就将还存活的对象复制到另一块内存上,然后再把已使用过的内存空间一次清理掉
- 标记-整理算法:整理就是根据存活对象进行整理,让存活对象都向一端移动,然后直接清除边界以外的内存
9.介绍一下JVM的内存结构
- 程序计数器:记录当前线程执行的字节码指令的地址
- 虚拟机栈:在执行方法的时候,JVM会同步创建一个栈帧,用于存储局部变量表、操作数栈、方法出口等信息,如果方法执行完毕,就会将该栈帧从虚拟机栈中出栈
- 本地方法栈:和虚拟栈原理基本一样,区别是为native方法服务的
- 堆:用来存放创建的对象
- 元空间:用来存储被加载的类信息、常量、静态变量以及常量池等数据
10.Spark3.0新特性AQE有了解过吗 *
- AQE又叫自适应查询执行(Adaptive Query Execution),解决了最初生成的查询计划不是最优的问题,在Spark查询过程中不断收集统计数据,然后通过算法模型来优化执行计划。
- AQE主要由三个核心功能:动态合并Shuffle分区、动态切换Join策略、动态优化数据倾斜