大数据开发超高频面试题!大厂面试必看!包含Hadoop、zookeeper、Hive、flume、kafka、Hbase、flink、spark、数仓等
大數(shù)據(jù)開發(fā)面試題
包含Hadoop、zookeeper、Hive、flume、kafka、Hbase、flink、spark、數(shù)倉等高頻面試題。
數(shù)據(jù)來自原博主爬蟲獲取!
文章目錄
- 大數(shù)據(jù)開發(fā)面試題
- **Hadoop**
- **一、HDFS文件寫入和讀取過程**
- **HDFS寫數(shù)據(jù)流程**
- **HDFS讀數(shù)據(jù)流程**
- **HDFS寫數(shù)據(jù)流程**
- **HDFS讀數(shù)據(jù)流程**
- **二、MapReduce工作原理**
- **Zookeeper**
- **Zookeeper的選舉機(jī)制**
- **Hive**
- **Hive的內(nèi)部表和外部表的區(qū)別**
- **Flume**
- **Flume的source、channel、sink分別都有哪些**
- **Kafka**
- **Kafka是如何實(shí)現(xiàn)高吞吐的**
- **HBase**
- **HBase的rowkey設(shè)計原則**
- **Spark**
- **Spark數(shù)據(jù)傾斜問題+解決方案**
- **說下RDD的寬依賴和窄依賴**
- **Flink**
- **Flink的Exactly Once語義怎么保證**
- **數(shù)據(jù)倉庫**
- **數(shù)據(jù)倉庫分層(層級劃分),每層做什么**
- **Saprk Streaming和Flink的區(qū)別**
Hadoop
一、HDFS文件寫入和讀取過程
可靈活回答 :
1)HDFS讀寫原理(流程)
2)HDFS上傳下載流程
3)講講(介紹下)HDFS
4)HDFS存儲機(jī)制
回答這個問題之前,我們先來看下機(jī)架感知 機(jī)制,也就是HDFS上副本存儲結(jié)點(diǎn)的選擇。
Hadoop3.x副本結(jié)點(diǎn)選擇:
由上圖可知,第一個副本在Client所處的節(jié)點(diǎn)上。如果客戶端在集群外,隨機(jī)選一個。
第二個副本在另一個機(jī)架的隨機(jī)一個節(jié)點(diǎn)。
第三個副本在第二個副本所在機(jī)架的隨機(jī)節(jié)點(diǎn)。
關(guān)于HDFS讀寫流程,這里還是給出兩個版本,有助于理解
第一個版本:簡潔版
HDFS寫數(shù)據(jù)流程
1)客戶端通過Distributed FileSystem模塊向NameNode請求上傳文件,NameNode檢查目標(biāo)文件是否已存在,父目錄是否存在。
2)NameNode返回是否可以上傳。
3)客戶端請求第一個 block上傳到哪幾個datanode服務(wù)器上。
4)NameNode返回3個datanode節(jié)點(diǎn),分別為dn1、dn2、dn3。
5)客戶端通過FSDataOutputStream模塊請求dn1上傳數(shù)據(jù),dn1收到請求會繼續(xù)調(diào)用dn2,然后dn2調(diào)用dn3,將這個通信管道建立完成。
6)dn1、dn2、dn3逐級應(yīng)答客戶端。
7)客戶端開始往dn1上傳第一個block(先從磁盤讀取數(shù)據(jù)放到一個本地內(nèi)存緩存),以packet為單位,dn1收到一個packet就會傳給dn2,dn2傳給dn3;dn1每傳一個packet會放入一個應(yīng)答隊(duì)列等待應(yīng)答。
8)當(dāng)一個block傳輸完成之后,客戶端再次請求NameNode上傳第二個block的服務(wù)器。(重復(fù)執(zhí)行3-7步)。
HDFS讀數(shù)據(jù)流程
1)客戶端通過Distributed FileSystem向NameNode請求下載文件,NameNode通過查詢元數(shù)據(jù),找到文件塊所在的DataNode地址。
2)挑選一臺DataNode(就近原則,然后隨機(jī))服務(wù)器,請求讀取數(shù)據(jù)。
3)DataNode開始傳輸數(shù)據(jù)給客戶端(從磁盤里面讀取數(shù)據(jù)輸入流,以packet為單位來做校驗(yàn))。
4)客戶端以packet為單位接收,先在本地緩存,然后寫入目標(biāo)文件。
第二個版本:詳細(xì)版,有助于理解
HDFS寫數(shù)據(jù)流程
1)Client將FileA按128M分塊。分成兩塊,block1和Block2;
2)Client向nameNode發(fā)送寫數(shù)據(jù)請求,如圖藍(lán)色虛線①------>。
3)NameNode節(jié)點(diǎn),記錄block信息。并返回可用的DataNode,如粉色虛線②------->。
????Block1: host2,host1,host6
????Block2: host7,host3,host4
4)client向DataNode發(fā)送block1;發(fā)送過程是以流式寫入。
流式寫入過程:
(1)將64M的block1按64k的package劃分;
(2)然后將第一個package發(fā)送給host2;
(3)host2接收完后,將第一個package發(fā)送給host1,同時client向host2發(fā)送第二個package;
(4)host1接收完第一個package后,發(fā)送給host6,同時接收host2發(fā)來的第二個package。
(5)以此類推,如圖紅線實(shí)線所示,直到將block1發(fā)送完畢。
(6)host2,host1,host6向NameNode,host2向Client發(fā)送通知,說“消息發(fā)送完了”。如圖粉紅顏色實(shí)線所示。
(7)client收到host2發(fā)來的消息后,向namenode發(fā)送消息,說我寫完了。這樣就完成了。如圖黃色粗實(shí)線。
(8)發(fā)送完block1后,再向host7,host3,host4發(fā)送block2,如圖藍(lán)色實(shí)線所示。
(9)發(fā)送完block2后,host7,host3,host4向NameNode,host7向Client發(fā)送通知,如圖淺綠色實(shí)線所示。
(10)client向NameNode發(fā)送消息,說我寫完了,如圖黃色粗實(shí)線。。。這樣就完畢了。
HDFS讀數(shù)據(jù)流程
1)client向namenode發(fā)送讀請求。
2)namenode查看Metadata信息,返回fileA的block的位置。
????block1:host2,host1,host6
????block2:host7,host3,host4
3)block的位置是有先后順序的,先讀block1,再讀block2。而且block1去host2上讀取;然后block2,去host7上讀取。
二、MapReduce工作原理
可靈活回答:
1)MapReduce執(zhí)行流程
2)對MapReduce的理解
3)MapReduce過程
4)MapReduce的詳細(xì)過程
5)MapTask和ReduceTask工作機(jī)制
6)MapReduce中有沒有涉及到排序
1)準(zhǔn)備一個200M的文件,submit中對原始數(shù)據(jù)進(jìn)行切片;
2)客戶端向YARN提交信息,YARN開啟一個MrAppmaster,MrAppmaster讀取客戶端對應(yīng)的信息,主要是job.split,然后根據(jù)切片個數(shù)(這里2個)開啟對應(yīng)數(shù)量的MapTask(2個);
3)MapTask通過InputFormat去讀取數(shù)據(jù)(默認(rèn)按行讀取),K是偏移量,V是一行內(nèi)容,數(shù)據(jù)讀取后交給Mapper,然后根據(jù)用戶的業(yè)務(wù)需求對數(shù)據(jù)進(jìn)行處理;
4)數(shù)據(jù)處理之后輸出到環(huán)型緩沖區(qū)(默認(rèn)100M),環(huán)型緩沖區(qū)一邊是存數(shù)據(jù),一邊存的是索引(描述數(shù)據(jù)的元數(shù)據(jù))。環(huán)型緩沖區(qū)存儲數(shù)據(jù)到達(dá)80%后進(jìn)行反向溢寫,并對數(shù)據(jù)進(jìn)行分區(qū)、排序;
5)再對分區(qū)且區(qū)內(nèi)有序的文件進(jìn)行歸并排序 ,然后存儲到磁盤;
6)當(dāng)所有MapTask任務(wù)完成后,啟動相應(yīng)數(shù)量的ReduceTask,并告知ReduceTask處理數(shù)據(jù)范圍(數(shù)據(jù)分區(qū))。注意:不是必須等到所有MapTask結(jié)束后才開始,可以自行配置。
7)ReduceTask開啟后,ReduceTask主動從MapTask對應(yīng)的分區(qū)拉取數(shù)據(jù);
8)再對ReduceTask拉取過來的數(shù)據(jù)進(jìn)行一個全局合并排序;
9)順序讀取數(shù)據(jù),按key分,key相同的數(shù)據(jù)進(jìn)入同一個Reducer,一次讀取一組數(shù)據(jù);
10)Reducer處理完數(shù)據(jù),通過OutPutFormat往外寫數(shù)據(jù),形成對應(yīng)文件。
簡潔版:面試可手寫
Zookeeper
Zookeeper的選舉機(jī)制
可靈活回答:
1)Zookeeper的選舉策略
2)Zookeeper的選舉過程
3)Zookeeper的Leader選舉是如何實(shí)現(xiàn)的
1)半數(shù)機(jī)制:集群中半數(shù)以上機(jī)器存活,集群可用。所以Zookeeper適合安裝奇數(shù)臺服務(wù)器。
2)Zookeeper雖然在配置文件中并沒有指定Master和Slave。但是,Zookeeper工作時,是有一個節(jié)點(diǎn)為Leader,其他則為Follower,Leader是通過內(nèi)部的選舉機(jī)制臨時產(chǎn)生的。
3)選舉過程
假設(shè)有五臺服務(wù)器組成的Zookeeper集群,它們的id從1-5,同時它們都是最新啟動的,也就是沒有歷史數(shù)據(jù),在存放數(shù)據(jù)量這一點(diǎn)上,都是一樣的。假設(shè)這些服務(wù)器依序啟動,來看看會發(fā)生什么。
(1)服務(wù)器1啟動,發(fā)起一次選舉。服務(wù)器1投自己一票。此時服務(wù)器1票數(shù)一票,不夠半數(shù)以上(3票),選舉無法完成,服務(wù)器1狀態(tài)保持為LOOKING;
(2)服務(wù)器2啟動,再發(fā)起一次選舉。服務(wù)器1和2分別投自己一票并交換選票信息:此時服務(wù)器1發(fā)現(xiàn)服務(wù)器2的ID比自己目前投票推舉的(服務(wù)器1)大,更改選票為推舉服務(wù)器2。此時服務(wù)器1票數(shù)0票,服務(wù)器2票數(shù)2票,沒有半數(shù)以上結(jié)果,選舉無法完成,服務(wù)器1,2狀態(tài)保持LOOKING
(3)服務(wù)器3啟動,發(fā)起一次選舉。此時服務(wù)器1和2都會更改選票為服務(wù)器3。此次投票結(jié)果:服務(wù)器1為0票,服務(wù)器2為0票,服務(wù)器3為3票。此時服務(wù)器3的票數(shù)已經(jīng)超過半數(shù),服務(wù)器3當(dāng)選Leader。服務(wù)器1,2更改狀態(tài)為FOLLOWING,服務(wù)器3更改狀態(tài)為LEADING;
(4)服務(wù)器4啟動,發(fā)起一次選舉。此時服務(wù)器1,2,3已經(jīng)不是LOOKING狀態(tài),不會更改選票信息。交換選票信息結(jié)果:服務(wù)器3為3票,服務(wù)器4為1票。此時服務(wù)器4服從多數(shù),更改選票信息為服務(wù)器3,并更改狀態(tài)為FOLLOWING;
(5)服務(wù)器5啟動,同4一樣當(dāng)小弟。
Hive
Hive的內(nèi)部表和外部表的區(qū)別
內(nèi)部表 (managed table):未被external修飾
外部表 (external table):被external修飾
區(qū)別:
1)內(nèi)部表數(shù)據(jù)由Hive自身管理,外部表數(shù)據(jù)由HDFS管理;
2)內(nèi)部表的數(shù)據(jù)存儲位置是hive.metastore.warehouse.dir,默認(rèn)位置:/user/hive/warehouse,外部表數(shù)據(jù)的存儲位置由自己制定(如果沒有LOCATION,Hive將在HDFS上的/user/hive/warehouse文件夾下以外部表的表名創(chuàng)建一個文件夾,并將屬于這個表的數(shù)據(jù)存放在這里);
3)刪除內(nèi)部表會直接刪除元數(shù)據(jù)(metadata)及存儲數(shù)據(jù);刪除外部表僅僅會刪除元數(shù)據(jù),HDFS上的文件并不會被刪除;
4)對內(nèi)部表的修改會將修改直接同步給元數(shù)據(jù),而對外部表的表結(jié)構(gòu)和分區(qū)進(jìn)行修改,則需要修復(fù)(MSCK REPAIR TABLE table_name;)
Flume
Flume的source、channel、sink分別都有哪些
可靈活回答:
1)Flume的source、channel、sink分別用的什么類型的?
2)Flume的Kafka sink
3)Flume分為哪幾塊?
4)channel的類型
Agent
Agent是一個JVM進(jìn)程,它以事件的形式將數(shù)據(jù)從源頭送至目的。
Agent主要由Source、Channel、Sink3個部分組成。
Source
Source是負(fù)責(zé)接收數(shù)據(jù)到Flume Agent的組件。
Channel
Channel是位于Source和Sink之間的緩沖區(qū)。因此,Channel允許Source和Sink運(yùn)作在不同的速率上。Channel是線程安全的,可以同時處理幾個Source的寫入操作和幾個Sink的讀取操作。
Sink
Sink不斷地輪詢Channel中的事件且批量地移除它們,并將這些事件批量寫入到存儲或索引系統(tǒng)、或者被發(fā)送到另一個Flume Agent。
Kafka
Kafka是如何實(shí)現(xiàn)高吞吐的
可靈活回答:
1)Kafka為什么低延遲高吞吐?
2)Kafka高吞吐的原因
3)Kafka為什么高可用、高吞吐?
4)Kafka如何保證高吞吐量?
Kafka是分布式消息系統(tǒng),需要處理海量的消息,Kafka的設(shè)計是把所有的消息都寫入速度低容量大的硬盤,以此來換取更強(qiáng)的存儲能力,但實(shí)際上,使用硬盤并沒有帶來過多的性能損失。
kafka主要使用了以下幾個方式實(shí)現(xiàn)了超高的吞吐率。
1)順序讀寫
kafka的消息是不斷追加到文件中的,這個特性使kafka可以充分利用磁盤的順序讀寫性能,順序讀寫不需要硬盤磁頭的尋道時間,只需很少的扇區(qū)旋轉(zhuǎn)時間,所以速度遠(yuǎn)快于隨機(jī)讀寫。
Kafka官方給出了測試數(shù)據(jù)(Raid-5,7200rpm):
順序 I/O: 600MB/s
隨機(jī) I/O: 100KB/s
2)零拷貝
先簡單了解下文件系統(tǒng)的操作流程,例如一個程序要把文件內(nèi)容發(fā)送到網(wǎng)絡(luò)。
這個程序是工作在用戶空間,文件和網(wǎng)絡(luò)socket屬于硬件資源,兩者之間有一個內(nèi)核空間。
在操作系統(tǒng)內(nèi)部,整個過程為:
在 Linux kernel2.2 之后出現(xiàn)了一種叫做"零拷貝(zero-copy)"系統(tǒng)調(diào)用機(jī)制,就是跳過“用 戶緩沖區(qū)”的拷貝,建立一個磁盤空間和內(nèi)存的直接映射,數(shù)據(jù)不再復(fù)制到“用戶態(tài)緩沖區(qū)” 。
系統(tǒng)上下文切換減少為 2 次,可以提升一倍的性能。
3)文件分段
kafka的隊(duì)列topic被分為了多個區(qū)partition,每個partition又分為多個段segment,所以一個隊(duì)列中的消息實(shí)際上是保存在N多個片段文件中
通過分段的方式,每次文件操作都是對一個小文件的操作,非常輕便,同時也增加了并 行處理能力
4)批量發(fā)送
Kafka允許進(jìn)行批量發(fā)送消息,先將消息緩存在內(nèi)存中,然后一次請求批量發(fā)送出去,比如可以指定緩存的消息達(dá)到某個量的時候就發(fā)出去,或者緩存了固定的時間后就發(fā)送出去 ,如100 條消息就發(fā)送,或者每5秒發(fā)送一次,這種策略將大大減少服務(wù)端的I/O次數(shù)
5)數(shù)據(jù)壓縮
Kafka 還支持對消息集合進(jìn)行壓縮,Producer可以通過GZIP或Snappy格式對消息集合進(jìn)行壓縮,壓縮的好處就是減少傳輸?shù)臄?shù)據(jù)量,減輕對網(wǎng)絡(luò)傳輸?shù)膲毫?#xff0c;Producer壓縮之后,在 Consumer需進(jìn)行解壓,雖然增加了CPU的工作,但在對大數(shù)據(jù)處理上,瓶頸在網(wǎng)絡(luò)上而不是 CPU,所以這個成本很值得。
HBase
HBase的rowkey設(shè)計原則
可靈活回答:
1)HBase如何設(shè)計rowkey?
2)你HBase的rowkey為什么這么設(shè)計?有什么優(yōu)缺點(diǎn)?
3)Hbase rowKey設(shè)置講究
HBase中,表會被劃分為1…n個Region,被托管在RegionServer中。Region二個重要的屬性:StartKey與EndKey表示這個Region維護(hù)的rowKey范圍,當(dāng)我們要讀/寫數(shù)據(jù)時,如果rowKey落在某個start-end key范圍內(nèi),那么就會定位到目標(biāo)region并且讀/寫到相關(guān)的數(shù)據(jù)。
那怎么快速精準(zhǔn)的定位到我們想要操作的數(shù)據(jù),就在于我們的rowkey的設(shè)計了。
設(shè)計原則如下:
1、rowkey長度原則
Rowkey是一個二進(jìn)制碼流,Rowkey的長度被很多開發(fā)者建議說設(shè)計在10~100個字節(jié),不過建議是越短越好,不要超過16個字節(jié)。
原因如下:
1)數(shù)據(jù)的持久化文件HFile中是按照Key Value 存儲的,如果Rowkey過長比如100個字節(jié),1000萬列數(shù)據(jù)光Rowkey就要占用100*1000 萬=10億個字節(jié),將近1G數(shù)據(jù),這會極大影響 HFile的存儲效率;
2)MemStore將緩存部分?jǐn)?shù)據(jù)到內(nèi)存,如果 Rowkey字段過長內(nèi)存的有效利用率會降低,系統(tǒng)將無法緩存更多的數(shù)據(jù),這會降低檢索效率。因此Rowkey的字節(jié)長度越短越好;
3)目前操作系統(tǒng)是都是64位系統(tǒng),內(nèi)存8字節(jié)對齊。控制在16個字節(jié),8字節(jié)的整數(shù)倍利用操作系統(tǒng)的最佳特性。
2、rowkey散列原則
如果Rowkey是按時間戳的方式遞增,不要將時間放在二進(jìn)制碼的前面,建議將Rowkey的高位作為散列字段,由程序循環(huán)生成,低位放時間字段,將會提高數(shù)據(jù)均衡分布在每個Regionserver實(shí)現(xiàn)負(fù)載均衡的幾率。如果沒有散列字段,首字段直接是時間信息將產(chǎn)生所有新數(shù)據(jù)都在一個 RegionServer上堆積的熱點(diǎn)現(xiàn)象,這樣在做數(shù)據(jù)檢索的時候負(fù)載將會集中在個別 RegionServer,降低查詢效率。
3、rowkey唯一原則
必須在設(shè)計上保證其唯一性。rowkey是按照字典順序排序存儲的,因此,設(shè)計rowkey的時候,要充分利用這個排序的特點(diǎn),將經(jīng)常讀取的數(shù)據(jù)存儲到一塊,將最近可能會被訪問的數(shù)據(jù)放到一塊。
Spark
Spark數(shù)據(jù)傾斜問題+解決方案
1、數(shù)據(jù)傾斜
數(shù)據(jù)傾斜指的是,并行處理的數(shù)據(jù)集中,某一部分(如Spark或Kafka的一個Partition)的數(shù)據(jù)顯著多于 其它部分,從而使得該部分的處理速度成為整個數(shù)據(jù)集處理的瓶頸
數(shù)據(jù)傾斜倆大直接致命后果
1)數(shù)據(jù)傾斜直接會導(dǎo)致一種情況:Out Of Memory
2)運(yùn)行速度慢
主要是發(fā)生在Shuffle階段。同樣Key的數(shù)據(jù)條數(shù)太多了。導(dǎo)致了某個key(下圖中的80億條)所在的Task數(shù) 據(jù)量太大了。遠(yuǎn)遠(yuǎn)超過其他Task所處理的數(shù)據(jù)量
一個經(jīng)驗(yàn)結(jié)論是:一般情況下,OOM的原因都是數(shù)據(jù)傾斜
2、如何定位數(shù)據(jù)傾斜
數(shù)據(jù)傾斜一般會發(fā)生在shuffle過程中。很大程度是使用可能會觸發(fā)shuffle操作的算子:distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等。
查看任務(wù)->查看Stage->查看代碼
也可從以下幾種情況考慮:
1)是不是有OOM情況出現(xiàn),一般是少數(shù)內(nèi)存溢出的問題
2)是不是應(yīng)用運(yùn)行時間差異很大,總體時間很長
3)需要了解你所處理的數(shù)據(jù)Key的分布情況,如果有些Key有大量的條數(shù),那么就要小心數(shù)據(jù)傾斜的問題
4)一般需要通過Spark Web UI和其他一些監(jiān)控方式出現(xiàn)的異常來綜合判斷
5)看看代碼里面是否有一些導(dǎo)致Shuffle的算子出現(xiàn)
3、數(shù)據(jù)傾斜的幾種典型情況
3.1 數(shù)據(jù)源中的數(shù)據(jù)分布不均勻,Spark需要頻繁交互
3.2 數(shù)據(jù)集中的不同Key由于分區(qū)方式,導(dǎo)致數(shù)據(jù)傾斜
3.3 JOIN操作中,一個數(shù)據(jù)集中的數(shù)據(jù)分布不均勻,另一個數(shù)據(jù)集較小(主要)
3.4 聚合操作中,數(shù)據(jù)集中的數(shù)據(jù)分布不均勻(主要)
3.5 JOIN操作中,兩個數(shù)據(jù)集都比較大,其中只有幾個Key的數(shù)據(jù)分布不均勻
3.6 JOIN操作中,兩個數(shù)據(jù)集都比較大,有很多Key的數(shù)據(jù)分布不均勻
3.7 數(shù)據(jù)集中少數(shù)幾個key數(shù)據(jù)量很大,不重要,其他數(shù)據(jù)均勻
4、數(shù)據(jù)傾斜的處理方法
4.1 數(shù)據(jù)源中的數(shù)據(jù)分布不均勻,Spark需要頻繁交互
解決方案:避免數(shù)據(jù)源的數(shù)據(jù)傾斜
實(shí)現(xiàn)原理 :通過在Hive中對傾斜的數(shù)據(jù)進(jìn)行預(yù)處理,以及在進(jìn)行kafka數(shù)據(jù)分發(fā)時盡量進(jìn)行平均分配。這種方案從根源上解決了數(shù)據(jù)傾斜,徹底避免了在Spark中執(zhí)行shuffle類算子,那么肯定就不會有數(shù)據(jù)傾斜的問題了。
方案優(yōu)點(diǎn) :實(shí)現(xiàn)起來簡單便捷,效果還非常好,完全規(guī)避掉了數(shù)據(jù)傾斜,Spark作業(yè)的性能會大幅度提升。
方案缺點(diǎn) :治標(biāo)不治本,Hive或者Kafka中還是會發(fā)生數(shù)據(jù)傾斜。
適用情況 :在一些Java系統(tǒng)與Spark結(jié)合使用的項(xiàng)目中,會出現(xiàn)Java代碼頻繁調(diào)用Spark作業(yè)的場景,而且對Spark作業(yè)的執(zhí)行性能要求很高,就比較適合使用這種方案。將數(shù)據(jù)傾斜提前到上游的Hive ETL,每天僅執(zhí)行一次,只有那一次是比較慢的,而之后每次Java調(diào)用Spark作業(yè)時,執(zhí)行速度都會很快,能夠提供更好的用戶體驗(yàn)。
總結(jié) :前臺的Java系統(tǒng)和Spark有很頻繁的交互,這個時候如果Spark能夠在最短的時間內(nèi)處理數(shù)據(jù),往往會給前端有非常好的體驗(yàn)。這個時候可以將數(shù)據(jù)傾斜的問題拋給數(shù)據(jù)源端,在數(shù)據(jù)源端進(jìn)行數(shù)據(jù)傾斜的處理。但是這種方案沒有真正的處理數(shù)據(jù)傾斜問題
4.2 數(shù)據(jù)集中的不同Key由于分區(qū)方式,導(dǎo)致數(shù)據(jù)傾斜
**解決方案1:**調(diào)整并行度
實(shí)現(xiàn)原理 :增加shuffle read task的數(shù)量,可以讓原本分配給一個task的多個key分配給多個task,從而讓每個task處理比原來更少的數(shù)據(jù)。
方案優(yōu)點(diǎn) :實(shí)現(xiàn)起來比較簡單,可以有效緩解和減輕數(shù)據(jù)傾斜的影響。
方案缺點(diǎn) :只是緩解了數(shù)據(jù)傾斜而已,沒有徹底根除問題,根據(jù)實(shí)踐經(jīng)驗(yàn)來看,其效果有限。
實(shí)踐經(jīng)驗(yàn) :該方案通常無法徹底解決數(shù)據(jù)傾斜,因?yàn)槿绻霈F(xiàn)一些極端情況,比如某個key對應(yīng)的數(shù)據(jù)量有100萬,那么無論你的task數(shù)量增加到多少,都無法處理。
解決方案2:
自定義Partitioner(緩解數(shù)據(jù)傾斜)
適用場景 :大量不同的Key被分配到了相同的Task造成該Task數(shù)據(jù)量過大。
解決方案 :使用自定義的Partitioner實(shí)現(xiàn)類代替默認(rèn)的HashPartitioner,盡量將所有不同的Key均勻分配到不同的Task中。
優(yōu)勢 :不影響原有的并行度設(shè)計。如果改變并行度,后續(xù)Stage的并行度也會默認(rèn)改變,可能會影響后續(xù)Stage。
劣勢 :適用場景有限,只能將不同Key分散開,對于同一Key對應(yīng)數(shù)據(jù)集非常大的場景不適用。效果與調(diào)整并行度類似,只能緩解數(shù)據(jù)傾斜而不能完全消除數(shù)據(jù)傾斜。而且需要根據(jù)數(shù)據(jù)特點(diǎn)自定義專用的Partitioner,不夠靈活。
4.3 JOIN操作中,一個數(shù)據(jù)集中的數(shù)據(jù)分布不均勻,另一個數(shù)據(jù)集較小(主要)
解決方案:
Reduce side Join轉(zhuǎn)變?yōu)镸ap side Join
適用場景 :在對RDD使用join類操作,或者是在Spark SQL中使用join語句時,而且join操作中的一個RDD或表的數(shù)據(jù)量比較小(比如幾百M(fèi)),比較適用此方案。
實(shí)現(xiàn)原理 :普通的join是會走shuffle過程的,而一旦shuffle,就相當(dāng)于會將相同key的數(shù)據(jù)拉取到一個shuffle read task中再進(jìn)行join,此時就是reduce join。但是如果一個RDD是比較小的,則可以采用廣播小RDD全量數(shù)據(jù)+map算子來實(shí)現(xiàn)與join同樣的效果,也就是map join,此時就不會發(fā)生shuffle操作,也就不會發(fā)生數(shù)據(jù)傾斜。
優(yōu)點(diǎn) :對join操作導(dǎo)致的數(shù)據(jù)傾斜,效果非常好,因?yàn)楦揪筒粫l(fā)生shuffle,也就根本不會發(fā)生數(shù)據(jù)傾斜。
缺點(diǎn) :適用場景較少,因?yàn)檫@個方案只適用于一個大表和一個小表的情況。
4.4 聚合操作中,數(shù)據(jù)集中的數(shù)據(jù)分布不均勻(主要)
解決方案:兩階段聚合(局部聚合+全局聚合)
適用場景 :對RDD執(zhí)行reduceByKey等聚合類shuffle算子或者在Spark SQL中使用group by語句進(jìn)行分組聚合時,比較適用這種方案
實(shí)現(xiàn)原理 :將原本相同的key通過附加隨機(jī)前綴的方式,變成多個不同的key,就可以讓原本被一個task處理的數(shù)據(jù)分散到多個task上去做局部聚合,進(jìn)而解決單個task處理數(shù)據(jù)量過多的問題。接著去除掉隨機(jī)前綴,再次進(jìn)行全局聚合,就可以得到最終的結(jié)果。具體原理見下圖。
優(yōu)點(diǎn) :對于聚合類的shuffle操作導(dǎo)致的數(shù)據(jù)傾斜,效果是非常不錯的。通常都可以解決掉數(shù)據(jù)傾斜,或者至少是大幅度緩解數(shù)據(jù)傾斜,將Spark作業(yè)的性能提升數(shù)倍以上。
缺點(diǎn) :僅僅適用于聚合類的shuffle操作,適用范圍相對較窄。如果是join類的shuffle操作,還得用其他的解決方案
將相同key的數(shù)據(jù)分拆處理
4.5 JOIN操作中,兩個數(shù)據(jù)集都比較大,其中只有幾個Key的數(shù)據(jù)分布不均勻
解決方案:為傾斜key增加隨機(jī)前/后綴
適用場景 :兩張表都比較大,無法使用Map側(cè)Join。其中一個RDD有少數(shù)幾個Key的數(shù)據(jù)量過大,另外一個RDD的Key分布較為均勻。
解決方案 :將有數(shù)據(jù)傾斜的RDD中傾斜Key對應(yīng)的數(shù)據(jù)集單獨(dú)抽取出來加上隨機(jī)前綴,另外一個RDD每條數(shù)據(jù)分別與隨機(jī)前綴結(jié)合形成新的RDD(笛卡爾積,相當(dāng)于將其數(shù)據(jù)增到到原來的N倍,N即為隨機(jī)前綴的總個數(shù)),然后將二者Join后去掉前綴。然后將不包含傾斜Key的剩余數(shù)據(jù)進(jìn)行Join。最后將兩次Join的結(jié)果集通過union合并,即可得到全部Join結(jié)果。
優(yōu)勢 :相對于Map側(cè)Join,更能適應(yīng)大數(shù)據(jù)集的Join。如果資源充足,傾斜部分?jǐn)?shù)據(jù)集與非傾斜部分?jǐn)?shù)據(jù)集可并行進(jìn)行,效率提升明顯。且只針對傾斜部分的數(shù)據(jù)做數(shù)據(jù)擴(kuò)展,增加的資源消耗有限。
劣勢 :如果傾斜Key非常多,則另一側(cè)數(shù)據(jù)膨脹非常大,此方案不適用。而且此時對傾斜Key與非傾斜Key分開處理,需要掃描數(shù)據(jù)集兩遍,增加了開銷。
注意:具有傾斜Key的RDD數(shù)據(jù)集中,key的數(shù)量比較少
4.6 JOIN操作中,兩個數(shù)據(jù)集都比較大,有很多Key的數(shù)據(jù)分布不均勻
解決方案 :隨機(jī)前綴和擴(kuò)容RDD進(jìn)行join
適用場景 :如果在進(jìn)行join操作時,RDD中有大量的key導(dǎo)致數(shù)據(jù)傾斜,那么進(jìn)行分拆key也沒什么意義。
實(shí)現(xiàn)思路 :將該RDD的每條數(shù)據(jù)都打上一個n以內(nèi)的隨機(jī)前綴。同時對另外一個正常的RDD進(jìn)行擴(kuò)容,將每條數(shù)據(jù)都擴(kuò)容成n條數(shù)據(jù),擴(kuò)容出來的每條數(shù)據(jù)都依次打上一個0~n的前綴。最后將兩個處理后的RDD進(jìn)行join即可。和上一種方案是盡量只對少數(shù)傾斜key對應(yīng)的數(shù)據(jù)進(jìn)行特殊處理,由于處理過程需要擴(kuò)容RDD,因此上一種方案擴(kuò)容RDD后對內(nèi)存的占用并不大;而這一種方案是針對有大量傾斜key的情況,沒法將部分key拆分出來進(jìn)行單獨(dú)處理,因此只能對整個RDD進(jìn)行數(shù)據(jù)擴(kuò)容,對內(nèi)存資源要求很高。
優(yōu)點(diǎn) :對join類型的數(shù)據(jù)傾斜基本都可以處理,而且效果也相對比較顯著,性能提升效果非常不錯。
缺點(diǎn) :該方案更多的是緩解數(shù)據(jù)傾斜,而不是徹底避免數(shù)據(jù)傾斜。而且需要對整個RDD進(jìn)行擴(kuò)容,對內(nèi)存資源要求很高。
實(shí)踐經(jīng)驗(yàn) :曾經(jīng)開發(fā)一個數(shù)據(jù)需求的時候,發(fā)現(xiàn)一個join導(dǎo)致了數(shù)據(jù)傾斜。優(yōu)化之前,作業(yè)的執(zhí)行時間大約是60分鐘左右;使用該方案優(yōu)化之后,執(zhí)行時間縮短到10分鐘左右,性能提升了6倍。
注意 :將傾斜Key添加1-N的隨機(jī)前綴,并將被Join的數(shù)據(jù)集相應(yīng)的擴(kuò)大N倍(需要將1-N數(shù)字添加到每一條數(shù)據(jù)上作為前綴)
4.7 數(shù)據(jù)集中少數(shù)幾個key數(shù)據(jù)量很大,不重要,其他數(shù)據(jù)均勻
解決方案 :過濾少數(shù)傾斜Key
適用場景 :如果發(fā)現(xiàn)導(dǎo)致傾斜的key就少數(shù)幾個,而且對計算本身的影響并不大的話,那么很適合使用這種方案。比如99%的key就對應(yīng)10條數(shù)據(jù),但是只有一個key對應(yīng)了100萬數(shù)據(jù),從而導(dǎo)致了數(shù)據(jù)傾斜。
優(yōu)點(diǎn) :實(shí)現(xiàn)簡單,而且效果也很好,可以完全規(guī)避掉數(shù)據(jù)傾斜。
缺點(diǎn) :適用場景不多,大多數(shù)情況下,導(dǎo)致傾斜的key還是很多的,并不是只有少數(shù)幾個。
實(shí)踐經(jīng)驗(yàn) :在項(xiàng)目中我們也采用過這種方案解決數(shù)據(jù)傾斜。有一次發(fā)現(xiàn)某一天Spark作業(yè)在運(yùn)行的時候突然OOM了,追查之后發(fā)現(xiàn),是Hive表中的某一個key在那天數(shù)據(jù)異常,導(dǎo)致數(shù)據(jù)量暴增。因此就采取每次執(zhí)行前先進(jìn)行采樣,計算出樣本中數(shù)據(jù)量最大的幾個key之后,直接在程序中將那些key給過濾掉。
說下RDD的寬依賴和窄依賴
可靈活回答:
1)Spark的寬依賴和窄依賴,為什么要這么劃分?
RDD和它依賴的parent RDD(s)的關(guān)系有兩種不同的類型,窄依賴(narrow dependency)和寬依賴(wide dependency)
1)窄依賴指的是每一個parent RDD的Partition最多被子RDD的一個Partition使用
2)寬依賴指的是多個子RDD的Partition會依賴同一個parent RDD的Partition
Flink
Flink的Exactly Once語義怎么保證
可靈活回答:
1)Flink怎么保證精準(zhǔn)一次消費(fèi)?
2)Flink如何實(shí)現(xiàn)Exactly Once?
3)Flink如何保證僅一次語義?
4)Flink的端到端Exactly Once?
Flink跟其他的流計算引擎相比,最突出或者做的最好的就是狀態(tài)的管理。什么是狀態(tài)呢?比如我們在平時的開發(fā)中,需要對數(shù)據(jù)進(jìn)行count,sum,max等操作,這些中間的結(jié)果(即是狀態(tài))是需要保存的,因?yàn)橐粩嗟母?#xff0c;這些值或者變量就可以理解為是一種狀態(tài),拿讀取kafka為例,我們需要記錄數(shù)據(jù)讀取的位置(即是偏移量),并保存offest,這時offest也可以理解為是一種狀態(tài)。
Flink是怎么保證容錯恢復(fù)的時候保證數(shù)據(jù)沒有丟失也沒有數(shù)據(jù)的冗余呢?checkpoint是使Flink 能從故障恢復(fù)的一種內(nèi)部機(jī)制。檢查點(diǎn)是 Flink 應(yīng)用狀態(tài)的一個一致性副本,包括了輸入的讀取位點(diǎn)。在發(fā)生故障時,Flink 通過從檢查點(diǎn)加載應(yīng)用程序狀態(tài)來恢復(fù),并從恢復(fù)的讀取位點(diǎn)繼續(xù)處理,就好像什么事情都沒發(fā)生一樣。Flink的狀態(tài)存儲在Flink的內(nèi)部,這樣做的好處就是不再依賴外部系統(tǒng),降低了對外部系統(tǒng)的依賴。在Flink的內(nèi)部。通過自身的進(jìn)程去訪問狀態(tài)變量。同時會定期的做checkpoint持久化。把checkpoint存儲在一個分布式的持久化系統(tǒng)中。如果發(fā)生故障。就會從最近的一次checkpoint中將整個流的狀態(tài)進(jìn)行恢復(fù)。
下面通過Flink從Kafka中獲取數(shù)據(jù),來說下怎么管理offest實(shí)現(xiàn)exactly-once的。
Apache Flink中實(shí)現(xiàn)的Kafka消費(fèi)者是一個有狀態(tài)的算子(operator),它集成了Flink的檢查點(diǎn)機(jī)制,它的狀態(tài)是所有Kafka分區(qū)的讀取偏移量。當(dāng)一個檢查點(diǎn)被觸發(fā)時,每一個分區(qū)的偏移量都被存到了這個檢查點(diǎn)中。Flink的檢查點(diǎn)機(jī)制保證了所有operator task的存儲狀態(tài)都是一致的。這里的“一致的”是什么意思呢?意思是它們存儲的狀態(tài)都是基于相同的輸入數(shù)據(jù)。當(dāng)所有的operator task成功存儲了它們的狀態(tài),一個檢查點(diǎn)才算完成。因此,當(dāng)從潛在的系統(tǒng)故障中恢復(fù)時,系統(tǒng)提供了excatly-once的狀態(tài)更新語義。
下面我們將一步步地介紹Apache Flink中的 Kafka消費(fèi)位點(diǎn)是如何做檢查點(diǎn)的。在本文的例子中,數(shù)據(jù)被存在了Flink的JobMaster中。值得注意的是,在POC或生產(chǎn)用例下,這些數(shù)據(jù)最好是能存到一個外部文件系統(tǒng)(如HDFS或S3)中。
第一步: 如下所示,一個Kafka topic,有兩個partition,每個partition都含有 “A”,“B”,“C”,”D”,“E”5條消息。我們將兩個partition的偏移量(offset)都設(shè)置為0。
第二步: Kafka comsumer(消費(fèi)者)開始從 partition 0 讀取消息。消息“A”正在被處理,第一個 consumer 的 offset 變成了1。
第三步: 消息“A”到達(dá)了Flink Map Task。兩個 consumer都開始讀取他們下一條消息(partition0讀取“B”,partition1讀取“A”)。各自將offset更新成2和1。同時,Flink的 JobMaster開始在source觸發(fā)了一個檢查點(diǎn)。
第四步: 接下來,由于source觸發(fā)了檢查點(diǎn),Kafka consumer創(chuàng)建了它們狀態(tài)的第一個快照(”offset = 2, 1”),并將快照存到了Flink的 JobMaster 中。Source 在消息“B”和“A”從partition 0 和 1 發(fā)出后,發(fā)了一個 checkpoint barrier。Checkopint barrier 用于各個 operator task 之間對齊檢查點(diǎn),保證了整個檢查點(diǎn)的一致性。消息“A”到達(dá)了 Flink Map Task,而上面的 consumer 繼續(xù)讀取下一條消息(消息“C”)。
第五步:
Flink Map Task收齊了同一版本的全部 checkpoint barrier后,那么就會將它自己的狀態(tài)也存儲到JobMaster。同時,consumer會繼續(xù)從Kafka讀取消息。
第六步: Flink Map Task完成了它自己狀態(tài)的快照流程后,會向Flink JobMaster匯報它已經(jīng)完成了這個checkpoint。當(dāng)所有的task都報告完成了它們的狀態(tài)checkpoint后,JobMaster就會將這個checkpoint標(biāo)記為成功。從此刻開始,這個 checkpoint就可以用于故障恢復(fù)了。值得一提的是,Flink并不依賴Kafka offset從系統(tǒng)故障中恢復(fù)。
故障恢復(fù) 在發(fā)生故障時(比如,某個worker掛了),所有的operator task會被重啟,而他們的狀態(tài)會被重置到最近一次成功的checkpoint。Kafka source分別從offset 2和1重新開始讀取消息(因?yàn)檫@是完成的checkpoint中存的offset)。當(dāng)作業(yè)重啟后,我們可以期待正常的系統(tǒng)操作,就好像之前沒有發(fā)生故障一樣。如下圖所示:
Flink的checkpoint是基于Chandy-Lamport算法的分布式一致性快照,如果想更加深入的了解Flink的checkpoint可以去了解一下這個算法。
數(shù)據(jù)倉庫
數(shù)據(jù)倉庫分層(層級劃分),每層做什么
CIF 層次架構(gòu)(信息工廠)通過分層將不同的建模方案引入到不同的層次中,CIF 將數(shù)據(jù)倉庫分為四層,如圖所示:
這里再給一張項(xiàng)目里面的數(shù)倉分層架構(gòu)
分層優(yōu)點(diǎn):復(fù)雜問題簡單化、清晰數(shù)據(jù)結(jié)構(gòu)(方便管理)、增加數(shù)據(jù)的復(fù)用性、隔離原始數(shù)據(jù)(解耦)
ODS(Operational Data Store):
操作數(shù)據(jù)存儲層 ,往往是業(yè)務(wù)數(shù)據(jù)庫表格的一對一映射,將業(yè)務(wù)數(shù)據(jù)庫中的表格在 ODS 重新建立,數(shù)據(jù)完全一致;
DWD(Data Warehouse Detail):
數(shù)據(jù)明細(xì)層 ,在 DWD 進(jìn)行數(shù)據(jù)的清洗、脫敏、統(tǒng)一化等操作,DWD 層的數(shù)據(jù)是干凈并且具有良好一致性的數(shù)據(jù);
DWS(Data Warehouse Service):
服務(wù)數(shù)據(jù)層(公共匯總層) ,在DWS層進(jìn)行輕度匯總,為DM層中的不同主題提供公用的匯總數(shù)據(jù);
DM(Data Market):
數(shù)據(jù)集市層 ,DM層針對不同的主題進(jìn)行統(tǒng)計報表的生成。
其它類型
Saprk Streaming和Flink的區(qū)別
可靈活回答 :
1)Saprk和Flink的區(qū)別
2)Flink和Spark對于批處理的區(qū)別?
3)Spark Streaming相比Flink的優(yōu)劣勢
這個問題是一個非常宏觀的問題,因?yàn)閮蓚€框架的不同點(diǎn)非常之多。但是在面試時有非常重要的一點(diǎn)一定要回答出來:Flink是標(biāo)準(zhǔn)的實(shí)時處理引擎,基于事件驅(qū)動。而Spark Streaming是微批(Micro-Batch)的模型。
下面我們就分幾個方面介紹兩個框架的主要區(qū)別:
1)從流處理的角度來講 ,Spark基于微批量處理,把流數(shù)據(jù)看成是一個個小的批處理數(shù)據(jù)塊分別處理,所以延遲性只能做到秒級。而Flink基于每個事件處理,每當(dāng)有新的數(shù)據(jù)輸入都會立刻處理,是真正的流式計算,支持毫秒級計算。由于相同的原因,Spark只支持基于時間的窗口操作(處理時間或者事件時間),而Flink支持的窗口操作則非常靈活,不僅支持時間窗口,還支持基于數(shù)據(jù)本身的窗口(另外還支持基于time、count、session,以及data-driven的窗口操作),開發(fā)者可以自由定義想要的窗口操作。
2)從SQL 功能的角度來講 ,Spark和Flink分別提供SparkSQL和Table APl提供SQL
3)交互支持 。兩者相比較,Spark對SQL支持更好,相應(yīng)的優(yōu)化、擴(kuò)展和性能更好,而Flink在SQL支持方面還有很大提升空間。
4)從迭代計算的角度來講 ,Spark對機(jī)器學(xué)習(xí)的支持很好,因?yàn)榭梢栽趦?nèi)存中緩存中間計算結(jié)果來加速機(jī)器學(xué)習(xí)算法的運(yùn)行。但是大部分機(jī)器學(xué)習(xí)算法其實(shí)是一個有環(huán)的數(shù)據(jù)流,在Spark中,卻是用無環(huán)圖來表示。而Flink支持在運(yùn)行時間中的有環(huán)數(shù)據(jù)流,從而可以更有效的對機(jī)器學(xué)習(xí)算法進(jìn)行運(yùn)算。
5)從相應(yīng)的生態(tài)系統(tǒng)角度來講 ,Spark的社區(qū)無疑更加活躍。Spark可以說有著Apache旗下最多的開源貢獻(xiàn)者,而且有很多不同的庫來用在不同場景。而Flink由于較新,現(xiàn)階段的開源社區(qū)不如Spark活躍,各種庫的功能也不如Spark全面。但是Flink還在不斷發(fā)展,各種功能也在逐漸完善。
基礎(chǔ)轉(zhuǎn)自 https://manor.blog.csdn.net/
原文鏈接:
https://mp.weixin.qq.com/s/2Dzv8uPlvEZz7d_jgB4WPg
侵刪
總結(jié)
以上是生活随笔為你收集整理的大数据开发超高频面试题!大厂面试必看!包含Hadoop、zookeeper、Hive、flume、kafka、Hbase、flink、spark、数仓等的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 第三方社区,从友盟微社区
- 下一篇: 如何更好地理解中间件和洋葱模型