ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

猿辅导大数据开发岗面试全流程复盘:Hadoop/Spark/Flink核心考点与实战经验

猿辅导大数据开发岗面试全流程复盘:Hadoop/Spark/Flink核心考点与实战经验 1. 先说结论猿辅导大数据岗到底在考什么我是在去年秋招投的猿辅导大数据开发岗base北京走完1面和2面之后整体感受是这个岗位的面试风格在互联网公司里属于相当务实的类型既没有单纯背概念的八股文也没有上来就甩你一道Hard算法的压迫感而是把重点放在“你真正做过什么”“你能不能说清楚数据链路里的每一个环节”这两件事上。简单介绍一下自己的背景我本硕都是计算机相关专业研究生期间主要做的是离线数仓和实时计算相关的项目用过Hadoop、Spark、Flink、Kafka、Hive这些组件会写Java和Scala也写过一些SQL调优的东西。所以下面复盘的内容会带上一些个人的技术倾向但核心的面试题和考察思路是通用的。如果你也在准备大数据方向的校招我建议你带着三个问题读这篇文章第一猿辅导的大数据面试和别的公司有什么不同第二一面和二面分别侧重什么第三有哪些细节是你在刷题和背八股时容易忽略、但面试官一定会问的。我尽量把每个问题背后面试官的考察意图讲清楚而不是简单列一个“面试题答案清单”。整个面试流程给人最直观的感觉是一面会快速验证你的编程能力和基础数据结构功底然后立刻转入大数据组件原理的深挖二面则更像一次“你愿不愿意把事情做扎实”的检验大量场景题都在模拟生产环境中真正会遇到的问题。我认为这两个维度的组合基本就是一个合格大数据工程师的日常既要能写代码也要能扛事。2. 一面实录编程基础、Hadoop体系与数据链路追问2.1 开场两道代码题考察的不只是能不能写出来一面面试官是一个看起来比我大不了几岁的工程师上来很直接说我们先写两道题不用跑通说思路加写伪代码就行。第一题是LeetCode上常见的“数组中的第K个最大元素”。这题看起来简单但我当时意识到他真正想看的并不是你背过没背过而是你能不能在手写代码的情况下讲清楚时间复杂度。我先说了两种方案一种是用小顶堆维护一个大小为K的堆复杂度是O(N log K)另一种是基于快速选择的partition思想平均复杂度O(N)最坏O(N^2)。面试官追问了快速选择的最坏情况是什么以及为什么加了随机化之后能大概率避免这个问题。这里他其实是想确认你有没有理解随机化算法背后的概率逻辑而不是仅仅记住结论。第二题是“判断一个链表是否有环并找出环的入口”。这题我比较熟快慢指针加一次相遇后重置指针就能解决。但面试官紧接着问了一个很有意思的问题如果链表特别大不能全部加载到内存里你怎么处理。这个问题本质上是在考察你有没有分布式思维。我当时的回答是如果链表不能全量放入内存就要看数据是怎么存储的如果是分布在多台机器上的那问题就会变成分布式图计算里的环检测可以考虑用类似Spark GraphX或者自研的分布式BFS方案来做。面试官点了点头没有继续往下深挖但我觉得这个追问本身就是大数据的信号——他们要的不是纯刷题选手而是能把问题放到分布式场景里去思考的人。两道题写完差不多用了25分钟然后面试官话锋一转开始问项目。我简历上写了一个离线用户行为分析平台他用这个项目串联起了后面整整30分钟的追问。所以如果你的简历上有项目一定要把项目里每一个细节都吃透因为面试官一定会把它当成“试金石”。2.2 Hadoop生态八连问从HDFS写入流程到MapReduce Shuffle项目里用了Hive做离线ETL数据存储在HDFS上所以面试官很自然地开始问HDFS相关的问题。第一个问题客户端往HDFS写一个文件完整的流程是什么。我讲了客户端先向NameNode发起请求NameNode检查权限和配额然后返回可以写入的DataNode列表客户端按块默认128MB依次写入写完一个块会进行校验和确认最后通知NameNode关闭文件。他接着追问如果写入过程中某个DataNode挂了怎么办我说客户端会收到写入异常的反馈然后从管道中移除这个DataNode继续向剩余的DataNode写入同时NameNode会将该块复制到其他节点以满足副本数要求。这块我答得比较顺因为之前在自己搭的集群上确实模拟过DataNode宕机的场景。第二个问题直接切到MapReduce的Shuffle阶段。他说很多人都知道MapReduce的Shuffle但你从map端输出到reduce端拉取整个过程中数据是怎么一步步组织起来的。我从map端的环形缓冲区说起map输出的结果先写入内存中的环形缓冲区默认大小100MB达到80%阈值时会触发spillspill之前会进行分区partition和排序sort然后根据配置决定是否做combinerspill产生的多个小文件会merge成一个大文件reduce端会通过HTTP拉取属于自己分区的数据拉取后同样进行merge和排序最后输入给reduce函数。面试官对环形缓冲区的阈值参数很感兴趣问我触发spill的比例默认是多少以及这个参数在哪里配置。这里我踩过坑因为平时写MR作业很少关注这些参数但面试就是会问这些“你不常用但必须要懂”的细节。mapreduce.map.sort.spill.percent默认0.8这个参数确实是可以调的建议面试前认真记一遍。第三个问题Hive的SQL是怎么变成MapReduce作业的。这个问题我用执行引擎的角度回答Hive会把SQL解析成抽象语法树AST然后经过语义分析生成逻辑计划再通过优化器做谓词下推、列剪枝等优化最后生成物理执行计划也就是一系列MapReduce任务。他追问了谓词下推在什么情况下可能失效我说比如分区表如果查询条件里对分区字段做了函数运算就会导致分区裁剪失效扫描全表。第四个问题是关于HDFS小文件问题的。他说你们做离线数仓Hive表底层经常会有大量小文件这会造成什么影响你们一般怎么处理。这个问题太经典了我讲了小文件对NameNode内存的压力、对MapReduce启动task的额外开销然后说出了几种处理方式用INSERT OVERWRITE配合DISTRIBUTE BY来控制reduce数量从而控制输出文件数量对于已经存在的小文件用ALTER TABLE ... CONCATENATE合并ORC文件如果是Parquet格式可以跑一个Spark作业用coalesce或者repartition重写数据。他追问为什么CONCATENATE对ORC格式比较合适而对Parquet不那么合适这其实是因为ORC有文件级别的统计信息和索引合并文件的代价较小而Parquet合并后需要重写元数据和索引代价要高一些。2.3 数据链路的一致性从WAL到最终一致性一面末尾面试官突然问了一个有点底层的问题HDFS为了保证数据不丢靠的是什么机制。我答了写入管道中的DFSOutputStream会以chunk为单位生成校验和同时NameNode的edits log是持久化的也就是通过WAL方式来保证元数据的一致性。他接着问那ZooKeeper有没有类似的机制两者有什么异同。我给了一个比较长的回答ZK的ZAB协议会把事务以日志形式写入磁盘并且超过半数节点确认后才算提交成功而HDFS的edits log其实也是先写本地磁盘再做合并但HDFS的NameNode是单点的除非启用NameNode HA在HA模式下会通过JournalNodes来同步edits log这里就用到了类似ZK的多数派思想。这场面试到这里就结束了总共大概55分钟。整体感觉是面试官非常清楚你想掩饰什么一追问就会暴露出来但只要你确实动手做过他不会揪着你不放而是会继续往下问。那种“我背过这个概念”和“我真的理解这个机制”的差别他一下子就听得出来。3. 二面深水区Spark、Flik与实时计算场景题3.1 Spark作业为什么会变慢从OOM到数据倾斜二面等了一周左右面试官看起来是部门里资历更深的工程师开场没有让我做代码题而是直接问项目里用的Spark版本和部署方式然后抛出第一个场景题假设你有一个Spark批处理作业在集群上一直跑得很稳定某天突然变慢了你会怎么排查。这个问题我觉得非常值得写下来因为它几乎完全复刻了生产环境里真实会遇到的情况。我当时按这个链路答的先看Spark UI上的Stage耗时分布哪个Stage耗时最长就点进去看然后看Executor的GC时间如果GC时间异常高大概率是内存不够导致频繁Full GC再看是否发生了数据倾斜判断方式是看某个Task处理的数据量远大于其他Task或者某个Stage的某个Task运行时间特别长确认是倾斜之后处理方式有加盐做两阶段聚合、调整并行度、对倾斜的key单独拆分处理等。他听完之后追问了一个很细节的问题你说的加盐两阶段聚合具体实现的时候要注意什么。我说第一要保证加盐后第一阶段的聚合结果能正确合并第二要注意加盐的随机值范围不能太小否则第二阶段还是会有热点第三是如果这个key本身业务上必须精确统计不能直接加盐可以选择把倾斜的key过滤出来单独跑。他点头后问了一个我没想到的问题如果你发现是某个Executor频繁OOM但你没法直接去看那个节点的日志你怎么定位到具体是哪个stage、哪个task的问题。这里我反应过来他是在考察远程调试和日志排查能力就说了可以通过Spark History Server查看Executor的stderr/stdout日志然后检查Driver的日志看有没有异常堆栈还可以借助jstack去dump线程栈但如果是用户代码的问题更快的做法是在代码里的foreachPartition或mapPartition里加一些针对性的日志输出用日志上下文去定位。这道题聊了大概15分钟让我感觉二面的节奏是一面完全不同的一面在快速验证你会不会二面在确认你遇到真实问题的时候会不会慌、有没有排查思路。3.2 Flink实时链路精确一次是怎么保证的项目里我也写了Flink做实时UV统计和实时大屏所以二面另一个重点自然落到了Flink上。面试官问Flink的Checkpoint机制能保证Exactly-Once吗它的底层原理是什么。我讲了Flink基于Chandy-Lamport分布式快照算法实现checkpointBarrier在流中流动每个算子收到Barrier后开始异步快照自己的状态Barrier对齐保证了快照的一致性。然后我补充了端到端的Exactly-Once还需要配合source端的消费位点保存和sink端的两阶段提交协议也就是Flink的TwoPhaseCommitSinkFunction。他追问如果你的source是Kafkasink是MySQL怎么保证不丢不重。我说KafkaSource会周期性提交消费位点到Kafka的内部topic但注意如果在checkpoint完成之前Job就挂了重启后会从最近一次成功的checkpoint对应的位点重新消费所以可能会有重复数据MySQL端的话如果MySQL不支持真正意义上的分布式事务可以考虑用幂等写入方案比如用唯一键去重或者将binlog作为最终对账的依据。他的下一个问题很典型实时计算里什么情况下会出现数据乱序怎么处理。我说Flink通过Watermark机制来处理事件时间乱序同时可以配合allowedLateness去容忍一定程度的迟到数据再结合侧输出流把超过容忍范围的数据发送到下游做单独处理。他问我Watermark设多长算合理我说要看业务对实时性的容忍度如果业务允许5秒以内的延迟Watermark可以设为5秒或10秒同时要考虑数据源本身的最大乱序程度这个值需要基于实际数据的统计分布来定而不是拍脑袋。这块聊完之后我明显感到二面对于实时计算的方向是有明确业务诉求的。猿辅导的业务场景里直播课的用户行为数据是海量的实时流数据他们需要在这条链路上做实时指标计算、异常行为检测和实时推荐所以Flink相关的题目不是随便问问而是真的会用到。3.3 数仓建模与维度建模从星型模型到缓慢变化维二面还问了一个比较“数仓向”的问题如果你要为一款在线教育产品搭建数据仓库你会怎么设计分层为什么。我按照经典的数据仓库分层理论来答ODS层存放原始数据不做任何加工DWD层做清洗、脱敏、维度退化形成明细事实表DWS层按业务主题做汇总形成公共汇总层ADS层面向具体应用生成报表和指标。他追问了一个非常现实的问题DWD层和DWS层之间的数据粒度是怎么定义的如果某个指标既需要按天粒度又需要按小时粒度你会怎么设计。这个问题让我想了一下因为很多面经里只讲了分层的名字没讲层与层之间的粒度约定。我回答说在DWS层做汇总时会按照业务方实际查询的最小粒度来设计比如同时保留按小时和按天的汇总表但为了避免数据冗余可以用一个汇总表同时记录小时粒度和天粒度配合时间维度字段来做区分。还可以考虑用ClickHouse的AggregatingMergeTree来预聚合在查询时直接查预聚合结果大幅提高查询性能。面试官听完之后没有说对不对而是顺势问了一个缓慢变化维SCD的问题如果用户修改了手机号你的数仓里的用户维度表应该怎么处理。我答了三种常见策略直接覆盖Type 1、保留历史并新增一行Type 2、增加历史字段列来保存上一次的值Type 3然后结合在线教育的场景说像用户手机号这种字段建议用Type 2因为后面做用户生命周期分析时需要回溯用户联系方式的变更历史但如果只是为了查询方便用Type 1可以减少数据量这里需要业务方在数据准确性和存储成本之间做权衡。说完之后我能感觉到他对这个回答比较认可因为他接着问了一个更贴近实操的问题你们的维度表是怎么保证每天刷新的如果有延迟你怎么办。这就涉及到了调度依赖和数据质量监控的范畴了。3.4 场景设计题如何从零搭一个实时大屏最后的场景设计题很有意思面试官说假设要做一个实时大屏展示全国各个城市正在观看直播课的用户数和累积观看时长数据源是前端埋点上报的日志延迟要求在5秒以内你会怎么设计整个链路。我思考了一下给出了一个相对完整的方案这里也分享给大家作为大数据架构设计的参考。整体链路分三层数据接入层、实时计算层和数据服务层。接入层用Nginx接收埋点日志然后通过Kafka作为消息队列缓冲。为什么用Kafka而不是直接写到后端服务核心原因是第一前端埋点日志的峰值流量和平均流量差距很大Kafka可以削峰填谷第二Kafka的分区机制天然适合后续的并行消费能够提高整个链路的数据吞吐能力。实时计算层用Flink消费Kafka中的数据主要做三件事一是清洗和过滤异常数据比如明显不合理的观看时长、空字段日志二是做维度关联把用户ID关联到城市、课程ID关联到课程名称这里需要维护一个维表我们当时是把城市维表放在Redis中用Flink的异步IO去查询三是做窗口聚合用事件时间配合滚动窗口每5秒计算一次各城市的在线用户数和观看时长。这里有一个非常容易忽略的点Flink作业的并行度设置。如果并发是100万级别的数据量并行度不能盲目配置需要通过压测来确认每个并行子任务能处理的QPS避免设置过大导致网络开销增加和状态后端压力过大。我建议先用一个较小的并行度跑起来观察背压情况再逐步调整到集群能承载的合理值。数据服务层我选择了用Redis或者TiDB来缓存计算好的指标前端大屏通过WebSocket推送数据。这里的关键问题是前端展示的指标是5秒一个窗口的中间结果如果直接查Flink的sink结果很容易因为下游存储的写入延迟导致前端界面数据闪烁。我们当时的做法是用Flik的结果先写入Redis的Hash结构中以城市为key然后用一个HTTP接口每隔5秒拉取一次Redis中的结果再推给前端WebSocket。这种方式的好处是Redis的读写性能足够高不会成为链路瓶颈。面试官听完之后问了两个让我印象非常深的问题。第一个是如果Kafka的某个分区出现堆积你怎么发现和处理。这个问题其实就是问消费能力不足和生产速率突增的经典问题。我说首先看Flink UI上的Kafka消费lag指标如果某个分区的lag持续上涨说明这个分区的消费能力低于生产速率常见处理方式有增加Flink作业的并行度但要注意增加并行度时Kafka分区的数量必须大于等于并行度否则还是会有空闲线程如果是因为某个key的数据量特别大导致该分区热可以对这个key做二次拆分在Flink端加一层哈希重新分区把热点数据分散到多个算子实例上。第二个问题是实时大屏上的数据如果出现偶发的不准确你如何对账。这个问题其实是在关注实时计算的可靠性。我的回答是用离线数据进行校验。比如T1的离线任务会对昨天的数据进行重新统计把实时计算的结果和离线计算的结果做比对如果偏差超过阈值就触发告警。这种方式在业界有个名字叫“实时离线数据对账”虽然不能完全自动化但能很早地发现问题。到这里二面基本上就结束了。整个二面持续了70分钟左右节奏很紧凑但并没有那种紧张压迫的感觉每个问题都给足了思考空间。4. 复盘总结这些准备项直接决定了面试成败上面讲的是面试过程的流水账复盘下面我把我认为在准备这个岗位时最关键的几个点单独拎出来说因为这些东西面试官不会直接告诉你但确实是拉开差距的地方。4.1 简历上的每个技术栈都要能挨个问到底很多人写简历会写“熟悉Hadoop、Hive、Spark、Flink、Kafka”但真正面试的时候面试官会从你最熟悉的那一项开始一路问到你不熟悉为止。所以写简历之前最好的做法是对每一个写上去的技术点自己先准备一个“三层追问体系”这个技术解决了什么问题它内部的原理是什么你在项目中用到了它的哪个特性有没有遇到过相关的问题。比如你写熟悉Kafka至少要能回答这些Kafka的ISR机制是什么leader选举是怎么做的消息是push还是pull模式为什么设计成pull你如何在项目中保证消息不丢不重。如果这些问题里有两个以上答不上来就先把该技术点从简历上撤下来。4.2 深度优先还是广度优先我在二面之前也纠结过一个问题是应该把所有大数据组件的面都铺开还是把其中一个组件研究得很深。后来对比了一下室友面试其他大厂的情况得出一个比较清晰的结论校招面试阶段广度决定了你的简历能不能过初筛深度决定了你面试能不能过。也就是说Hadoop、Hive、Spark、Flink这些主流组件至少要达到“能讲清楚原理、能说出常见问题点”的水平同时你必须在其中两个组件上达到“有真实项目经验能经得起连续15分钟追问”的深度。以我为例我的深度主要集中在Spark和Flink所以面试官问到的Spark内存模型、数据倾斜处理、Flink的checkpoint机制、两阶段提交这些问题时我能回答得比较细这会让面试官产生“这个人有实战能力”的判断。4.3 编程能力不是只刷题一面和二面虽然各有一两道代码题但说实话题目本身比字节跳动、美团的面试要温和不少。但不要因此放松警惕因为它考察的是你写生产级代码的潜力。比如一面里链表判环的问题正常人都会用快慢指针但面试官真正想听的是你对空间复杂度的敏感以及遇到超大链表时的分布式思路。我在面试前刷了大概150道LeetCode主要集中在中等级别重点是数组、链表、哈希、二叉树这四类。如果你的时间有限我建议按照这个优先级去刷因为大数据岗位的算法题很少出动态规划和图论难题反而更偏爱和数据结构、数据分布相关的题目。4.4 真实的项目经历是最大的底气这一点我想放到最后说因为它是我这次面试当中最深的感受。我在简历里写了两个项目一个是离线用户行为分析平台一个是实时UV统计和实时大屏。这两个项目一方面向面试官展示了我的技术栈覆盖面更重要的是为面试官提供了足够多的追问素材。面试中有一个很有意思的现象当你在回答一个关于Spark数据倾斜的问题时如果这时你能直接说“我在那个用户行为分析项目中就遇到过一次类似情况当时的现象是这样的最后我是这样解决的”面试官的信任度会瞬间上一个台阶。这比任何背熟的八股文都更有说服力。我也建议如果你现在还在准备阶段尽量自己动手搭一套集群环境用模拟数据把整套流程跑通而不是只看别人的博客和视频。只有真正部署过Hadoop、Spark、Flink搭建过Kafka和Hive你才会对配置文件里的哪些参数是核心参数、哪些参数是摆设有一个直观的判断这种经验是面试前临时抱佛脚记不来的。5. 那些面试里聊过的“隐藏问题”与应对建议除了上面说的主线问题面试中还有一些看似闲聊、其实暗藏考察点的小问题。我把它们单独整理出来因为这类问题最容易让人放松警惕。第一个是你在团队里如果和同事的方案有分歧你会怎么处理。这个问题不是大数据技术问题但猿辅导的面试官问了。他可能是想了解你在团队协作中的沟通方式和心态。我的回答是先梳理清楚两种方案各自的适用边界和数据支撑再向对方表达我的观点如果对方依然坚持我会尊重最终决定但会把自己认为的风险点记录下来后续用数据验证谁更合理。这种回答既表达了合作性又体现了独立思考能力。第二个是你平时是怎么关注大数据领域新技术的。这个问题其实是在看你的学习驱动力。我当时提到自己会关注Apache Flink和StarRocks这两个社区也会看一些国内外大厂的云原生数据架构博客。后来回想起来面试官可能更想听到的是你自己有没有主动去调研一些新技术而不是等公司安排。第三个是如果给你一个需求让你设计一个数据同步任务把MySQL中的数据实时同步到数仓你会怎么做。这个问题我当时是当场组织思路的回答的是用Canal监听MySQL的binlog将变更事件发送到Kafka再由Flink或DataX进行数据写入。面试官追问了Canal原理中binlog的三种模式的区别分别是ROW、STATEMENT和MIXED。这里强调一下ROW模式是Canal能工作的基础因为Canal需要拿到变更前后的行数据这个知识点会经常被问到。我把这些隐藏问题也放进来是想提醒大家面试不仅仅是技术考察更是整体的综合能力展示。你回答问题时的语言组织、思路清晰度、是否承认自己的理解盲区都直接影响最终的面试评价。6. 一些踩过坑之后的真心话写到这这篇猿辅导大数据校招的面经基本就复盘完了。最后分享几个踩过坑之后的体会希望能帮你少走弯路。第一不要等到面试前一天才去复习大数据组件的原理。像HDFS写入流程、MapReduce Shuffle、Flink Checkpoint、Kafka ISR这些知识点背下来只需要几个小时但如果之前没有理解过面试时一旦被追问到细节就会露馅。至少提前一周把这些核心机制用自己的话写成文字稿反复检查逻辑是否通顺你会发现很多你以为理解的概念其实写着写着就发现还有漏洞。第二面试中遇到不会的问题不要慌张更不要乱编。大数据这个领域很广遇到没接触过的组件和概念是完全正常的。我二面时被问到ClickHouse的合并树原理我当时只了解一个大概没有深入看过MergeTree的底层实现于是直接告诉面试官这部分我了解得还不够细但我了解它的适用场景和基本工作原理然后简单说了一下。面试官没有追着这个问题不放而是直接跳到了其他问题上。这种坦诚的态度不会减分反而会让面试官觉得你有清晰的自我认知。第三英语阅读能力真的很重要。大数据生态里最核心的文档、源码注释、社区讨论都是英文的面试中面试官提到的一个概念如果你平时通过阅读英文文档了解过回答起来会明显更顺畅。比如Flink的官方文档我面试前认真读过重点章节很多术语和原理直接用英文表达会显得更专业。第四给自己留一个复盘时间。我在每次模拟面试后都会把答不上的问题记下来整理到一个文档里然后针对每个问题写一个“标准答案”。这个习惯在准备猿辅导面试时帮了我大忙因为二面时有两个问题竟然是一模一样的。所以不管你是面哪家公司把自己不会的问题沉淀成一套个人题库很有价值。这次面试的经验大概就是这样。如果你正在准备大数据的校招希望这篇面经能给你一些启发也祝你能拿到心仪的Offer。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进