ARTICLE DETAIL

资讯详情

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

大数据校招笔试题核心考点拆解:从HDFS原理到Spark调优

大数据校招笔试题核心考点拆解:从HDFS原理到Spark调优 1. 写在前面一张2018年的卷子为什么今天还值得看收到“字节跳动2018校招大数据方向第三批”这个题目时我愣了一下。2018年那会儿字节跳动的招牌产品还在快速爬坡期大数据团队的扩张需求非常旺盛校招笔试的筛选力度和考察范围都相当有代表性。虽然不是每道题我都还记得一字不差但那一批大数据方向的题目方向、考察重点、以及候选人普遍栽跟头的地方我印象很深。别看是2018年的卷子放到现在依然很有参考价值。大数据方向的技术栈核心其实没怎么变过分布式存储、计算引擎、资源调度、数据倾斜、实时链路、数仓建模翻来覆去考的就是这些。变的只是框架版本和考察方式底层原理如果吃透了换什么壳都能应付。这篇文章我想从“准备这场笔试”的角度出发把大数据方向校招笔试里最有代表性的几个考察模块拆开揉碎讲清楚每个模块背后考的是什么底层能力再结合我当年踩过的坑和后来辅导新人时总结的经验给你一份可以直接照着复习的路线。无论你是正在准备大数据校招的应届生还是刚转行做数据开发不久的新人这篇文章应该都能帮你省下不少瞎折腾的时间。2. 整体备考思路从“背八股”到“讲原理”2.1 笔试到底在筛什么很多人在准备大数据笔试题时有个误解觉得刷题就行了把面经里的题背熟考试时默写出来就过。我见过太多这种类型HDFS写流程背得滚瓜烂熟但被问到“如果NameNode挂了怎么办”就支支吾吾MapReduce的Shuffle过程能画出来但被问到“为什么需要Combiner”就答不到点子上。2018年这批题目给我的整体感觉是它不只是考你知不知道这个组件而是在考你“遇到具体问题时能不能用这个组件解决问题”。所以它会有大量的场景题和设计题。比如给你一个数据量级问你用什么样的架构来处理比较合理比如给你一个业务场景问你怎么设计一个实时指标计算链路。这类题目没有标准答案但能清晰暴露你到底是背出来的还是理解出来的。备考的第一个原则不要只背结论要能讲清楚“为什么”。Kafka为什么要分区不分区行不行Spark为什么要引入DAG跟MapReduce比优势在哪里HBase的LSM-Tree为什么比BTree更适合写密集型场景。这些问题如果能不看资料讲明白才算真正过关。2.2 再看一次2018年第三批的时间背景2018年是个很特殊的年份。那一年Spark在大数据处理领域已经完全是主流但Flink还远不像今天这么普及很多人对流处理的认知还停留在Storm。那一年Kafka 1.0刚发布不久Kafka Streams在社区里还比较新。那一年Hadoop 3.0刚刚发布但生产环境主流还是Hadoop 2.x。也就是说2018年的笔试题里实时计算部分的比重不会像今天那么大但会考基础的事件时间、窗口、水位线这类概念。数据处理框架部分重点还是会放在MapReduce和Spark上这跟2018年的技术生态是吻合的。如果你是现在备考反而要额外补上Flink和Kafka的部分因为这几年的技术风向已经变了。所以看当年的题正确的姿势是用当年的考法来理解考察意图再结合当前的技术栈来做知识补充。核心原理是通的但回答时的技术选型要体现出“我知道现在的主流是什么”的敏感度。3. 核心细节拆解那些必考必问的硬核考点3.1 分布式存储HDFS的机制与容错HDFS基本属于必考模块而且题目不会只停留在“数据块默认128MB”这种记忆层面更常见的问法包括数据块为什么设置成128MB调大调小会有什么影响。读写流程中涉及到哪些角色哪个环节最容易成为瓶颈。副本机制是怎么实现的副本放置策略具体是什么。如果DataNode挂了HDFS怎么恢复数据的完整性。小文件问题是怎么产生的有哪些治理手段。我挑几个容易答偏的点展开讲讲。首先是数据块大小的选择逻辑。128MB的大小不是拍脑袋定的它的核心是“寻址开销与传输开销的权衡”。NameNode上的元数据是存在内存里的每个数据块元数据大约占150字节左右在总内存固定的情况下块越小能容纳的块数量越多但元数据总占比变大块越大单个块的寻址时间占比越低传输效率越高但并行度会下降。128MB是在普通Linux文件系统IO性能和网络传输性能的平衡点上算出来的数值不是随随便便确定的。再一个考生容易答不完整的是副本放置策略。默认副本因子是3第一副本放在客户端所在节点如果客户端不在集群内就随机选一个第二副本放在与第一个副本不同机架的节点上第三副本放在与第二副本相同机架的不同节点上。这样设计的目的是兼顾可靠性、写入带宽和容错数据有三个副本可以承受单个节点和一个机架同时故障读写数据时可以尽量在不同机架上并行拉取。实际面试时这些机制知道还不够最好能补充一些线上调优经验。比如我曾经负责过的一个集群NameNode堆内存常年紧张排查下来就是离线任务生成的小文件太多一个百万级分区表的业务跑了三个月文件数突破了千万级。后来我们做了两层优化一是对存量小文件做合并用Hive的concatenate或者Spark repartition重新写一遍二是在写入链路层做了控制限制动态分区的数量并且开启Hive的merge-small-files开关。效果很直接NameNode堆内存使用率降了将近40%。3.2 计算引擎MapReduce与Spark的异同与演进2018年的笔试里MapReduce和Spark的对比题基本属于送分题级别但送分题恰恰最容易答得浅。很多人只会说“Spark基于内存计算所以比MapReduce快”这个回答只能拿一半分。正确且完整的答法应该分几个层面计算模型层面MapReduce的每个Map、Reduce阶段都会落盘中间结果写磁盘后续阶段从磁盘读大量IO开销Spark通过RDD的血缘关系构建DAG尽可能在内存中完成计算中间结果不落盘。调度层面MapReduce的每个Job都是一个独立的执行单元Job之间的数据复用要通过外部存储比如HDFSSpark把一个应用切分成多个StageStage之间通过Shuffle衔接同一个应用内的多个算子可以流水线式执行。容错层面MapReduce出错重算的是整个TaskSpark基于血统机制只重算丢失的分区代价更小。编程模型层面MapReduce只提供Map和Reduce两个原语复杂逻辑需要用多个Job串起来Spark提供了丰富的算子map、filter、flatMap、reduceByKey、join、groupByKey等表达能力更强。要说清楚Spark的“快”还要理解一个关键概念Lazy Evaluation。Spark中的transformation操作是惰性求值的只有遇到action操作才会真正触发计算。这样做的好处是Spark可以合并多个操作形成一个优化的执行计划减少不必要的Shuffle和落盘。有一道经典题几乎年年出现Spark的宽依赖和窄依赖有什么区别为什么宽依赖会导致Shuffle。窄依赖是指每个父RDD分区最多被子RDD的一个分区使用比如map、filter宽依赖是指父RDD的每个分区可能被子RDD的多个分区使用比如groupByKey、reduceByKey。宽依赖会导致数据需要跨节点传输也就是Shuffle。在读源码或者看执行计划时这两个概念直接决定Stage怎么划分——遇到宽依赖就切割Stage遇到窄依赖就把多个算子放在同一个Stage里流水线执行。我强烈建议你去Spark UI里看一次真实任务的DAG图和Job列表把Stage划分的边界和Shuffle的环节对应起来看一遍比看十篇面经都管用。3.3 数据倾斜一道数据分析师都能聊几句的题大数据笔试题里数据倾斜大概是最“常青”的考点。2018年考2025年还在考。因为它是真实生产环境中最常见、最棘手的问题之一。题目的问法通常很直接一个Spark任务reduce阶段很多Task都跑完了只有一个Task卡了几个小时你怀疑是数据倾斜怎么定位怎么解决。定位的方法要说清楚看Spark UI中各个Stage的Task耗时分布如果绝大多数Task在几十秒内完成个别Task耗时异常长基本可以判断是数据倾斜。看是否有大量的Shuffle读写。倾斜的Task往往Shuffle Read的数据量是其他Task的好几倍。如果业务代码里有按某个Key分组或Join的逻辑可以单独统计一下这个Key的数据分布确认是不是集中在少数几个值上。解决手段要能给出适用场景增加shuffle分区数。这个方法最简单但如果某个Key本身数据量就极大分区数再多也分散不了这个Key内部的压力。记住这个方法只适用于“倾斜不明显”的情况。两阶段聚合也叫局部聚合加全局聚合。思路是先给Key加随机前缀比如加一个1到10的随机数把原本集中在同一个Key上的数据打散到多个分组完成局部聚合后再去掉前缀做一次全局聚合。这个方案适用于聚合类操作但对Join类操作无效。广播小表。如果一个表很小默认阈值是10MB可以通过spark.sql.autoBroadcastJoinThreshold调整可以把它广播到每个Executor用map端Join替代reduce端Join从根本上避免Shuffle。如果业务允许这是最简单的方案。针对Join场景的倾斜Key单独处理。先把倾斜的Key过滤出来单独做Join再和非倾斜的数据union起来。比如用salting加盐的方式把大Key膨胀成多个小Key去关联小表。我自己的习惯是先看数据分布再决定方案。很多时候问题不在技术层面而在于业务本身对空值或者默认值的处理不规范导致大量数据都打到了同一个Key上。SQL里加一个条件把异常值过滤掉可能比任何技术优化都管用。所以笔试题里如果能提到“先检查业务数据的质量”是会加分的。4. 实操过程与核心环节完整过一遍典型题型4.1 题型一手写WordCount以及它的进阶变体WordCount相当于大数据界的“Hello World”考它的意义不在题目本身而在于确认你有没有真的动手写过代码有没有真正理解MapReduce和Spark的执行流程。Spark版本先看一个最基础的实现import org.apache.spark.{SparkConf, SparkContext} object WordCount { def main(args: Array[String]): Unit { val conf new SparkConf().setAppName(WordCount) val sc new SparkContext(conf) val textFile sc.textFile(hdfs:///input/) val counts textFile .flatMap(line line.split( )) .map(word (word, 1)) .reduceByKey(_ _) counts.saveAsTextFile(hdfs:///output/) sc.stop() } }这个答案能过基本关但要拿高分还得答出几个延伸点。第一个延伸点是flatMap和map的区别。很多基础不扎实的人会在这两个算子间踩坑。map一对一的映射输入一行输出一行flatMap先map再展平输入一行可能输出多行。WordCount里如果误用成map(line line.split( ))得到的是每行单词数组的集合后面的处理逻辑就完全不对了。第二个延伸点是reduceByKey和groupByKey的选择。这两个算子都能实现分组聚合但性能特性完全不同。groupByKey会把所有键值对原样Shuffle到下游不提前聚合reduceByKey会在Map端先做一次本地聚合Shuffle的量就小很多。最简单的记忆方法能用reduceByKey就绝不用groupByKey。第三个延伸点是分区数的设置。默认情况下reduceByKey输出的分区数等于父RDD的分区数在集群规模较大的情况下可能偏少导致每个Task处理的Reduce数据量过大。合理做法是显式指定分区数比如reduceByKey(_ _, 200)200这个数值需要根据数据量来估算单个分区建议处理200MB到1GB之间的数据如果预估输入是200GB200个分区比较合适。高级一点的变体题是“统计每个文件中出现次数最多的Top10单词”。这类题考察的是Combine和Reduce的配合以及输出排序的技巧。Spark实现大概是val top10 textFile .flatMap(line line.split( )) .map(word (word, 1)) .reduceByKey(_ _) .mapPartitions(iter iter.toList.sortBy(-_._2).take(10).iterator) .collect() .sortBy(-_._2) .take(10)这里的mapPartitions是为了在每个分区内先做一轮局部Top10减少后续收集阶段的数据量。如果在笔试时能主动提到这个优化说明你已经不只是会写样例代码了。4.2 题型二实时计算链路设计题从Kafka到指标输出2018年第三批的题目里实时计算相关的考察方式基本是场景题。比如有一个用户行为日志流每秒几百MB的数据量你需要实时统计每种页面的PV和UV并输出到存储系统供前端大屏展示怎么设计这条链路。这种题没有标准答案但考察的知识点是固定的数据接入层Kafka的Topic设计、分区策略、副本因子设置。流处理层用什么框架2018年的主流答案是Storm或Spark Streaming今天的主流答案是Flink如何保证状态一致性。数据输出层结果写到什么样的存储里Redis简单指标、ClickHouse多维分析还是消息队列。端到端延迟全链路从事件发生到前端可见大致是秒级还是分钟级。我先给出一个今天依然适用的参考方案然后逐个环节讲解设计理由。Kafka配置方面Topic按业务线拆分比如page_view、button_click、item_view各一个Topic分区数建议设置为流处理框架Consumer并行度的整数倍比如Consumer并行度是12分区数就可以设成24副本因子按集群节点数来至少2有条件就3。流处理框架选型今天的答案基本可以毫不犹豫地写Flink。它的事件时间处理、精确一次语义的checkpoint机制、窗口API的完备程度都是Spark Streaming基于微批在实时性上没法比的。面试如果追问原理要能说出Flink通过Barrier机制实现checkpoint当某个算子处理到Barrier时会把当前状态快照保存到持久化存储如果任务失败就从最近一次成功checkpoint恢复状态并重放这段时间的数据从而做到精确一次。指标计算的实现方式给一个Flink示例思路DataStreamUserBehavior stream ...; stream .filter(behavior - pageView.equals(behavior.getEventType())) .keyBy(behavior - behavior.getPageId()) .window(TumblingProcessingTimeWindows.of(Time.minutes(1))) .aggregate(new CountAggregate(), new WindowResultFunction()) .keyBy(result - result.getWindowEnd()) .process(new TopNHotItems(5));这个例子里有两点值得展开。第一是为什么用ProcessingTime而不是EventTime。如果业务对事件乱序不敏感比如页面PV统计用ProcessingTime可以降低延迟不用维护水位线但如果指标要求准确回溯比如统计用户从点击到购买的完整转化路径就必须用EventTime。第二是TopN的求法用窗口聚合得到每分钟每个页面的访问量后再按窗口结束时间分组在ProcessFunction中用优先级队列保存当前窗口内访问量最高的N个页面定时输出。我印象特别深的是很多基础不错的人会在“结果输出”这个环节答崩。问计算好了的实时指标存在哪里为什么。如果只回答“写进MySQL”面试官基本会追问一句“MySQL扛得住这么高频率的写入吗”。这里需要给出有说服力的选型。简单指标优先Redis用Hash或ZSet结构TTL设置好多维明细查询类指标写入ClickHouse用MergeTree表引擎按时间分区如果需要供下游再次消费就写入Kafka的另一个Topic。关键是要说清楚每个存储的定位和原因。4.3 题型三离线数仓设计题从需求到分层离线数仓相关的题目几乎年年有而且权重很高。典型的问法给一个电商业务背景有订单表、用户表、商品表需要统计每日销售额、各品类销量、用户复购率等指标你怎么设计数仓。正确答法要体现出对数仓分层的理解。我直接用最经典的ODS、DWD、ADS三层来展开。ODS层原样接入业务库数据以增量全量两种方式同步。这个层的数据基本不动保留原始状态方便回溯。DWD层做清洗和标准化把埋点日志和业务表做整合统一字段命名和类型生成明细事实表。比如订单表在这个层拆出“订单事实表”和“订单状态快照表”把用户维度和商品维度冗余进来便于后续分析。ADS层面向具体业务需求产出汇总指标。比如每日销售额表、品类销售排行表、用户留存分析表。这一层的数据量通常显著减少查询响应快可以直接对接报表平台。分层的意义在于第一清晰的管理边界。每一层各司其职某个环节出问题可以快速定位不用像面条一样全串在一起。第二数据复用性。DWD层的明细表是统一的ADS层不同主题的指标都从DWD层取数不会出现同一个指标在不同统计里口径不一致的情况。指标口径是笔试和面试中最容易暴露经验的环节。同一个“销售额”有的是含税价有的是不含税价同一个“用户数”有的按手机号去重有的按设备ID去重有的按登录账号去重。如果没有在数仓建设初期定义好口径后面每次取数都是一场纠纷。所以在做题时如果题目给出了具体指标一定要反问或明确统计口径这个小举动体现的是你对业务和数据关系的理解深度。4.4 题型四大数据集群部署与资源管理2023年之后的热搜词里出现了“大数据集群部署策略”这其实在2018年的笔试里也是一个考察方向问法更基础给几台物理机你怎么规划一个Hadoop集群。回答的思路要分几块讲清楚。硬件规划NameNode和ResourceManager需要较大的内存建议单独节点部署不要和DataNode混布DataNode需要大容量磁盘建议每节点配置多块数据盘RAID或JBOD都可以HDFS自身有副本机制不需要RAID提供数据冗余JBOD更经济机架感知要配置好保证副本能分布在不同机架。组件规划NameNode、ResourceManager、HMaster等Master角色部署在不同节点上避免单点集中在同一台机器ZooKeeper一般部署3或5台奇数是为了选举机制能正常判定如果装了HBaseRegionServer和DataNode混部比较常见可以利用数据本地性。资源管理YARN队列怎么划分生产环境一般按业务线拆分成多个队列每个队列设置最小和最大资源比例避免某个业务把集群资源全部占满。我现在回看早年踩过的一个坑某个离线任务疯狂占用资源直接导致同集群的实时任务数据延迟飙升。后来把实时任务的资源调高优先级并在独立队列运行才把问题根治。集群部署策略在笔试中通常要求画出架构图给出各节点角色分配表。这种题考察的不是你记没记住官方推荐而是你有没有从稳定性、成本、数据安全三个维度综合思考。5. 常见问题与排查技巧实录5.1 经典笔试连环坑这里整理几个我见过最多人掉进去的坑以及对应的正确思路。第一个坑是Kafka消费者组与分区的关系。题目常见问法一个Topic有4个分区同一个消费者组里有3个消费者请问每个消费者消费几个分区。答案是3个消费者分别消费不同分区但其中有1个消费者会多消费1个分区4个分区分给3个消费者实际分配为2、1、1。如果同一个消费者组里的消费者数大于分区数那么多余的消费者会空闲。这个知识点几乎每次都考要理解背后的逻辑消费者组内的消费者不应该超过分区数否则有消费者是闲置的。第二个坑是Hive和MySQL的区别。问得直白一点Hive能用MySQL替换吗。很多新手会陷入“都能存数据”的误区。正确理解是Hive不是数据库它只是把SQL翻译成MapReduce/Spark作业执行数据本身存在HDFS上MySQL是OLTP型关系型数据库擅长事务处理和点查Hive适合OLAP式的批量分析。日常开发中两者常配合使用Hive算完结果导出到MySQL供线上查询。第三个坑是数据一致性问题。比如在Spark Streaming或Flink中任务重启后可能重复消费Kafka的数据导致指标偏高。答题要点是区分at-most-once、at-least-once、exactly-once三种语义以及各自实现方式。Flink通过Kafka消费者的offset由Flink checkpoint管理实现精确一次前提是Kafka版本支持0.11及以上且开启了checkpoint。2018年考这个还比较少但今天基本属于必考内容。第四个坑是“为什么我的Spark任务跑得比MapReduce还慢”。这题很有迷惑性得从配置层面分析。常见原因包括数据倾斜没处理、分区数设置不合理每个分区处理数据量太小任务调度开销大于计算收益、序列化方案没配置默认的Java序列化远不如Kryo、Executor内存和核数配置不匹配导致频繁GC。回答这类问题建议按“定位问题→分析可能原因→逐项验证”的思路来不要一上来就说“数据倾斜”虽然这个问题最常见但题目没说数据倾斜就不能强行套。5.2 一道容易翻车的“场景设计”面经题来一道比较典型的场景题有一张用户行为表每天新增10亿条记录主键是用户ID和时间戳。需要支持按用户ID查询最近30天的行为记录并且要求延迟在百毫秒级你会怎么设计存储。这个题挂在“大数据”背景下很多人会脱口而出“放HBase”。这个答案不算错但只说一个“放HBase”肯定拿不到高分因为它没回答出设计的核心逻辑。HBase能胜任这个场景的关键在于RowKey设计。如果RowKey直接用“用户ID_时间戳”那么同一个用户的行为记录会按时间顺序连续存储查询某个用户的最近30天记录时只需要Scan一个连续范围效率很高。如果把时间戳放在用户ID前面数据就会按照时间维度分布到不同Region查询某个用户时可能要跨多个Region性能大打折扣。这个细节就是考题想看到的东西。如果继续深挖还可以补充HBase的行键设计原则长度不宜过长避免热点尽量用散列前缀。在这个场景里可以对用户ID做散列取模作为前缀再把原始用户ID和时间戳拼上去。这样既能均匀分布又能兼容按用户查询的需求。5.3 常见问题排查速查表把这些年在实际排查和大数据笔试题中反复出现的问题整理成一个速查表方便你冲刺前快速过一遍。现象可能原因快速处理方法Spark任务某个Task长时间不结束数据倾斜Spark UI查看Task耗时与Shuffle读数据量差距确认倾斜Key后分别尝试加盐、广播、过滤等方式Kafka消费延迟持续增加消费者处理能力不足或分区数不足确认消费者group消费线程数、单条消息处理耗时、是否有频繁的rebalance增加分区或消费者实例HDFS空间频繁告警小文件过多或历史数据未清理检查NameNode块数量合并小文件或设置自动清理策略开启Hive合并Hive SQL跑得极慢数据倾斜、缺少分区裁剪、未使用列式存储检查执行计划确认是否扫描了全表是否可用ORC/Parquet加压缩格式YARN任务大量失败内存配置不足检查Container内存与堆内存设置确认是否有数据量超过配置的场景实时任务重启后指标偏高重复消费确认checkpoint是否开启及配置确认Kafka offset重置策略确认幂等输出是否实现NameNode内存溢出元数据过多清理无用的文件目录合并小文件评估是否扩容NameNode堆内存这个表基本覆盖了从分布式存储到实时计算再到离线SQL的常见问题。每一行都值得你展开去读一下相关的原理面试官对“你处理过什么问题”的兴趣远大于“你背了几道题”。6. 关于备考路线和节奏的一点个人建议准备大数据方向的校招笔试也好面试也好我的核心思路一直是“横向铺面纵向挖深”。横向铺面是指Hadoop生态里核心组件的角色和关系要清楚——HDFS负责存YARN负责资源调度Spark/Flink负责算Kafka负责传输Hive负责SQL化——各组件之间的数据流线画得出来整体架构图能解说得流畅。纵向挖深是指至少选择两个组件进行原理级学习建议是Spark和Kafka原因很简单一个是当前离线和实时计算的主力引擎一个是几乎所有数据链路必经的消息管道。把这两个的原理吃透你的技术深度在面试官眼里已经立住了。具体准备节奏上我建议分成三到四周第一周夯实基础。把HDFS、MapReduce、Spark核心机制过一遍动手写一遍WordCount认真看一遍Spark UI的执行流程。目标不是“我学会了”而是“我能不看资料讲出来”。第二周重点突破。选择一个场景做全链路设计练习比如“实时统计热门商品的PV和UV”从Kafka接入、Flink计算、存储输出整条链路走一遍。这个练习如果能真正在本地环境跑起来理解深度完全不一样。第三周刷题与复盘。集中做历年真题和面经题每道题不只背答案把答案背后的原理写出来形成自己的知识体系。遇到不会的题目不是坏事它是你查漏补缺的清单。第四周模拟实战。找朋友或者自己录像做一次完整的模拟面试和笔试。重点是控制时间笔试题目量通常很大要练出“先做会做的再啃不会的”的节奏感。我见过太多人复习到最后陷入“背题焦虑”和“刷题疲劳”状态越差效率越低。大数据这个方向最大的特点是知识面宽但逻辑自洽只要把核心组件的原理真正理解了大部分题目都是同一套逻辑的变体。知识本身没有捷径但理解可以让你走得比纯靠死记硬背的人快得多。最后说一句我自己的体会2018年那一批卷子难的其实不是技术本身而是选拔标准里非常看重“你能不能把一个复杂问题拆成几个简单的子问题”。这个概念到现在依然是核心能力。你在准备过程中遇到的任何一个模糊的概念都值得停下来花半小时彻底弄懂。这些“停下来”的时间最后都会变成你在考场上稳住的底气。
返回列表