ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

爱奇艺大数据开发秋招笔试题全解析:核心考点与答题策略

爱奇艺大数据开发秋招笔试题全解析:核心考点与答题策略 上个月整理硬盘翻出了一份2019年爱奇艺大数据开发方向秋招笔试题A卷的回忆版是我考完当天凭记忆整理的后来几个朋友也帮忙补过几题。坦率讲这类真题回忆版不完全等同于官方原卷但题型结构、考点覆盖和出题风格基本保留了下来。现在回头看这套题虽然是几年前的但它的考察框架依然非常典型Java并发与集合、Hadoop生态、Spark原理、Kafka消息链路、SQL和算法编程几乎横跨大数据开发岗笔试的所有核心板块。对正在准备秋招的人来说这套题的参考价值不只是题目答案而是能帮你理解出题人到底在筛什么人、用什么样的题来筛。我打算按板块逐题拆解把每道题背后的知识点、容易踩的坑、以及答题时应该写到什么深度都说清楚。如果你正在准备大数据开发岗建议静下心来读完整篇遇到不懂的地方按着方向去补比盲目刷几百道题有用得多。1. 这场笔试的底层逻辑出题人在筛什么样的人1.1 技术栈分布与题型结构爱奇艺做视频业务每天产生海量的用户行为日志、播放记录、推荐特征数据大数据团队的技术栈基本是业内主流的那一套HDFS、MapReduce、YARN、Hive、Spark、Kafka早期实时计算用Spark Streaming后来逐渐向Flink迁移。笔试A卷的题型结构大体如下题型题量占比考察方向建议用时基础选择题约30%Java、JVM、并发、Linux20分钟简答题约20%Hadoop、Spark原理25分钟SQL与编程题约30%算法、SQL窗口函数、手写代码35分钟综合设计题约20%Kafka、实时链路架构设计20分钟可以看出这不是一套纯考背诵的卷子。选择题考的是你有没有认真读过源码和官方文档简答题考的是你能不能把原理讲清楚编程和SQL题则直接检验编码基本功综合题则是为了筛掉那些只写过Demo、没真正理解分布式系统的人。1.2 筛选标准背后的业务场景为什么出题人这么出可以结合爱奇艺的典型业务场景来看。比如视频播放日志一天就有几十亿条这些日志要从业务服务器采集上来经过Kafka削峰再落地到HDFS或者进入实时计算引擎。这个链路里任何一环出问题都会直接影响推荐效果和运营报表。所以笔试中必须考察你对HDFS读写机制、MapReduce数据处理流程、Kafka可靠性、Spark调优这些核心环节的理解。换句话说这套题筛的不是会不会调API而是把你扔进一个真实的分布式集群环境里你能不能判断问题出在哪、能不能设计出合理的方案。后面的所有题目都是围绕这个目的展开的。2. Java并发与集合最容易被低估的送分题2.1 HashMap从链表到红黑树一道题考出你的底层功底笔试中有一道很经典的选择题改了几个选项核心考的是同一个点JDK1.8中HashMap底层用什么结构解决Hash冲突链表长度达到什么条件会转红黑树标准答案都知道底层是数组加链表加红黑树链表长度达到8时会尝试转红黑树。但这里有个关键限制条件链表长度达到8且当前数组长度不小于64才会真正转红黑树。如果数组长度还不到64HashMap会优先选择扩容而不是转树。我当时认识一个同学这道题就栽了他只记住了阈值是8题目里把条件改成只要链表长度达到8就转红黑树他直接选了正确。实际上这是个错误选项因为数组长度不足64时扩容才是首选。顺带说一下为什么是8这个数字。源码注释里有解释基于泊松分布在负载因子0.75、随机哈希函数的前提下链表长度达到8的概率大约是千万分之六。也就是说正常业务数据几乎不可能触发这个长度真到了8基本可以断定有人在恶意构造哈希碰撞。红黑树的存在主要是为了防这种攻击而不是为了优化正常场景。答题时如果能写出链表长度达到8且数组长度不小于64这个完整条件再补充一句这是为了在哈希碰撞极端情况下保证查询复杂度从O(n)降为O(logn)这一题的深度立刻就不一样了。2.2 线程池执行流程从笔试答案到生产配置线程池的考察几乎从不缺席而且出题方式很固定给出corePoolSize、maximumPoolSize、workQueue这几个参数让你描述一个任务提交之后线程池内部到底干了什么。完整的执行流程是下面这样的当前线程数小于corePoolSize时新建核心线程执行任务。线程数达到corePoolSize后新任务被放入工作队列排队。工作队列满了且线程数小于maximumPoolSize创建非核心线程执行任务。队列满了且线程数已经达到maximumPoolSize触发拒绝策略。这里最容易搞混的是第2步和第3步的顺序。很多人以为队列满了才会创建线程这没错但更准确的说法是核心线程满了之后先尝试往队列里塞塞不进去了才创建新线程。这个顺序决定了线程池的先排队、后加人逻辑和很多人的直觉相反。关于拒绝策略常见的四种AbortPolicy直接抛异常、CallerRunsPolicy让提交任务的线程自己跑、DiscardPolicy静默丢弃、DiscardOldestPolicy丢弃队列里最老的任务。笔试如果问生产环境选哪个我一般推荐CallerRunsPolicy它能让生产者感知到压力起到天然的背压效果。生产环境配线程池时参数怎么定CPU密集型任务核心线程数建议设为CPU核数加1因为CPU密集型线程基本不阻塞多了反而频繁切换。IO密集型任务核心线程数可以设为CPU核数的两倍左右因为线程大部分时间在等IO需要更多线程来占满CPU。如果你拿不准可以先用压测工具测再根据耗时和吞吐量调整。2.3 JVM与GC的小题不小选择题里通常还会有一道JVM相关的最常见的是Java 8中哪个区域被移除了。答案是永久代PermGen被元空间Metaspace取代。这道题本身不难但很多人只记住了答案没理解背后的原因。永久代的大小是有限的由-XX:MaxPermSize控制而且它属于JVM堆内存的一部分。字符串常量池和类元数据都放在这里很容易因为类加载过多导致OOM。Java 8把元空间挪到了本地内存默认情况下只受物理内存限制不再那么容易撑爆。如果笔试里出到GC算法相关题记住几个关键结论就够了新生代用复制算法因为朝生夕死的对象多复制成本低老年代用标记清理或标记整理因为对象存活率高复制不划算CMS和G1的区别在于CMS主打低停顿但会产生内存碎片G1则把堆划分成Region可预测停顿时间。回答时能带上为什么就比死记硬背高一个层次。3. Hadoop生态三件套MapReduce、HDFS与YARN的隐藏考点3.1 WordCount不是白写的Shuffle全过程拆解MapReduce的简答题里经典提问方式是介绍WordCount的完整执行流程或者直接问Shuffle过程中Map端和Reduce端各自做了什么。如果只答Map输出后经过Shuffle传给Reduce基本拿不到分。要答得完整需要拆成Map端和Reduce端两条线。Map端的Shuffle流程是这样的map函数输出结果先写入环形缓冲区默认大小100MB达到80%阈值时触发溢写。溢写过程中会做分区、排序如果设置了Combiner还会在溢写前做一次本地聚合减少写入磁盘的数据量。溢写会产生多个小文件最后会合并成一个大的溢出文件同时做一次归并排序。Reduce端的流程是先从Map端拉取属于自己分区的数据拉取方式有HTTP请求拉到本地后做合并和归并排序然后按照Key分组把同一Key的所有Value交给reduce函数处理。很多同学容易漏掉几个细节环形缓冲区默认100MB、溢写阈值80%、Map端有Combiner可选、Reduce端拉取数据是走HTTP。这些细节才是考官判断你是否真正写过MapReduce作业、是否读过源码的依据。顺带说一下MapReduce为什么慢整个Shuffle过程中数据要多次落盘、多次序列化和反序列化还要进行排序。磁盘IO和网络传输是最大瓶颈。所以后来Spark才提出基于内存的计算这个卖点把中间结果尽量留在内存里。3.2 HDFS读写链路与副本放置策略HDFS的题目通常是这样的描述HDFS读文件的过程或者问副本放置策略是什么。读流程回答要点是客户端调用FileSystem.open方法向NameNode发起RPC请求获取文件的数据块信息。NameNode返回每个块对应的DataNode地址列表客户端根据网络拓扑距离选择最近的DataNode读取数据边读边校验防止读到损坏的块。写流程稍微复杂一点。客户端向NameNode发起创建文件请求NameNode检查权限和路径后创建文件元数据。客户端开始写第一个块先写入本地临时文件然后从NameNode获取一个DataNode列表构建pipeline。数据按客户端-第一个DataNode-第二个DataNode-第三个DataNode的管道方式依次传递每个DataNode写完会向上游返回ack最后一个DataNode写完会通知客户端。副本放置策略也是高频考点第一个副本放在客户端所在节点第二个副本放在同机架的不同节点第三个副本放在不同机架。这样兼顾了写入性能第一个副本本地写、容错性跨机架和读取性能同机架内有两个副本。答题时如果能补充一句NameNode只存元数据、不存实际数据所有数据读写都走DataNode会让考官觉得你对架构有整体认知。3.3 YARN资源调度题怎么答才不丢分YARN的考察通常和作业提交流程绑定比如一个MapReduce作业提交到YARN后完整执行流程是什么标准的回答链路是客户端向ResourceManager提交作业。RM为作业分配一个容器Container并在该容器中启动ApplicationMaster。AM启动后向RM注册自己并向RM申请运行Map和Reduce任务的资源。RM返回可用节点列表AM与对应的NodeManager协商在Container中启动Task。所有任务执行完成后AM向RM注销并释放资源。这里有个容易忽略的点ApplicationMaster是作业级别的MapReduce、Spark on YARN都是先启动AM再由AM去申请资源。AM本身就是一个Container它负责这个作业的生命周期管理。如果题目进一步问调度器区别答三点FIFO先来先服务简单但容易队头阻塞Capacity Scheduler按队列分配资源适合多租户Fair Scheduler按公平策略动态分配资源适合资源利用率要求高的场景。爱奇艺这种大集群一般用Capacity Scheduler因为它能保证不同业务线之间的资源隔离。4. Spark核心选择题考概念大题考调优4.1 宽窄依赖判断题别把union记成宽依赖Spark选择题里必有一道宽窄依赖判断常见选项包括map、filter、groupByKey、union。宽依赖和窄依赖的划分标准是子RDD的每个分区依赖父RDD的哪些分区。如果只依赖父RDD的固定一个分区就是窄依赖比如map、filter、flatMap、union如果依赖父RDD的多个分区就是宽依赖比如groupByKey、reduceByKey、join。最容易错的是union。union只是把多个RDD拼接在一起子RDD的每个分区仍然只依赖父RDD中对应的一个分区所以它是窄依赖不是宽依赖。很多人看到union觉得是多个合并成一个想当然就选了宽依赖这是典型的凭感觉答题。为什么Spark要区分宽窄依赖两个原因。第一个是Stage划分宽依赖是划分Stage的边界遇到宽依赖就必须Shuffle所以要把Stage切在这里。第二个是故障恢复窄依赖的某个分区丢失只需要重新计算对应的父分区宽依赖的某个分区丢失可能要重新计算父RDD的多个分区恢复成本高得多。4.2 Spark作业提交到执行的完整链路Spark作业执行流程是简答题里的常客。答题时按下面的链路展开基本不会漏点通过spark-submit提交应用启动Driver进程。Driver中构建SparkContextSparkContext向ClusterManager申请资源。在YARN模式下会先在集群中启动ApplicationMaster。AM向ResourceManager申请Container用来启动Executor进程。Executor启动后反向注册到SparkContext。SparkContext根据业务代码构建RDD依赖关系生成DAG。DAGScheduler按照宽依赖把DAG切分成多个Stage每个Stage包含一组可以并行执行的Task。TaskScheduler把Task下发到Executor上执行。Executor执行Task结果返回给Driver或者直接写入外部存储系统。这里有两个容易漏的点一是DAGScheduler切分Stage的依据是宽依赖二是Executor是在Driver注册之后才执行具体任务的。如果你能补充一句Stage内部可以pipeline执行多个窄依赖算子可以在一个Task里连续计算会显得你对执行模型有更深的理解。另外还常问cache和checkpoint的区别。一句话总结cache只是把数据留在内存或磁盘不切断血缘checkpoint会切断血缘把数据写到可靠存储如HDFS。所以用checkpoint时要注意它会把RDD的血缘彻底断掉后面如果缓存被清了只能从checkpoint目录重新加载。4.3 数据倾斜各大厂大数据笔试的常青树数据倾斜几乎是大数据开发笔试简答题里出现频率最高的问题没有之一。爱奇艺这道题的问法是Spark作业中遇到数据倾斜你会怎么排查和解决。答题时先讲排查手段在Spark UI里看各个Task的耗时和读写数据量正常情况下Task之间应该比较均衡如果某个Task处理的数据量远超其他Task基本可以确定是数据倾斜。然后是定位原因最常见的三种一是Key本身分布不均匀比如某个热点Key的数据量特别大二是分组聚合类操作groupByKey或reduceByKey时大量数据落到同一个Key上三是Join操作中有一张表的Key大量重复。解决方案按场景给如果倾斜Key可以过滤直接把异常Key过滤掉再计算。如果是大表Join小表用Broadcast Join把小表广播到每个Executor避免Shuffle。如果是聚合类倾斜用两阶段聚合。先给每个Key加一个随机前缀让它拆分成多个子Key先做一次局部聚合再去掉前缀做第二次全局聚合。相当于把压力分散到多个Task。提高Shuffle并行度调整spark.sql.shuffle.partitions或spark.default.parallelism让每个Task处理的数据量变小。这个方法最简单但不一定能根治问题。答题时最好把两阶段聚合的逻辑说清楚因为这是最能体现实战经验的点。考官一听你是真的处理过倾斜不是只会背方案分数自然不一样。5. 消息队列与实时链路区分会用和懂原理5.1 Kafka可靠性三件套acks、重试与最小副本Kafka的题目通常围绕消息可靠性展开常见的问法是如何保证Kafka消息不丢失、不重复要答好这道题需要从生产端、消费端、Broker端三个层面分别说明。生产端保证不丢设置acksall表示所有ISR副本都写入成功才返回成功设置retries大于0并在网络抖动时允许重试开启幂等性enable.idempotencetrue防止重试导致消息重复写入。Broker端保证不丢设置min.insync.replicas2表示至少两个副本同步成功才认为写入成功关闭unclean.leader.election.enable避免非同步副本被选为Leader导致数据丢失。消费端保证不丢核心是关闭自动提交enable.auto.commitfalse改成手动提交offset并且一定要在业务逻辑处理完成之后再提交。如果先提交offset再处理业务消费者挂了就会丢数据。至于不重复消费坦白说Kafka的语义是at least once也就是至少一次生产端重试和消费端重平衡都可能导致同一批消息被消费多次。所以真正的解法是在业务侧做幂等比如写入数据库时用唯一索引去重或者用Redis记录已处理的消息ID。这部分答出来说明你理解消息系统的边界而不是幻想一个配置就能同时解决不丢和不重。5.2 实时推荐链路设计题的答题套路综合题常给一个场景比如设计一个实时统计视频播放量的系统要求每天处理几十亿条日志延迟在分钟级你会怎么设计架构。这种题没有标准答案但答题框架是固定的按数据流向逐层说就行。第一层是日志采集视频播放日志通过Nginx或业务服务打印由Flume或Logstash采集。注意采集端要有缓冲机制防止业务高峰把采集进程打爆。第二层是消息队列日志进入Kafka主题按业务线划分比如播放主题、点击主题。Kafka在这里的核心作用是削峰填谷和解耦下游计算引擎挂掉时Kafka可以帮忙把数据暂存起来不会丢。第三层是实时计算用Spark Streaming或Flink消费Kafka数据按分钟窗口聚合播放量、完播率等指标。如果用Flink要开启Checkpoint保证故障恢复时不丢数据。第四层是存储和展示聚合结果写入Redis供实时查询或者写入ES供多维分析再通过报表平台展示。答题时如果能结合选型理由会更好比如为什么用Flink不用Spark Streaming因为Flink是真正的流式计算延迟更低且支持精确一次语义。这种每选一个组件都能说出为什么的能力才是综合设计题真正考察的东西。6. 编程与SQL题送分题和压轴题并存6.1 单例模式双重检查锁为什么必须加volatile手写代码题里常有一道实现单例模式而且要求线程安全、懒加载。最经典的写法是双重检查锁代码如下public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance null) { synchronized (Singleton.class) { if (instance null) { instance new Singleton(); } } } return instance; } }这道题的关键不是能不能写出来而是能不能解释清楚volatile的作用。new Singleton()这行代码在JVM层面不是原子操作它分三步在堆上分配内存、执行构造函数初始化对象、把引用指向这块内存。在没有volatile的情况下第三步可能先于第二步执行也就是引用指向了一个还没有初始化完成的内存区域。此时另一个线程进来判断instance不为null直接返回拿到的是一个半初始化的对象再用就会出问题。volatile的作用是禁止这两行指令重排序保证引用赋值一定发生在对象初始化完成之后。外层判空是为了避免不必要的加锁开销内层判空是为了防止多个线程同时进入同步块时重复创建实例。把这几点写在答案旁边这一题满分。当然也可以用静态内部类实现逻辑更简单利用类加载机制保证线程安全但笔试时DCL是更主流的考点建议还是先把这个写法吃透。6.2 Top K问题堆与快速选择的取舍另一道经典算法题是从10亿个整数中找出最大的100个。这题一眼看上去数据量大其实关键就在100这个K值很小。最优解是维护一个大小为100的最小堆遍历整个数组如果堆没满就直接放入如果当前元素比堆顶大就弹出堆顶再放入当前元素。遍历结束后堆里就是最大的100个数。时间复杂度是O(nlogK)这里K是100所以logK是常数级别相当于O(n)。空间复杂度是O(K)非常小。PriorityQueueInteger heap new PriorityQueue(100); for (int num : nums) { if (heap.size() 100) { heap.offer(num); } else if (num heap.peek()) { heap.poll(); heap.offer(num); } }顺便提一下另一种解法快速选择算法平均时间复杂度O(n)但它有一个问题会修改原数组顺序而且如果要输出有序的Top K还要再排一次序。更重要的是如果数据是流式不断进来的快速选择就没法用了而堆天然支持增量计算。所以在大数据场景下堆是更实用的方案。答题时能说出10亿个数不需要全部加载到内存一次只处理一个数空间只需要维护K个元素这道题就算答到位了。如果面试官追问进程内存不够怎么办可以补充外部排序或MapReduce的分布式思路。6.3 连续登录SQL窗口函数的标准解法SQL题里频率最高的一类是连续性问题比如给定用户登录表user_login(user_id, login_date)找出连续登录3天及以上的用户。标准解法是先用窗口函数给每个用户按登录日期编号再用登录日期减去编号得到一个新的日期字段。同一用户连续登录时这个新字段是相同的。SELECT user_id, grp_date, COUNT(*) AS cnt FROM ( SELECT user_id, login_date, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS grp_date FROM user_login ) t GROUP BY user_id, grp_date HAVING COUNT(*) 3;核心逻辑是如果用户连续登录比如3月1日、3月2日、3月3日分别对应row_number的1、2、3日期减去编号得到2月28日、2月28日、2月28日完全一样。一旦中间断了这个差值就会变化从而被分到不同的组。写这道题有几个坑需要注意login_date要去重因为同一天可能有多条登录记录窗口函数会重复计数导致连续天数被算多。处理方式是对(user_id, login_date)先distinct或者用dense_rank代替row_number但最稳妥的还是先做去重。另外DATE_SUB函数在不同数据库里写法可能不同MySQL里是DATE_SUBHive里可以直接用date_sub笔试时注意看题目指定的环境。7. 丢分点复盘与笔试实战建议7.1 这几个坑我当年亲眼见过别人踩整理这套题的时候我把自己和身边人考完后的复盘汇总了一下列出出现频率最高的丢分点大家可以对照检查考点常见错误正确理解HashMap转红黑树只记得长度达到8需要长度达到8且数组长度不小于64线程池执行顺序以为队列满才创建核心线程核心线程满后先入队队满再创建非核心线程宽窄依赖把union当成宽依赖union的每个分区只依赖父RDD对应分区属于窄依赖MapReduce Shuffle漏掉溢写和排序步骤Map端有环形缓冲区溢写Reduce端有拉取和归并排序Kafka可靠性只会说设置acksall需要分生产端、Broker端、消费端三层说明连续登录SQL忘记去重导致连续天数虚高先对登录日期去重再做窗口计算另外还有一个非技术层面的坑简答题只写关键词不写过程。比如问Shuffle流程有人只写排序、合并、拉取几个词甚至不分Map端和Reduce端。笔试是按点给分的你不展开写考官就算想给分也找不到依据。7.2 时间分配与答题顺序时间分配是很多人忽略的隐形丢分点。这套题总分100分SQL和编程题占了30分以上但它也是最耗时的部分。我的建议是拿到卷子先花两分钟通读一遍然后按SQL编程题优先、简答题其次、选择题最后的顺序来做。为什么先做SQL和编程因为这类题分值大、区分度高而且思路一旦断了很难再捡起来放在后面容易因为时间不够而被迫放弃。选择题反而不是那么着急很多基础选项一眼就能判断拿不准的先跳过做完大题再回来推敲往往能靠排除法选出正确答案。简答题答题时也要控制篇幅。每道简答题写5到8行即可把核心步骤列清楚用第一步、第二步的方式组织比写一大段流水账强得多。阅卷的人最怕看到满篇文字但要自己从中找得分点。我自己当年考试有一个习惯遇到不会的大题先把脑子里能想到的关键词和公式写上去再逐步组织语言。因为笔试阅卷是抓要点给分写了不一定得分但不写一定是零分。这个习惯帮我救回过不少题。最后聊几句整理这篇拆解的时候我自己也重新过了一遍当年的知识点。说实话这类笔试真正考的不是你背了多少八股而是你能否把一个知识点放到真实场景里讲清楚。HashMap为什么转红黑树、数据倾斜怎么解决、Kafka怎么保证可靠性这些问题背后全是真实业务里会遇到的麻烦事。如果你正在准备大数据开发的秋招我的建议是别只刷题而是把每一个考点往底层原理和业务场景追问一层。看到HashMap就想想并发场景下它为什么会丢数据看到Shuffle就想想数据倾斜时它会放大什么问题看到Kafka就想想如果你的下游挂了它到底靠什么兜底。把知识点串成一条线笔试和面试都会顺手很多。这套题里还有几个方向没有完全展开比如Linux常用命令、HiveQL优化如果大家需要我可以再单独写一篇。祝各位秋招顺利。
返回列表