大資料工程師面試題—4
2.23. 我們開發job時,是否可以去掉reduce階段。
可以。設定reduce數為0 即可。
2.24. datanode在什麼情況下不會備份
datanode在強制關閉或者非正常斷電不會備份。
2.25. combiner出現在那個過程
出現在map階段的map方法後等。
2.26. hdfs的體系結構
hdfs有namenode、secondraynamenode、datanode組成。
為n+1模式
namenode負責管理datanode和記錄元資料
secondraynamenode負責合併日誌
datanode負責儲存資料
2.27. 3個datanode中有一個datanode出現錯誤會怎樣?
這個datanode的資料會在其他的datanode上重新做備份。
2.28. 描述一下hadoop中,有哪些地方使用了快取機制,作用分別是什麼?
在mapreduce提交job的獲取id之後,會將所有檔案儲存到分散式快取上,這樣檔案可以被所有的mapreduce共享。
2.29. 如何確定hadoop叢集的健康狀態
通過頁面監控,指令碼監控。
2.30.生產環境中為什麼建議使用外部表?
1、因為外部表不會載入資料到hive,減少資料傳輸、資料還能共享。
2、hive不會修改資料,所以無需擔心資料的損壞
3、刪除表時,只刪除表結構、不刪除資料。
3.15期新增
3.1.新增
1)hadoop的核心配置檔名稱是什麼?
core-site.xml
2)“jps”命令的用處?
jps位於jdk的bin目錄下,其作用是顯示當前系統的java程序情況,及其id號。 jps相當於Solaris程序工具ps。不象”pgrep java”
或”ps -ef grep java”,jps並不使用應用程式名來查詢JVM例項。因此,它查詢所有的Java應用程式,包括即使沒有使用java執行
體的那種(例如,定製的啟動 器)。另外,jps僅查詢當前使用者的Java程序,而不是當前系統中的所有程序。
3)如何檢查namenode是否正常執行?重啟namenode的命令是什麼?
通過節點資訊和瀏覽器檢視,通過指令碼監控
hadoop-daemon.sh start namenode
hdfs-daemon.sh start namenode
4)避免namenode故障導致叢集宕機的解決方法是什麼?
自己書寫指令碼監控重啟
5)hbase資料庫對行鍵的設計要求是什麼?
行健以字典序排列,設計時充分利用這個特點,將經常一起查詢的行健設計在一起,例如時間戳結尾,使用者名稱開頭(位置相關性)
6)請給出你的設計方案,比如使用哪些技術框架,該框架起到的作用等。
1、用hive分析業務資料即可
2、將資料匯入到hive中
sql的設計思路:多表關聯
1、找到所有在2015-01-01到2015-01-31時間內訪問A頁面的使用者
2、在這些使用者中刪選在2015-01-01到2015-03-31下單的使用者
3、統計總數
3.2. 你們資料庫怎麼匯入hive 的,有沒有出現問題
在匯入hive的時候,如果資料庫中有blob或者text欄位,會報錯,解決方案在sqoop筆記中
在將資料由Oracle資料庫匯入到Hive時,發現帶有clob欄位的表的資料會錯亂,出現一些欄位全為NULL的空行。
由於在專案中CLOB欄位沒有實際的分析用途,因此考慮將CLOB欄位去掉。
同時,為了防止CLOB欄位產生一些問題,因此將HIVE中CLOB欄位禁用,禁用的方式如下:
[[email protected] sqoop-1.4.5]$ cd $SQOOP_HOME/conf
[[email protected] conf]$ vi oraoop-site.xml
將以下屬性的註釋去掉,並且將value改為true
<property>
<name>oraoop.import.omit.lobs.and.long</name>
<value>true</value>
<description>If true, OraOop will omit BLOB, CLOB, NCLOB and LONG columns during an Import.
</description>
</property>
有些表中雖然有clob欄位,但是不能排除掉,因為其他欄位使我們所需要,因此在匯入的時候採用指定--columns的方式來進行匯入
sqoop import --hive-import --hive-database test --create-hive-table --connect jdbc --username user--password user
--bindir //scratch --outdir /Java --table aaa --columns "ID,NAME" -m 1 --null-string '\\N' --null-non-string '\\N'
3.3. 公司技術選型可能利用storm 進行實時計算,講解一下storm
描述下storm的設計模式,是基於work、excutor、task的方式執行程式碼,由spout、bolt組成等等
3.4. 一個datanode 宕機,怎麼一個流程恢復
將datanode資料刪除,重新當成新節點加入即可。
3.5. Hbase 的特性,以及你怎麼去設計 rowkey 和 columnFamily ,怎麼去建一個table
hbase是列式資料庫,rowkey是字典序的,設計時的規則同上。
每個列族是一個檔案,將經常一起查詢的列放到同一個列族中,減少檔案的定址時間。
3.6. Redis,傳統資料庫,hbase,hive 每個之間的區別
redis:分散式快取,強調快取,記憶體中資料
傳統資料庫:注重關係
hbase:列式資料庫,無法做關係資料庫的主外來鍵,用於儲存海量資料,底層基於hdfs
hive:資料倉庫工具,底層是mapreduce。不是資料庫,不能用來做使用者的互動儲存
3.7. shuffle 階段,你怎麼理解的
shuffle過程包括在Map和Reduce兩端中。
在Map端的shuffle過程是對Map的結果進行分割槽(partition)、排序(sort)和分割(spill),然後將屬於同一個劃分的輸出合併在一起
(merge)並寫在硬碟上,同時按照不同的劃分將結果傳送給對應的Reduce(Map輸出的劃分與Reduce的對應關係由JobTracker確定)。
Reduce端又會將各個Map送來的屬於同一個劃分的輸出進行合併(merge),然後對merge的結果進行排序,最後交給Reduce處理。通俗的講,
就是對Map輸出結果先進行分割槽(partition),如“aaa”經過Partitioner後返回0,也就是這對值應當交由第一個reducer來處理。接下來,
需要將資料寫入記憶體緩衝區中,緩衝區的作用是批量收集map結果,減少磁碟IO的影響。我們的key/value對以及Partition的結果都會被寫
入緩衝區。當然寫入之前,key與value值都會被序列化成位元組陣列。這個記憶體緩衝區是有大小限制的,預設是100MB。當map task的輸出結果
很多時,需要在一定條件下將緩衝區中的資料臨時寫入磁碟,然後重新利用這塊緩衝區。這個從記憶體往磁碟寫資料的過程被稱為Spill。
Spill可以認為是一個包括Sort和Combiner(Combiner是可選的,使用者如果定義就有)的過程。先進行sort可以把緩衝區中一段範圍key的數
據排在一起,(如果資料多的時候,多次重新整理往記憶體緩衝區中寫入的資料可能會有屬於相同範圍的key,也就是說,多個spill檔案中可能會
有統一範圍的key,這就是需要下面Map端merge的原因),這裡有點繞,具體的介紹可以看下面的詳細過程,執行過sort之後,如果使用者定義
了combiner就會執行combine,然後執行merge操作,接著就是Reduce端。
3.8. Mapreduce 的 map 數量 和 reduce 數量 怎麼確定 ,怎麼配置
map的數量由資料塊決定,reduce數量隨便配置。
3.9. 唯一難住我的是他說實時計算,storm 如果碰上了複雜邏輯,需要算很長的時間,你怎麼去優化,怎麼保證實時性
3.10. Hive 你們用的是外部表還是內部表,有沒有寫過UDF,hive 的版本
3.11. Hadoop 的版本
1.04、1.20都為穩定版,是兩個常用的hadoop1版本。
3.12. 實時流式計算 的結果內容有哪些,你們需要統計出來麼
3.13.
1)設計日誌收集分析系統
日誌分佈在各個業務系統中,我們需要對當天的日誌進行實時彙總統計,同時又能按天查詢歷史的彙總資料(可以圍繞PV、UV、IP等
指標進行闡述)
1、通過flume將不同系統的日誌收集到kafka中
2、通過storm實時的處理PV、UV、IP
3、通過kafka的consumer將日誌生產到hbase中。
4、通過離線的mapreduce或者hive,處理hbase中的資料
2)如果你來做技術分享,你會選擇什麼主題,課程安排是什麼樣的?
大體分為3個部分:
1、離線hadoop技術分享(mapreduce、hive)
2、nosql資料庫hbase分享
3、實時流計算分享
5)Hive語句實現WordCount。
假設資料存放在hadoop下,路徑為:/home/hadoop/worddata裡面全是一些單詞
1、建表
2、分組(group by)統計wordcount
select word,count(1) from table1 group by word;
6)給定a、b兩個檔案,各存放50億個url,每個url各佔64位元組,記憶體限制是4G,找出a、b檔案共同的url?
可以估計每個檔案的大小為50億×64=298G,遠遠大於記憶體限制的4G。所以不可能將其完全載入到記憶體中處理。考慮採取分而治之的方法。
1、將檔案儲存到hdfs中,這樣每個檔案為64M或者是128M
2、分別對兩個檔案的url進行去重、排序輸出,這樣能排除a檔案中相同的url,b檔案也一樣
3、對a、b兩個檔案處理後的結果進行wordcount,並且在reduce中判斷單詞個數,個數為2的時候輸出,這樣就找到了a、b檔案中的相同url。
4、此計算步驟中的每一步載入到記憶體中的檔案大小都不會超過64M,遠遠小於4G。
7)一億個資料獲取前100個最大值(步驟及演算法複雜度)
兩種思路:
1. 根據快速排序劃分的思想
a. 假設陣列為 array[N] (N = 1 億),首先利用quicksort的原理把array分成兩個部分,左邊部分比 array[N - 1] (array中的最後一個值,
即pivot) 大, 右邊部分比pivot 小。然後,可以得到 array[array.length - 1] (即 pivot) 在整個陣列中的位置,假設是 k.
b. 如果 k 比 99 大,我們在陣列[0, k - 1]裡找前 100 最大值。 (繼續遞迴)
c. 如果 k 比 99 小, 我們在陣列[k + 1, ..., N ]裡找前 100 - (k + 1) 最大值。(繼續遞迴)
d. 如果 k == 99, 那麼陣列的前 100 個值一定是最大的。(退出)
2.先取出前100個數,維護一個100個數的最小堆,遍歷一遍剩餘的元素,在此過程中維護堆就可以了。具體步驟如下:
step1:取前m個元素(例如m=100),建立一個小頂堆。保持一個小頂堆得性質的步驟,執行時間為O(lgm);建立一個小頂堆執行時間為m*O(lgm)=O(m lgm);
step2:順序讀取後續元素,直到結束。每次讀取一個元素,如果該元素比堆頂元素小,直接丟棄
如果大於堆頂元素,則用該元素替換堆頂元素,然後保持最小堆性質。最壞情況是每次都需要替換掉堆頂的最小元素,因此需要維護堆的代價為(N-m)*O(lgm);
最後這個堆中的元素就是前最大的10W個。時間複雜度為O(N lgm)。
兩種思路比較:
基於最小堆方法執行時間很穩定(每次執行時間相差很小),基於quicksort原理的方法執行時間不穩定(每次執行時間相差大)。
Random rand = new Random(); PriorityQueue<Integer> P = new PriorityQueue<Integer>(); for(int i = 0,num = rand.nextInt(); (i < 100 && P.add(num)) || (i < 100000000 && (P.peek() < num && P.add(num) && P.remove() != null || 1==1));
i++,num = rand.nextInt()); //System.out.println(P);
top K問題
在大規模資料處理中,經常會遇到的一類問題:在海量資料中找出出現頻率最好的前k個數,或者從海量資料中找出最大的前k個數,這類問題通常被稱為top K問題。例如,在搜尋引擎中,
統計搜尋最熱門的10個查詢詞;在歌曲庫中統計下載最高的前10首歌等。
針對top K類問題,通常比較好的方案是分治+Trie樹/hash+小頂堆(就是上面提到的最小堆),即先將資料集按照Hash方法分解成多個小資料集,
然後使用Trie樹活著Hash統計每個小資料集中的query詞頻,之後用小頂堆求出每個資料集中出現頻率最高的前K個數,最後在所有top K中求出最終的top K。
eg:有1億個浮點數,如果找出期中最大的10000個?
最容易想到的方法是將資料全部排序,然後在排序後的集合中進行查詢,最快的排序演算法的時間複雜度一般為O(nlogn),如快速排序。但是在32位的機器上,
每個float型別佔4個位元組,1億個浮點數就要佔用400MB的儲存空間,對於一些可用記憶體小於400M的計算機而言,很顯然是不能一次將全部資料讀入記憶體進行排序的。
其實即使記憶體能夠滿足要求(我機器記憶體都是8GB),該方法也並不高效,因為題目的目的是尋找出最大的10000個數即可,而排序卻是將所有的元素都排序了,做了很多的無用功。
第二種方法為區域性淘汰法,該方法與排序方法類似,用一個容器儲存前10000個數,然後將剩餘的所有數字——與容器內的最小數字相比,如果所有後續的元素都比容器內的10000個數還小,
那麼容器內這個10000個數就是最大10000個數。如果某一後續元素比容器內最小數字大,則刪掉容器內最小元素,並將該元素插入容器,最後遍歷完這1億個數,
得到的結果容器中儲存的數即為最終結果了。此時的時間複雜度為O(n+m^2),其中m為容器的大小,即10000。
第三種方法是分治法,將1億個資料分成100份,每份100萬個資料,找到每份資料中最大的10000個,最後在剩下的100*10000個數據裡面找出最大的10000個。如果100萬資料選擇足夠理想,
那麼可以過濾掉1億資料裡面99%的資料。100萬個資料裡面查詢最大的10000個數據的方法如下:用快速排序的方法,將資料分為2堆,如果大的那堆個數N大於10000個,
繼續對大堆快速排序一次分成2堆,如果大的那堆個數N大於10000個,繼續對大堆快速排序一次分成2堆,如果大堆個數N小於10000個,就在小的那堆裡面快速排序一次,找第10000-n大的數字;
遞迴以上過程,就可以找到第1w大的數。參考上面的找出第1w大數字,就可以類似的方法找到前10000大數字了。此種方法需要每次的記憶體空間為10^6*4=4MB,一共需要101次這樣的比較。
第四種方法是Hash法。如果這1億個書裡面有很多重複的數,先通過Hash法,把這1億個數字去重複,這樣如果重複率很高的話,會減少很大的記憶體用量,從而縮小運算空間,
然後通過分治法或最小堆法查詢最大的10000個數。
第五種方法採用最小堆。首先讀入前10000個數來建立大小為10000的最小堆,建堆的時間複雜度為O(mlogm)(m為陣列的大小即為10000),然後遍歷後續的數字,並於堆頂(最小)
數字進行比較。如果比最小的數小,則繼續讀取後續數字;如果比堆頂數字大,則替換堆頂元素並重新調整堆為最小堆。整個過程直至1億個數全部遍歷完為止。然後按照中序遍歷的方式輸出當前
堆中的所有10000個數字。該演算法的時間複雜度為O(nmlogm),空間複雜度是10000(常數)。
實際執行:
實際上,最優的解決方案應該是最符合實際設計需求的方案,在時間應用中,可能有足夠大的記憶體,那麼直接將資料扔到記憶體中一次性處理即可,也可能機器有多個核,這樣可以採用
多執行緒處理整個資料集。
下面針對不容的應用場景,分析了適合相應應用場景的解決方案。
(1)單機+單核+足夠大記憶體
如果需要查詢10億個查詢次(每個佔8B)中出現頻率最高的10個,考慮到每個查詢詞佔8B,則10億個查詢次所需的記憶體大約是10^9 * 8B=8GB記憶體。如果有這麼大記憶體,直接在記憶體中對
查詢次進行排序,順序遍歷找出10個出現頻率最大的即可。這種方法簡單快速,使用。然後,也可以先用HashMap求出每個詞出現的頻率,然後求出頻率最大的10個詞。
(2)單機+多核+足夠大記憶體
這時可以直接在記憶體總使用Hash方法將資料劃分成n個partition,每個partition交給一個執行緒處理,執行緒的處理邏輯同(1)類似,最後一個執行緒將結果歸併。
該方法存在一個瓶頸會明顯影響效率,即資料傾斜。每個執行緒的處理速度可能不同,快的執行緒需要等待慢的執行緒,最終的處理速度取決於慢的執行緒。而針對此問題,解決的方法是,
將資料劃分成c×n個partition(c>1),每個執行緒處理完當前partition後主動取下一個partition繼續處理,知道所有資料處理完畢,最後由一個執行緒進行歸併。
(3)單機+單核+受限記憶體
這種情況下,需要將原資料檔案切割成一個一個小檔案,如次啊用hash(x)%M,將原檔案中的資料切割成M小檔案,如果小檔案仍大於記憶體大小,繼續採用Hash的方法對資料檔案進行分割,
知道每個小檔案小於記憶體大小,這樣每個檔案可放到記憶體中處理。採用(1)的方法依次處理每個小檔案。
(4)多機+受限記憶體
這種情況,為了合理利用多臺機器的資源,可將資料分發到多臺機器上,每臺機器採用(3)中的策略解決本地的資料。可採用hash+socket方法進行資料分發。
從實際應用的角度考慮,(1)(2)(3)(4)方案並不可行,因為在大規模資料處理環境下,作業效率並不是首要考慮的問題,演算法的擴充套件性和容錯性才是首要考慮的。
演算法應該具有良好的擴充套件性,以便資料量進一步加大(隨著業務的發展,資料量加大是必然的)時,在不修改演算法框架的前提下,可達到近似的線性比;演算法應該具有容錯性,
即當前某個檔案處理失敗後,能自動將其交給另外一個執行緒繼續處理,而不是從頭開始處理。
top K問題很適合採用MapReduce框架解決,使用者只需編寫一個Map函式和兩個Reduce 函式,然後提交到Hadoop(採用Mapchain和Reducechain)上即可解決該問題。
具體而言,就是首先根據資料值或者把資料hash(MD5)後的值按照範圍劃分到不同的機器上,最好可以讓資料劃分後一次讀入記憶體,這樣不同的機器負責處理不同的數值範圍,
實際上就是Map。得到結果後,各個機器只需拿出各自出現次數最多的前N個數據,然後彙總,選出所有的資料中出現次數最多的前N個數據,這實際上就是Reduce過程。
對於Map函式,採用Hash演算法,將Hash值相同的資料交給同一個Reduce task;對於第一個Reduce函式,採用HashMap統計出每個詞出現的頻率,對於第二個Reduce 函式,統計所有Reduce task,
輸出資料中的top K即可。
直接將資料均分到不同的機器上進行處理是無法得到正確的結果的。因為一個數據可能被均分到不同的機器上,而另一個則可能完全聚集到一個機器上,同時還可能存在具有相同數目的資料。
以下是一些經常被提及的該類問題。
(1)有10000000個記錄,這些查詢串的重複度比較高,如果除去重複後,不超過3000000個。一個查詢串的重複度越高,說明查詢它的使用者越多,也就是越熱門。請統計最熱門的10個查詢串,
要求使用的記憶體不能超過1GB。
(2)有10個檔案,每個檔案1GB,每個檔案的每一行存放的都是使用者的query,每個檔案的query都可能重複。按照query的頻度排序。
(3)有一個1GB大小的檔案,裡面的每一行是一個詞,詞的大小不超過16個位元組,記憶體限制大小是1MB。返回頻數最高的100個詞。
(4)提取某日訪問網站次數最多的那個IP。
(5)10億個整數找出重複次數最多的100個整數。
(6)搜尋的輸入資訊是一個字串,統計300萬條輸入資訊中最熱門的前10條,每次輸入的一個字串為不超過255B,記憶體使用只有1GB。
(7)有1000萬個身份證號以及他們對應的資料,身份證號可能重複,找出出現次數最多的身份證號。
重複問題
在海量資料中查找出重複出現的元素或者去除重複出現的元素也是常考的問題。針對此類問題,一般可以通過點陣圖法實現。例如,已知某個檔案內包含一些電話號碼,每個號碼為8位數字,
統計不同號碼的個數。
本題最好的解決方法是通過使用點陣圖法來實現。8位整數可以表示的最大十進位制數值為99999999。如果每個數字對應於點陣圖中一個bit位,那麼儲存8位整數大約需要99MB。因為1B=8bit,
所以99Mbit摺合成記憶體為99/8=12.375MB的記憶體,即可以只用12.375MB的記憶體表示所有的8位數電話號碼的內容。
8)實時資料統計會用到哪些技術,它們各自的應用場景及區別是什麼?
flume:日誌收集系統,主要用於系統日誌的收集
kafka:訊息佇列,進行訊息的快取和系統的解耦
storm:實時計算框架,進行流式的計算。
1)String和StringBuffer的區別,StringBuffer與StringBuilder的區別
簡單地說,就是一個變數和常量的關係。StringBuffer物件的內容可以修改;而String物件一旦產生後就不可以被修改,重新賦值其實是兩個物件。
StringBuilder:執行緒非安全的
StringBuffer:執行緒安全的
當我們在字串緩衝去被多個執行緒使用是,JVM不能保證StringBuilder的操作是安全的,雖然他的速度最快,但是可以保證StringBuffer是可以正確操作的。
當然大多數情況下就是我們是在單執行緒下進行的操作,所以大多數情況下是建議用StringBuilder而不用StringBuffer的,就是速度的原因。