
又到秋招季總有學弟學妹跑來問我大數據開發方向的筆試題到底怎么準備我的建議向來是同一個——先找一套完整的大廠真題從頭到尾認真做一遍比漫無目的地刷幾個月短視頻里的“面試技巧”有用得多。如果你問哪套題最適合用來摸底我通常會推薦愛奇藝2019秋招大數據開發方向筆試題B。原因很簡單這套題覆蓋面夠廣Java基礎、并發、大數據組件、Linux命令、SQL、手寫代碼全都有難度梯度也算合理特別適合當成一張“能力體檢表”來用。我當年把這套題的回憶版翻來覆去做了三遍后來去其他公司面試時發現很多考點是相通的。今天就把我對這套題的分析、做題過程中查漏補缺的知識點以及從這套題里反推出來的秋招備戰思路一次性整理出來。不需要你基礎多好只要你有一定 Java 和 Hadoop 生態的使用經驗這篇文章就能幫你把零散的知識串成一條線。1. 這套筆試題為什么值得反復拆解1.1 從崗位JD反推考察重點想弄明白一套筆試題為什么這么出最直接的方法是看崗位 JD。大數據開發這個崗位在愛奇藝這類視頻平臺日常面對的絕不僅僅是“寫幾個 MapReduce”那么簡單。視頻網站每天產生海量用戶行為日志點擊、播放、暫停、拖拽、搜索、評論、付費這些日志經過采集、清洗、ETL、數倉建模、指標計算最終支撐推薦、廣告、會員運營等業務方做決策。所以這個崗位要求的能力是復合的既要懂 Java 這種主力開發語言又要熟悉 Hadoop、Spark、Flink、Kafka 這套大數據生態組件還要能寫復雜的 SQL 和 Shell 腳本偶爾甚至要自己調 JVM 參數、排查線上 OOM。愛奇藝這套筆試B的考點布局基本上就是按照這個能力模型來的。很多同學拿到試卷第一反應是“怎么考這么多 Java 基礎”覺得大數據開發不應該只考框架嗎這個認知在面試里很吃虧。大數據框架本身就跑在 JVM 上Hadoop、Spark、Flink、Kafka 的源碼全是 Java/Scala 寫的你如果連 HashMap 的結構、并發編程的基本機制都說不清楚面試官很難相信你能讀懂框架源碼、能定位線上問題。所以 Java 基礎部分不是湊題數是篩人。1.2 題型分布與答題節奏從各個渠道流傳的回憶版來看B 卷大致分為四類單選題、多選題、簡答題、編程題。單選多選主要覆蓋 Java 基礎、并發、JVM、Linux 命令、SQL 語法、大數據組件原理簡答題一般會有一兩道讓你描述 MapReduce 流程、Spark 任務執行流程或者數據傾斜解決方案的題編程題則是傳統的數據結構與算法題偶爾會結合大數據場景。這里有一個很關鍵的答題節奏問題選擇題不能戀戰。每道選擇題的分值并不高但如果在兩道爭議題上死磕十分鐘后面編程題的時間就會被壓縮。我記得當時給自己定的規則是單道選擇題最多兩分鐘拿不準的先標記等編程題寫完再回頭蒙。整套題里真正的拉分項永遠是編程題和簡答題不要在基礎題上丟了西瓜撿芝麻。1.3 B 卷背后的“套卷機制”標題里的B不是隨便標的。大廠筆試通常會在同一時間安排多套試卷題目一樣但順序打亂或者抽選不同子題集目的就是防止前后排考生對答案。這也是為什么你在網上看到同樣的“2019秋招大數據開發筆試題”有人說是 A 卷、有人說是 B 卷題目卻大同小異。準備的時候不用糾結自己考的是哪一套考點就那么多把核心知識點全部過一遍任何卷子都能應付。2. Java與并發看起來是選擇題實則是淘汰主戰場2.1 為什么大數據開發要死磕 Java 基礎大數據開發的日常工作中Java 不是“偶爾用一下”的語言而是主力語言。你用 Spark 寫分析任務雖然可以用 Scala 或者 PySpark但閱讀源碼、調優、排查問題最終都會落到 Java/JVM 層面。愛奇藝這套筆試題里Java 相關題目占比相當高而且考察得非常細。這不是為難人而是想篩掉那些只背框架 API、不懂底層原理的簡歷選手。我之前幫部門做過校招面試發現一個明顯的規律Java 基礎扎實的人大數據框架學得也快因為 Spark 的 RDD、DataFrame 也好Flink 的 Watermark、Checkpoint 也罷本質上都是 Java 并發、集合、網絡編程的封裝。你明白 HashMap 的擴容原理就更容易理解 Spark 的 shuffle 為什么會產生大量小文件你明白 JVM 內存模型就更容易理解為什么大數據任務要設置 executor memory 參數。2.2 HashMap、ConcurrentHashMap 與并發安全的底層邏輯集合框架是 Java 基礎題里的“必考點”愛奇藝這套題也不例外。比較有代表性的考察方式是這樣的問題JDK 7 和 JDK 8 中 HashMap 的實現有哪些差異為什么 HashMap 在并發場景下不安全這個題幾乎每年都出現但能答全的人不多。正確的答題框架應該是JDK 7 的 HashMap 底層是數組加鏈表插入元素時采用頭插法擴容時多線程并發 put 可能形成環形鏈表一旦 get 的時候發生死循環CPU 直接飆滿。JDK 8 改成了數組加鏈表加紅黑樹鏈表長度超過 8 且數組長度超過 64 時樹化插入改用尾插法從機制上避免了死循環問題但并發場景下仍然可能出現數據覆蓋、size 計數不準確等問題。所以并發場景要用 ConcurrentHashMap。如果再追問 ConcurrentHashMap 的原理JDK 7 是分段鎖把整個 Map 分成 16 個 Segment每個 Segment 是一把鎖JDK 8 放棄分段鎖改用 CAS 加 synchronized 鎖住桶的首節點鎖粒度更細并發度更高。這種層層遞進的答法比背幾句“線程安全基于 CAS”的面試話術要顯得有底氣得多。2.3 JVM 與 GC 的考察方式JVM 相關題目在 B 卷里也占據一席之地常見考法有內存區域劃分、GC 算法、OOM 場景分析。這類題看起來很“后端”但大數據開發同樣躲不開因為跑 Spark/Flink 任務時OOM 是出現頻率最高的線上事故之一。我推薦用“畫圖加舉例”的方式復習把堆內存、虛擬機棧、本地方法棧、方法區、程序計數器的職責先講清楚然后結合一個具體場景——比如一個 Spark Executor 頻繁 Full GC你會怎么排查一般思路是先用jstat看 GC 頻率再用jmap導出堆內存快照用 MAT 分析哪個對象占內存最大。如果你能在筆試簡答題里寫出這個排查鏈路面試官對你的印象會明顯不一樣。GC 算法方面CMS 和 G1 的區別是高頻考點。CMS 基于標記清除并發收集但會產生內存碎片G1 把堆劃分成 Region基于 Region 做局部回收可以預測停頓時間。JDK 9 之后 G1 成為默認垃圾回收器JDK 17 以后 ZGC 開始普及這些演進脈絡也可以順帶了解。2.4 數組與指針從 Java 數組到 C 指針的延伸搜這套題的同學經常會連著搜“數組和指針筆試題”說明這類題在筆試里出現頻率很高。Java 里沒有指針的概念但數組本身就是一種引用類型所以考題會圍繞數組的拷貝、引用傳遞、內存分配展開。比如問題int[] a {1,2,3}; int[] b a; b[0] 100;此時a[0]是多少答案是 100。因為b a賦值的是引用兩個變量指向同一塊堆內存修改 b 的元素等于修改 a 的元素。這是 Java 基礎題里最經典的坑也是很多非科班同學容易忽略的點。C 語言的指針與數組又是另一套完全不同的玩法數組名是常量指針a[i]本質上是*(a i)的語法糖。雖然大數據開發崗位基本不會讓你寫 C但筆試偶爾會出這類題來考察計算機基礎是否扎實。應對方式很簡單把指針加減、指針數組和數組指針、函數指針這幾個概念過一遍即可不需要深入。2.5 Java 基礎部分的備戰方式針對這套題折射出來的 Java 考點我的建議是不要只看面經要自己動手做實驗。比如 HashMap 的樹化條件你就寫一段代碼往 HashMap 里插入哈希值相同的 key觀察鏈表什么時候變成紅黑樹再比如 volatile 的可見性你寫一個多線程程序驗證一下不加 volatile 時死循環的現象。這些實驗做完之后你會發現很多題不再需要“背答案”而是憑理解就能推導出來。3. 大數據組件原理MapReduce、Spark 與 Kafka 的考察重心3.1 視頻平臺的真實數據鏈路愛奇藝這類視頻平臺的數據鏈路很有代表性。以一次用戶播放行為為例客戶端上報播放日志到 KafkaFlink/Spark Streaming 消費 Kafka 數據進行實時清洗與此同時離線任務把日志落盤到 HDFS通過 Hive/Spark SQL 做 ETL按天構建數倉分層最終產出播放量、完播率、觀看時長等核心指標。理解了這條鏈路你就明白為什么筆試題會同時考察 Kafka、Flink、Spark、Hive 這些組件。它們不是孤立的知識點而是同一套數據流轉過程中的不同環節。考試的時候別只顧著背每個組件單獨的特性能講清楚一條數據從產生到最終形成報表的完整流轉過程才是面試官真正想看到的。3.2 MapReduce 與 Shuffle必考的流程題MapReduce 的 Shuffle 過程幾乎是大數據筆試的“釘子戶”。愛奇藝這套題簡答題部分很可能會有這么一道描述一個 MapReduce 任務從提交到完成的完整流程。答題不能只寫“Map 階段輸出中間結果Reduce 階段匯總”那樣太單薄。完整的回答應該包含這幾個階段InputFormat 對輸入數據進行切分生成 InputSplitRecordReader 將數據解析成 key-value 對Mapper 處理數據后map 輸出先寫入環形緩沖區默認大小 100MB達到 80% 閾值時觸發溢寫溢寫前會做分區和排序默認按 key 的哈希值分區溢寫會產生多個小文件之后執行歸并排序合并成一個大文件同時做 Combiner 局部聚合Reduce 端通過 pull 方式拉取屬于自己的分區數據做一次完整的 shuffle然后再進行分組排序最終調用 Reduce 函數。一個容易踩坑的細節是很多同學分不清“分區”和“分組”的區別。分區是決定某個 key 進入哪個 Reduce 分區分組是決定哪些 key 值被認為是同一個 key從而調用一次 Reduce 方法。在 Hive 中group by作用于分組而 MapReduce 的分區數決定 Reduce 個數兩者不是說一回事。3.3 Spark 核心RDD 依賴、Stage 劃分與數據傾斜Spark 的考察重點集中在 RDD 依賴關系、Stage 劃分、Spark SQL 和調優方向。寬依賴和窄依賴的區別是必考題。窄依賴是指父 RDD 的每個分區最多被子 RDD 的一個分區使用典型操作有 map、filter、union寬依賴是指父 RDD 的每個分區可能被子 RDD 的多個分區使用典型操作有 groupByKey、reduceByKey、join。窄依賴的算子不需要 shuffle可以在同一個 Stage 內完成寬依賴需要 shuffle是 Stage 劃分的邊界。為什么這個知識點如此重要因為數據傾斜通常就發生在寬依賴的算子上。比如用 groupByKey 做 WordCount某個單詞出現次數特別多對應的 Reduce 任務就會長時間運行甚至 OOM。解決方案主要是加隨機前綴進行二次聚合、兩階段聚合、調整并行度、開啟spark.sql.adaptive.enabled讓 Spark 自動做傾斜 join 優化。筆試題如果出“Spark 任務運行緩慢你怎么排查”答題思路應該是先看 Spark UI識別出哪個 Stage 耗時最長再點進去看是某個 Task 卡住還是所有 Task 都慢如果是單個 Task 慢基本可以斷定是數據傾斜再用sample算子抽樣檢查 key 分布最后根據傾斜情況選擇加隨機前綴或者調并行度。3.4 Flink 和 Kafka如果考到會這么出題雖然 2019 年的時候 Flink 還沒有如今這么普及但愛奇藝的實時計算場景早就存在了所以這套題里出現 Flink 相關題目也不意外。Flink 常見的考點是事件時間與處理時間的區別、Watermark 的作用、狀態后端、Checkpoint 機制。Kafka 的考點相對更基礎分區與副本機制、ISR 與 ACK 參數acks0/1/all、消費者組與分區分配策略、消息不丟失的保證。有一個很經典的連環題“Kafka 如何保證消息不丟失”答題要從生產者、Broker、消費者三個層面分別說明生產者設置acksall并開啟重試Broker 設置min.insync.replicas2消費者處理完成之后再提交 offset。能分三層答基本能拿滿分。3.5 數倉分層與建模類簡答題大數據開發筆試里最常見的一類簡答題是談談你們數倉是怎么分層的各層的作用是什么一般回答是 ODS、DWD、DWS、ADS 四層模型。ODS 層是源數據直接落地保持與業務庫一致不做任何加工DWD 層做清洗、規范化、維度退化統一命名規范DWS 層按主題匯總比如按用戶、商品、流量主題加工成寬表ADS 層是面向報表和應用的數據直接對接業務方。這道題考察的不只是概念還有你對業務的理解。能結合視頻平臺舉出具體例子最好比如“播放記錄表屬于 ODS 層清洗后的播放明細表在 DWD 層按用戶維度匯總的觀看統計表在 DWS 層最終每日報表在 ADS 層”。筆試的時候如果能寫出這種層級加例子而不是只背四層定義是一個不小的加分項。4. Linux與SQL筆試中的“隱形大戶”4.1 Linux 命令題總是被低估很多同學備戰大數據筆試時會把精力放在算法題和框架原理上對 Linux 命令不屑一顧覺得“反正工作之后再學也不遲”。但大數據開發這個崗位日常工作的主戰場就是 Linux 服務器你不會用top、free、df、ps連排查問題都無從下手。所以筆試里出 Linux 題是非常合理的而且考察的點往往貼合實際場景。常見的出題方式不是問“ls命令的-l參數是什么意思”而是給你一個實戰場景服務器 CPU 飆升你怎么找出是哪個進程干的標準答案是先用top查看進程 CPU 占用率再用top -Hp [pid]查看具體線程配合jstack導出線程快照找到出問題的代碼位置。另一個高頻場景磁盤空間不足怎么快速找到大文件df -h看整體使用率du -sh *層層排查目錄再用find / -type f -size 1G直接列出大于 1GB 的文件。這些命令在大數據運維里天天都要用筆試考它們就是考察日常積累。4.2 grep、awk、sed 三件套的實戰用法文本處理三件套是 Linux 命令題的重頭戲。比如日志文件access.log的每一行是“IP 地址 訪問時間 請求路徑 狀態碼”問你如何統計訪問次數最多的前 10 個 IP。awk {print $1} access.log | sort | uniq -c | sort -rn | head -10這條命令的每一步都值得拆開講awk {print $1}是取第一列sort是排序讓相同的 IP 排在一起uniq -c統計去重后每項的出現次數sort -rn按數字逆序排序head -10取前十條。還有一類常考題是 sed 的原地替換把文件里所有http替換成https并且修改原文件。sed -i s#http://#https://#g config.txt這里沒用常見的/作為分隔符而是用了#主要原因是 URL 里本身包含/直接用/做分隔符需要轉義寫成#可以少踩很多坑。這種細節就是筆試選擇題里的加分點。4.3 SQL 窗口函數分組 TopN 是最高頻考點大數據開發筆試的 SQL 題基本繞不開窗口函數。它的典型場景是求每個部門工資最高的員工、求每個用戶最近一筆訂單、求連續登錄 N 天的用戶。窗口函數的核心語法就一條row_number() over (partition by 分組字段 order by 排序字段 desc) as rk以“求每個用戶的最近 3 筆訂單”為例select user_id, order_id, order_time from ( select user_id, order_id, order_time, row_number() over(partition by user_id order by order_time desc) as rk from orders ) t where rk 3;這里特別需要提醒一個新手常犯的錯誤子查詢里的rk字段不能在同一個查詢的 where 條件里直接引用比如where row_number() over(...) 3會直接報錯因為窗口函數是最后執行的。必須包一層子查詢在外面過濾。這個坑在筆試里出現頻率特別高因為它考察的是執行順序的理解而不是語法背誦。4.4 連續登錄問題的兩種解法“求連續登錄 3 天以上的用戶”是另一道高頻 SQL 題它有很多變形比如連續簽到、連續購買。核心解法是用date_sub做日期差值。select user_id from ( select user_id, login_date, row_number() over(partition by user_id order by login_date) as rn from user_login group by user_id, login_date ) t group by user_id, date_sub(login_date, rn) having count(1) 3;思路是這樣的先把同一個用戶每天的連續登錄日期減去行號如果日期是連續的那么差值會保持不變如果中間斷了差值就會變。所以group by user_id, 差值之后count 大于等于 3 的組就是連續登錄至少 3 天的用戶。這里有個細節login_date可能同一天有多條記錄比如用戶一天登錄了兩次直接算行號會把同一天的重復記錄也算進去導致誤判。所以要先group by user_id, login_date去重再做窗口計算。這個去重的步驟是很多參考答案里沒寫出來的但實際筆試時很容易中招。5. 編程題是拉分項從 TopN 到滑動窗口的破題路徑5.1 編程題到底在考什么筆試的編程題不會讓你寫一個完整的 MapReduce也不會讓你手寫 Spark 算子。它的核心考察點還是數據結構和算法只是偶爾會套一層“大數據場景”的外衣。愛奇藝這套題的編程部分基本集中在數組、字符串、鏈表、堆、滑動窗口這些經典題型上。刷題的時候不要盲目追求題量先把每一類題型的套路吃透。比如“連續子數組最大和”是動態規劃基礎題“兩數之和”是哈希表的典型應用“TopK”是堆的經典場景“最長無重復子串”是滑動窗口的標準模板。這四類題掌握之后筆試遇到新題至少不會完全懵。5.2 海量日志 TopK堆是最優解結合大數據場景的編程題最常見的是“在一個很大的文件里找出出現次數最多的 TopK 個單詞”。純算法題版的問法是“求一個無序數組里的前 K 大元素”。public int[] topK(int[] nums, int k) { PriorityQueueInteger heap new PriorityQueue(k); for (int num : nums) { if (heap.size() k) { heap.offer(num); } else if (num heap.peek()) { heap.poll(); heap.offer(num); } } int[] res new int[k]; for (int i 0; i k; i) { res[i] heap.poll(); } return res; }這里用了一個大小固定為 K 的最小堆遍歷數組時只要當前元素比堆頂大就替換堆頂這樣堆里始終維護著當前最大的 K 個數時間復雜度 O(n log k)。面試如果追問“數據量特別大怎么辦”可以補充說明文件過大無法一次性加載到內存時先做哈希分片把大文件拆成多個小文件分別統計每個小文件的 TopK最后再歸并。這道題還有一個高頻變種求第 K 大的元素。用快速選擇算法平均時間復雜度 O(n)代碼思路是在快排的 partition 基礎上只遞歸處理包含第 K 大的一側不做全量排序。如果筆試時間充裕寫快選比寫一堆更優雅。5.3 連續子數組最大和動態規劃入門模板“最大子數組和”是 LeetCode 第 53 題也是筆試編程題里出現頻率很高的一道因為它短小精悍能快速看出候選人的動態規劃基本功。public int maxSubArray(int[] nums) { int cur nums[0]; int max nums[0]; for (int i 1; i nums.length; i) { cur Math.max(nums[i], cur nums[i]); max Math.max(max, cur); } return max; }核心邏輯就一行cur Math.max(nums[i], cur nums[i])。翻譯成人話就是“當前最大子序列和”要么從當前元素重新開始要么帶著前面的累加值繼續加取兩者較大值。cur維護的是以當前元素結尾的子數組最大和max維護的是全局最大和。這道題寫出來很容易但想要在筆試里拿滿分還需要在注釋或者旁邊寫明“時間 O(n)空間 O(1)”這能體現你的算法復雜度意識。5.4 輸入輸出格式筆試翻車的高發區域代碼寫對了但是 0 分這類悲劇每年都在發生。原因絕大多數不是算法問題而是輸入輸出格式沒處理好。牛客網這類平臺和 LeetCode 不同LeetCode 已經幫你把函數簽名定義好了你只需要填函數體牛客網需要你寫完整的public class Main自己用Scanner讀取輸入再按指定格式輸出。很多同學平時只刷 LeetCode不熟悉這種“自己處理輸入輸出”的方式筆試時一緊張Scanner 的循環讀法都寫錯了。我建議在秋招開始前去牛客網上把近三年的真題模擬題都做幾道專門練習完整的代碼結構。記住一個通用模板import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); int n sc.nextInt(); int[] arr new int[n]; for (int i 0; i n; i) { arr[i] sc.nextInt(); } // 處理邏輯 System.out.println(result); } }還有一個容易被忽略的點有些題目要求輸出結果保留兩位小數比如System.out.printf(%.2f, result)有些要求多個結果之間用空格分隔最后一個后面不能有空格。這些細節在筆試環境里一旦出錯會直接判定答案錯誤比算法沒寫出來還可惜。6. 從這套筆試反推秋招備戰我的幾點實踐復盤6.1 原理與刷題的時間配比我見過太多人備戰大數據開發筆試要么只刷算法題要么只看框架面經這倆都是極端。愛奇藝這套題給我的最大啟發是它同時考察原理深度和代碼熟練度兩邊的權重其實差不多。比較合理的安排是五五開一半時間用來深入理解 Hadoop、Spark、Kafka 的核心機制另一半時間用來刷算法題和 SQL 題。原理部分不要停留在“會用”層面要能用自己的話講清楚 MapReduce 的 Shuffle 過程、Spark 寬窄依賴、Kafka 的 ISR 機制。SQL 部分不要只看題解一定要親手在本地或者在線環境跑一遍。我自己復習時有一個笨但有效的方法把每個核心知識點抄在一張 A4 紙上只寫關鍵詞和流程箭頭不看資料對著這張紙口述講一遍。講不出來的地方就是知識盲區回頭再去看那塊的源碼或博客。這個方法堅持兩周效果比反復讀書好得多。6.2 筆試現場的答題順序與時間切分真正坐在筆試考場里心態和平時刷題完全不一樣。我總結了一套當時用著很順的答題順序先花一分鐘掃一遍全部題標記出編程題的大致難度然后按順序做選擇題遇到卡殼的直接跳過選擇題做完后先做會寫的編程題再做簡答題最后回頭處理跳過的選擇題和自己不熟悉的編程題。時間切分上我一般會把整個筆試時間的 50% 留給編程題30% 留給選擇填空20% 留給簡答。因為編程題是按通過用例給分的寫出來大部分用例可能就能拿到 60% 到 80% 的分數這比在選擇題上糾結半天的性價比高得多。6.3 復盤比刷題更重要做完一套題對照答案估分只是第一步更重要的是把錯題涉及的每一個知識點都深挖一遍。我會為每道錯題建立一個類似“問題是什么、涉及的知識點、根本原因、同類題型的解題模板”的卡片然后每周集中回顧一次。比如我在做 HashMap 相關題時錯過一次“JDK 7 頭插法和 JDK 8 尾插法的原因”這個點復盤的時候我就專門去看 JDK 8 的源碼把putVal方法整個讀了一遍又畫了擴容前后鏈表結構的示意圖。從那以后凡是遇到 HashMap 并發問題我基本不會再丟分。這種“以題帶點、以點帶面”的復盤方式比再刷十套新題更有效果。6.4 最后分享一點心態上的體會準備秋招筆試的過程確實枯燥尤其是當你發現同一道題做了三遍還是會錯的時候很容易自我懷疑。但大數據開發這個方向本來考查的就是知識廣度和深度并重一時半會兒記不全太正常了。我自己的體會是把每一次筆試都當成一次免費的學習機會題沒做完不要緊關鍵是從中提煉出哪些知識點還沒掌握、哪些代碼模板還不夠熟練下一次進場多拿幾分就足夠了。