本公眾號(五分鐘學大資料)將推出大資料面試系列文章—五分鐘小面試,此系列文章將會深入研究各大廠筆面試真題,并根據筆面試題擴展相關的知識點,助力大家都能夠成功入職大廠!

大資料筆面試系列文章分為兩種型別:混合型(即一篇文章中會有多個框架的知識點—融會貫通);專項型(一篇文章針對某個框架進行深入決議—專項演練),
此篇文章為系列文章的第一篇(混合型)
第一題:大資料筆試題-Java相關(美菜網)
寫出下列程式的輸出:
class Father{
static {
System.out.println("Static Father");
}
{
System.out.println("Non-static Father");
}
public Father(){
System.out.println("Constructor Father");
}
}
public class Son extends Father{
static {
System.out.println("Static Son");
}
{
System.out.println("Non-static Son");
}
public Son(){
System.out.println("Constructor Son");
}
public static void main(String[] args) {
System.out.println("First Son");
new Son();
System.out.println("Second Son");
new Son();
}
}
運行結果:
Static Father
Static Son
First Son
Non-static Father
Constructor Father
Non-static Son
Constructor Son
Second Son
Non-static Father
Constructor Father
Non-static Son
Constructor Son
分析:
這道程式題考察的是Java中的靜態代碼塊、構造代碼塊、建構式的概念,
- 靜態代碼塊 static {}:
隨著類的加載而執行,即JVM加載類后就執行,而且只執行一次,執行優先級高于非靜態的初始化塊,它會在類初始化的時候執行一次,執行完成便銷毀,它僅能初始化類變數,即static修飾的資料成員,
- 非靜態代碼塊,也稱構造代碼塊 {}:
執行的時候如果有靜態代碼塊,先執行靜態代碼塊再執行非靜態代碼塊,在每個物件生成時都會被執行一次,它可以初始化類的實體變數,非靜態代碼塊會在建構式執行時,在建構式主體代碼執行之前被運行,
- 建構式:
物件一建立,就會呼叫與之相應的建構式,也就是說,不建立物件,建構式是不會運行的,
一個物件建立,建構式只運行一次,而一般方法可以被該物件呼叫多次,
再來看本題,程式運行,執行main()方法會先加載main()方法所在的類,加載 Son 類,但是 Son 類繼承自 Father 類,所以先加載父類,同時父類的靜態代碼塊執行,然后加載 Son 類本身,Son 類自己的靜態代碼塊開始執行,類加載完成之后執行main()方法內部的陳述句,列印 First Son,然后 new Son(),在創建物件時先構造父類的物件,因為靜態代碼塊只在類加載時執行一次,所以不再執行,然后執行父類的構造代碼塊,建構式,構造代碼塊的優先級大于建構式,然后在執行 Son 物件本身,完成之后列印 Second Son,接著又 new Son(),重復以上步驟,構造代碼塊和建構式在每次new的時候都會執行一次,
第二題:大資料面試題-JVM相關(豐巢科技)
問:解釋記憶體中的堆疊(stack)、堆(heap)和靜態存盤區的用法?
答:通常我們定義一個基本資料型別的變數,一個物件的參考,還有就是函式呼叫的現場保存都使用記憶體中的堆疊空間;而通過new關鍵字和構造器創建的對象放在堆空間;程式中的字面量(literal)如直接書寫的100、“hello”和常量都是放在靜態存盤區中,堆疊空間操作最快但是也很小,通常大量的物件都是放在堆空間,整個記憶體包括硬碟上的虛擬記憶體都可以被當成堆空間來使用,
String str = new String(“hello”);
上面的陳述句中str放在堆疊上,用new創建出來的字串物件放在堆上,而“hello”這個字面量放在靜態存盤區,
補充:較新版本的Java中使用了一項叫“逃逸分析“的技術,可以將一些區域物件放在堆疊上以提升物件的操作性能,(在 Java SE 6u23+ 開始支持,并默認設定為啟用狀態,可以不用額外加這個引數,)
第三題:大資料面試題-海量資料相關(騰訊)
問:給 40 億個不重復的 unsigned int 的整數,沒排過序的,然后再給一個數,如何快速判斷這個數是否在那 40 億個數當中?
答:方案 1:申請 512M 的記憶體,512M是42億多 bit,一個 bit 位代表一個 unsigned int 值,讀入 40 億個數,設定相應的 bit 位,讀入要查詢的數,查看相應 bit 位是否為 1,為 1 表示存在,為 0 表示不存在,
方案 2:這個問題在《編程珠璣》里有很好的描述,大家可以參考下面的思路,探討一下: 因為 2^32 為 42 億多,所以給定一個數可能在,也可能不在其中; 這里我們把 40 億個數中的每一個用 32 位的二進制來表示 ,假設這 40 億個數開始放在一個檔案中, 然后將這 40 億個數分成兩類:
- 最高位為 0
- 最高位為 1
并將這兩類分別寫入到兩個檔案中,其中一個檔案中數的個數<=20 億,而另一個>=20 億(相當于折半); 與要查找的數的最高位比較并接著進入相應的檔案再查找
然后再把這個檔案為又分成兩類:
- 次最高位為 0
- 次最高位為 1
并將這兩類分別寫入到兩個檔案中,其中一個檔案中數的個數<=10 億,而另一個>=10 億(相當于折半); 與要查找的數的次最高位比較并接著進入相應的檔案再查找,
…
以此類推,就可以找到了,而且時間復雜度為 O(logn),
第四題:大資料面試題-Hadoop相關(阿里)
問:MapReduce 中排序發生在哪幾個階段?這些排序是否可以避免?為什么?
答:
-
一個 MapReduce 作業由 Map 階段和 Reduce 階段兩部分組成,這兩階段會對資料排序,從這個意義上說,MapReduce 框架本質就是一個 Distributed Sort,
-
在 Map 階段,Map Task 會在本地磁盤輸出一個按照 key 排序(采用的是快速排序)的檔案(中間可能產生多個檔案,但最侄訓合并成一個),在 Reduce 階段,每個 Reduce Task 會對收到的資料排序(采用的是歸并排序),這樣,資料便按照 Key 分成了若干組,之后以組為單位交給 reduce 處理,
-
很多人的誤解在 Map 階段,如果不使用 Combiner 便不會排序,這是錯誤的,不管你用不用 Combiner,Map Task 均會對產生的資料排序(如果沒有 Reduce Task,則不會排序,實際上 Map 階段的排序就是為了減輕 Reduce端排序負載),
-
由于這些排序是 MapReduce 自動完成的,用戶無法控制,因此,在hadoop 1.x 中無法避免,也不可以關閉,但 hadoop2.x 是可以關閉的,
第五題:大資料面試題-Kafka相關(商湯科技)
問:kafka資料磁區和消費者的關系,kafka的資料offset讀取流程,kafka內部如何保證順序
答:
-
kafka資料磁區和消費者的關系:1個partition只能被同組的?一個consumer消費,同組的consumer則起到均衡效果
-
kafka的資料offset讀取流程:
- 連接ZK集群,從ZK中拿到對應topic的partition資訊和partition的Leader的相關資訊
- 連接到對應Leader對應的broker
- consumer將?自?己保存的offset發送給Leader
- Leader根據offset等資訊定位到segment(索引?檔案和?日志?檔案)
- 根據索引?檔案中的內容,定位到?日志?檔案中該偏移量量對應的開始位置讀取相應?長度的資料并回傳給consumer
-
kafka內部如何保證順序:kafka只能保證partition內是有序的,但是partition間的有序是沒辦法的,愛奇藝的搜索架構,是從業務上把需要有序的打到同一個partition,
第六題:大資料面試題-分布式相關(阿里)
問:說說三種分布式鎖?
答:
- 基于資料庫實作分布式鎖:(性能較差,鎖表的風險,非阻塞,失敗需要輪詢耗CPU)
- 悲觀鎖
利用select … where … for update 排他鎖
注意: 其他附加功能與實作基本一致,這里需要注意的是“where name=lock ”,name欄位必須要走索引,否則會鎖表,有些情況下,比如表不大,mysql優化器會不走這個索引,導致鎖表問題,
- 樂觀鎖
所謂樂觀鎖與悲觀鎖最大區別在于基于CAS思想,是不具有互斥性,不會產生鎖等待而消耗資源,操作程序中認為不存在并發沖突,只有update version失敗后才能覺察到,我們的搶購、秒殺就是用了這種實作以防止超賣,
樂觀鎖是通過增加遞增的版本號欄位實作的,
- 基于快取(Redis等)實作分布式鎖:(過期時間不好控制,非阻塞,失敗需要輪詢耗CPU)
-
獲取鎖的時候,使用setnx加鎖,并使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷,
-
獲取鎖的時候還設定一個獲取的超時時間,若超過這個時間則放棄獲取鎖,
-
釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放,
- 基于Zookeeper實作分布式鎖:(高可用、可重入、阻塞鎖)
大致思想:每個客戶端對某個功能加鎖時,在zookeeper上的與該功能對應的指定節點的目錄下,?生成?個唯一的瞬時有序節點,判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個,當釋放鎖的時候,只需將這個瞬時節點洗掉即可,同時,其可以避免服務宕機導致的鎖無法釋放,?而產生的死鎖問題,
-
優點:鎖安全性高,zk可持久化,且能實時監聽獲取鎖的客戶端狀態,一旦客戶端宕機,則瞬時節點隨之消失,zk因?而能第一時間釋放鎖,這也省去了用分布式快取實作鎖的程序中需要加入超時時間判斷的這一邏輯,
-
缺點:性能開銷?比較高,因為其需要動態產生、銷毀瞬時節點來實作鎖功能,所以不太適合直接提供給高并發的場景使用,
-
實作:可以直接采用zookeeper第三方庫curator即可方便地實作分布式鎖,
-
適用場景:對可靠性要求非常高,且并發程度不高的場景下使用,如核心資料的定時全量/增量同步等,
第七題:大資料面試題-Hadoop、Spark相關(京東金融)
問:Hadoop 和 Spark 的相同點和不同點?
答:
Hadoop底層使用MapReduce計算架構,只有map和reduce兩種操作,表達能力比較欠缺,而且在MR程序中會重復的讀寫hdfs,造成大量的磁盤io讀寫操作,所以適合高時延環境下批處理計算的應用;
Spark是基于記憶體的分布式計算架構,提供更加豐富的資料集操作型別,主要分成轉化操作和行動操作,包括map、reduce、filter、flatmap、groupbykey、reducebykey、union和join等,資料分析更加快速,所以適合低時延環境下計算的應用;
spark與hadoop最大的區別在于迭代式計算模型,基于mapreduce框架的Hadoop主要分為map和reduce兩個階段,兩個階段完了就結束了,所以在一個job里面能做的處理很有限;spark計算模型是基于記憶體的迭代式計算模型,可以分為n個階段,根據用戶撰寫的RDD算子和程式,在處理完一個階段后可以繼續往下處理很多個階段,而不只是兩個階段,所以spark相較于mapreduce,計算模型更加靈活,可以提供更強大的功能,
但是spark也有劣勢,由于spark基于記憶體進行計算,雖然開發容易,但是真正面對大資料的時候,在沒有進行調優的情況下,可能會出現各種各樣的問題,比如OOM記憶體溢位等情況,導致spark程式可能無法運行起來,而mapreduce雖然運行緩慢,但是至少可以慢慢運行完,
第八題:大資料面試題-Yarn相關(特斯拉)
問:一個應用程式是如何在 Yarn 集群上執行的?
答:
當 jobclient 向YARN提交一個應用程式后,YARN將分兩個階段運行這個應用程式:一是啟動ApplicationMaster;第二個階段是由ApplicationMaster創建應用程式,為它申請資源,監控運行直到結束,
具體步驟如下:
-
用戶向YARN提交一個應用程式,并指定ApplicationMaster程式、啟動ApplicationMaster的命令、用戶程式,
-
RM為這個應用程式分配第一個Container,并與之對應的NM通訊,要求它在這個Container中啟動應用程式ApplicationMaster,
-
ApplicationMaster向RM注冊,然后拆分為內部各個子任務,為各個內部任務申請資源,并監控這些任務的運行,直到結束,
-
AM采用輪詢的方式向RM申請和領取資源,
-
RM為AM分配資源,以Container形式回傳,
-
AM申請到資源后,便與之對應的NM通訊,要求NM啟動任務,
-
NodeManager為任務設定好運行環境,將任務啟動命令寫到一個腳本中,并通過運行這個腳本啟動任務,
-
各個任務向AM匯報自己的狀態和進度,以便當任務失敗時可以重啟任務,
-
應用程式完成后,ApplicationMaster向ResourceManager注銷并關閉自己,
第九題:大資料面試題-資料質量相關(螞蟻金服)
問:資料質量怎么監控?
答:
如一張表的記錄數在一個已知的范圍內,或者上下浮動不會超過某個閾值:
-
SQL結果:var 資料量 = select count(*)from 表 where 時間等過濾條件
-
報警觸發條件設定:如果資料量不在[數值下限, 數值上限], 則觸發報警
-
同比增加:如果((本周的資料量 -上周的資料量)/上周的資料量*100)不在 [比例下線,比例上限],則觸發報警
-
環比增加:如果((今天的資料量 - 昨天的資料量)/昨天的資料量*100)不在 [比例下線,比例上限],則觸發報警
-
報警觸發條件設定一定要有,如果沒有配置的閾值,不能做監控
榷訓、周活、月活、留存(日周月)、轉化率(日、周、月)GMV(日、周、月)
復購率(日周月)
單表空值檢測
某個欄位為空的記錄數在一個范圍內,或者占總量的百分比在某個閾值范圍內
-
目標欄位:選擇要監控的欄位,不能選“無”
-
SQL結果:var 例外資料量 = select count(*) from 表 where 目標欄位 is null
-
單次檢測:如果(例外資料量)不在[數值下限, 數值上限],則觸發報警
單表重復值檢測
一個或多個欄位是否滿足某些規則
-
目標欄位:第一步先正常統計條數;select count(*) form 表;
-
第二步,去重統計;select count(*) from 表 group by 某個欄位
-
第一步的值和第二步的值做減法,看是否在上下線閥值之內
-
單次檢測:如果(例外資料量)不在[數值下限, 數值上限], 則觸發報警
跨表資料量對比
主要針對同步流程,監控兩張表的資料量是否一致
-
SQL結果:count(本表) - count(關聯表)
-
閾值配置與“空值檢測”相同
第十題:大資料面試題-海量資料相關(百度)
問:在海量日志資料中,提取出某日訪問百度次數最多的那個IP
答:這類問題都歸為求Top K的問題,解決方法都差不多,
將這一天訪問百度的日志的IP取出來,逐個寫入到一個大檔案中,注意到IP是32位的,最多有個2^32個IP,同樣可以采用映射的方法,比如模1000,把整個大檔案映射為1000個小檔案,再找出每個小文中出現頻率最大的IP(可以采用 HashMap 進行頻率統計,然后再找出頻率最大的幾個)及相應的頻率,然后再在這1000個最大的IP中找出那個頻率最大的IP,即為所求,
演算法思想:分而治之+Hash
-
IP地址最多有2^32=4G種取值情況,所以不能完全加載到記憶體中處理;
-
可以考慮采用分而治之的思想,按照IP地址的Hash(IP) % 1024值,把海量IP日志分別存盤到1024個
小檔案中,這樣每個小檔案最多包含4MB個IP地址; 這里解釋一下為什么用Hash(IP) % 1024值,如果不用,而直接分類的話,可能會出現這樣一種情況,就是有個IP在每個小檔案中都存在,而且這個IP并不一定在那個小檔案中是數量最多的,那么最終可能選擇的結果會有問題,所以這里用了Hash(IP)%1024值,這樣的話,通過計算IP的Hash值,相同IP肯定會放到一個檔案中,當然了不同的IP的Hash值也可能相同,就存在一個小檔案中, -
對于每一個小檔案,可以構建一個IP為key,出現的次數為value的HashMap,同時記錄當前出現次數最多的那個IP地址;
-
可以得到1024個小檔案中的出現次數最多的那個IP,再依據常規的排序演算法得出總體上出現次數最多的IP,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/262531.html
標籤:其他
上一篇:TDH中的Workflow
