大數據面試題彙總版

作者

 

 

 

 

 

 

 

 

 

 

大數據面試題及答案

彙總版

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

當前版本:

Ver 1.0

製作單位:

 

編寫人員:


審 核 人:

 

籤 收 人:

 

簽署日期:

    2017 年 05 月 22 日

 

版權所有 翻印必究

文檔信息

版本號

1.0

版本日期

2017-05-22

所有者

 

作者


修訂記錄

日期

描述

作者

版本號

2017-05-22

新增


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

目錄

第1部分          申請ID.. 3

第2部分          部署kafka. 4

2.1        部署86節點kafka. 4

2.2        配置86節點zookeeper. 5

2.3        部署87節點kafka. 5

2.4        配置87節點zookeeper. 5

第3部分          啓動zookeeper. 5

3.1        啓動86節點啓動zookeeper-1服務... 5

3.2        啓動87節點啓動zookeeper-2、zookeeper-3服務... 6

第4部分          啓動kafka. 6

4.1        啓動86節點kafka服務... 6

4.2        啓動87節點kafka服務... 6

第5部分          創建topic. 7

5.1        測試Topic(可選)... 7

5.2        創建生產的topic. 7

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第1部分           選擇題

1.1     Hadoop選擇題

1.1.1  Hdfs

1.      下面哪個程序負責 HDFS 數據存儲?

a)NameNode  

b)Jobtracker  

c)Datanode  

d)secondaryNameNode  

e)tasktracker

2.      HDfS 中的 block 默認保存幾份?

a)3

b)2份

c)1份

d)不確定

3.      下列哪個程序通常與NameNode 在一個節點啓動?

a)SecondaryNameNode

b)DataNode

c)TaskTracker

d)Jobtracker

注:haoop1.X

分析:

hadoop 的集羣是基於 master/slave 模式,namenode 和 jobtracker 屬於 master,datanode 和 tasktracker屬於 slave,master 只有一個,而 slave 有多個。SecondaryNameNode 內存需求和 NameNode 在一個數量級上,所以通常 secondary NameNode(運行在單獨的物理機器上)和 NameNode 運行在不同的機器上。

JobTracker 和 TaskTracker

JobTracker 對應於 NameNode

TaskTracker 對應於 DataNode

DataNode 和 NameNode 是針對數據存放來而言的

JobTracker 和 TaskTracker 是對於 MapReduce 執行而言的

mapreduce 中幾個主要概念,mapreduce 整體上可以分爲這麼幾條執行線索:

jobclient,JobTracker 與 TaskTracker。

1、JobClient 會在用戶端通過 JobClient 類將應用已經配置參數打包成 jar 文件存儲到 hdfs,並把路徑提交到 Jobtracker,然後由 JobTracker 創建每一個 Task(即 MapTask 和 ReduceTask)並將它們分發到各個 TaskTracker 服務中去執行

2、JobTracker 是一個 master 服務,軟件啓動之後 JobTracker 接收 Job,負責調度 Job 的每一個子任務 task運行於 TaskTracker 上,並監控它們,如果發現有失敗的 task 就重新運行它。一般情況應該把 JobTracker 部署在單獨的機器上。

3、TaskTracker 是運行在多個節點上的 slaver 服務。TaskTracker 主動與 JobTracker 通信,接收作業,並負責直接執行每一個任務。TaskTracker 都需要運行在 HDFS 的 DataNode 上

4.      HDFS 默認 Block Size

a)32MB  

b)64MB

c)128MB

注:舊版本是64MB

5.      Client 端上傳文件的時候下列哪項正確

a)數據經過 NameNode 傳遞給 DataNode

b)Client 端將文件切分爲 Block,依次上傳

c)Client 只上傳數據到一臺 DataNode,然後由 NameNode 負責 Block 複製工作

分析:

Client 向 NameNode 發起文件寫入的請求。

NameNode 根據文件大小和文件塊配置情況,返回給 Client 它所管理部分 DataNode 的信息。

Client 將文件劃分爲多個 Block,根據 DataNode 的地址信息,按順序寫入到每一個 DataNode 塊中。

6.      下面與 HDFS 類似的框架是?C

A NTFS

B FAT32

C GFS

D EXT3

7.      的

8.      的

1.1.2  集羣管理

1.      下列哪項通常是集羣的最主要瓶頸

a)CPU  

b)網絡  

c)磁盤 IO  

d)內存

解析:

由於大數據面臨海量數據,讀寫數據都需要 io,然後還要冗餘數據,hadoop 一般備 3 份數據,所以 IO就會打折扣。

2.      關於SecondaryNameNode 哪項是正確的?

a)它是 NameNode 的熱備

b)它對內存沒有要求

c)它的目的是幫助 NameNode 合併編輯日誌,減少 NameNode 啓動時間

d)SecondaryNameNode 應與 NameNode 部署到一個節點

3.      下列哪項可以作爲集羣的管理?

a)Puppet  b)Pdsh  c)ClouderaManager  d)Zookeeper

分析:

A:puppetpuppet 是一種 Linux、Unix、windows 平臺的集中配置管理系統

B:pdsh 可以實現在在多臺機器上執行相同的命令

詳細參考:集羣管理小工具介紹-pdsh

C:可以參考 Cloudera Manager 四大功能【翻譯】

首先這裏給管理下一個定義:部署、配置、調試、監控,屬於管理

4.      配置機架感知的下面哪項正確

a)如果一個機架出問題,不會影響數據讀寫

b)寫入數據的時候會寫到不同機架的 DataNode

c)MapReduce 會根據機架獲取離自己比較近的網絡數據

5.      下列哪個是 Hadoop 運行的模式

a)單機版 b)僞分佈式 c)分佈式

6.      Cloudera 提供哪幾種安裝 CDH 的方法

a)Cloudera manager  b)Tarball  c)Yum  d)Rpm

7.      的

8.       D d

9.      的

10.  的

1.2     Hbase選擇題

1.2.1  Hbase基礎

1.      HBase 來源於哪篇博文? C

A TheGoogle File System

BMapReduce

CBigTable

D Chubby

2.      下面對 HBase 的描述哪些是正確的? B、C、D

A 不是開源的

B 是面向列的

C 是分佈式的

D 是一種 NoSQL 數據庫

3.      HBase 依靠()存儲底層數據 A

A HDFS

B Hadoop

C Memory

DMapReduce

4.      HBase 依賴()提供消息通信機制 A

AZookeeper

B Chubby

C RPC

D Socket

5.      HBase 依賴()提供強大的計算能力 D

AZookeeper

B Chubby

C RPC

DMapReduce

6.      MapReduce 與 HBase 的關係,哪些描述是正確的? B、C

A 兩者不可或缺,MapReduce 是 HBase 可以正常運行的保證

B 兩者不是強關聯關係,沒有 MapReduce,HBase 可以正常運行

CMapReduce 可以直接訪問 HBase

D 它們之間沒有任何關係

7.      下面哪些選項正確描述了HBase 的特性? A、B、C、D

A 高可靠性

B 高性能

C 面向列

D 可伸縮

8.      下面哪些概念是 HBase 框架中使用的?A、C

A HDFS

B GridFS

CZookeeper

D EXT3

9.       D

1.2.2  Hbase核心

1.      LSM 含義是?A

A 日誌結構合併樹

B 二叉樹

C 平衡二叉樹

D 長平衡二叉樹

2.      下面對 LSM 結構描述正確的是? A、C

A 順序存儲

B 直接寫硬盤

C 需要將數據 Flush 到磁盤

D 是一種搜索平衡樹

3.      LSM 更能保證哪種操作的性能?B

A 讀

B 寫

C 隨機讀

D 合併

4.      LSM 的讀操作和寫操作是獨立的?A

A 是。

B 否。

C LSM 並不區分讀和寫

D LSM 中讀寫是同一種操作

5.      LSM 結構的數據首先存儲在()。 B

A 硬盤上

B 內存中

C 磁盤陣列中

D 閃存中

6.      HFile 數據格式中的 Data 字段用於()。A

A 存儲實際的 KeyValue 數據

B 存儲數據的起點

C 指定字段的長度

D 存儲數據塊的起點

7.      HFile 數據格式中的 MetaIndex 字段用於()。D

A Meta 塊的長度

B Meta 塊的結束點

C Meta 塊數據內容

D Meta 塊的起始點

8.      HFile 數據格式中的 Magic 字段用於()。A

A 存儲隨機數,防止數據損壞

B 存儲數據的起點

C 存儲數據塊的起點

D 指定字段的長度

9.      HFile 數據格式中的 KeyValue 數據格式,下列選項描述正確的是()。A、D

A 是 byte[]數組

B 沒有固定的結構

C 數據的大小是定長的

D 有固定的結構

10.  HFile 數據格式中的 KeyValue 數據格式中 Value 部分是()。C

A 擁有複雜結構的字符串

B 字符串

C 二進制數據

D 壓縮數據

11.  D

1.2.3  HBase 高級應用介紹

1.      HBase 中的批量加載底層使用()實現。A

AMapReduce

B Hive

CCoprocessor

D BloomFilter

2.      HBase 性能優化包含下面的哪些選項?A、B、C、D

A 讀優化

B 寫優化

C 配置優化

D JVM 優化

3.      Rowkey 設計的原則,下列哪些選項的描述是正確的?A、B、C

A 儘量保證越短越好

B 可以使用漢字

C 可以使用字符串

D 本身是無序的

4.      HBase 構建二級索引的實現方式有哪些? AB

AMapReduce

BCoprocessor

C BloomFilter

D Filter

5.      關於 HBase 二級索引的描述,哪些是正確的?A、B

A 核心是倒排表

B 二級索引概念是對應 Rowkey 這個“一級”索引

C 二級索引使用平衡二叉樹

D 二級索引使用 LSM 結構

6.      下列關於 Bloom Filter 的描述正確的是?A、C

A 是一個很長的二進制向量和一系列隨機映射函數

B 沒有誤算率

C 有一定的誤算率

D 可以在 Bloom Filter 中刪除元素

7.      D

1.2.4  HBase 安裝、部署、啓動

1.      HBase 官方版本可以安裝在什麼操作系統上?A、B、C

A CentOS

B Ubuntu

C RedHat

D Windows

2.      HBase 虛擬分佈式模式需要()個節點?A

A 1

B 2

C 3

D 最少 3 個

3.      HBase 分佈式模式最好需要()個節點?C

A 1

B 2

C 3

D 最少

4.      下列哪些選項是安裝 HBase 前所必須安裝的?A、B

A 操作系統

B JDK

C ShellScript

D JavaCode

5.      解壓.tar.gz 結尾的 HBase 壓縮包使用的 Linux 命令是?A

A tar-zxvf

B tar -zx

C tar -s

D tar -nf

6.      D

7.      D

1.3     Zookeeper選擇題

1.3.1  Zookeeper基礎

1.      下面與 Zookeeper 類似的框架是?D

AProtobuf

B Java

C Kafka

D Chubby

2.      的

3.      D

4.      D

5.      D

6.      D

7.      D

8.      D

9.      d

 

第2部分           判斷題

第2部分      

2.1     Hadoop判斷題

2.1.1  集羣管理

1.      Ganglia 不僅可以進行監控,也可以進行告警。(正確)

解析:

ganglia 作爲一款最常用的 Linux 環境中的監控軟件,它擅長的的是從節點中按照用戶的需求以較低的代價

採集數據。但是 ganglia 在預警以及發生事件後通知用戶上並不擅長。最新的 ganglia 已經有了部分這方面

的功能。但是更擅長做警告的還有 Nagios。Nagios,就是一款精於預警、通知的軟件。通過將 Ganglia 和

Nagios 組合起來,把 Ganglia 採集的數據作爲 Nagios 的數據源,然後利用 Nagios 來發送預警通知,可以

完美的實現一整套監控管理的系統。

2.      Nagios 不可以監控 Hadoop 集羣,因爲它不提供 Hadoop支持。(錯誤 )

分析:

Nagios 是集羣監控工具,而且是雲計算三大利器之一

3.      如果 NameNode 意外終止,SecondaryNameNode 會接替它使集羣繼續工作。(錯誤 )

分析:

SecondaryNameNode 是幫助恢復,而不是替代

4.      Cloudera CDH 是需要付費使用的。(錯誤)

分析:

第一套付費產品是 Cloudera Enterpris,Cloudera Enterprise 在美國加州舉行的 Hadoop 大會 (HadoopSummit) 上公開,以若干私有管理、監控、運作工具加強 Hadoop 的功能。收費採取合約訂購方式,價格隨用的 Hadoop 叢集大小變動。

5.      NameNode 負責管理 metadata,client 端每次讀寫請求,它都會從磁盤中讀取或則會寫入 metadata信息並反饋 client 端。(錯誤)

分析:

NameNode 不需要從磁盤讀取 metadata,所有數據都在內存中,硬盤上的只是序列化的結果,只有每次namenode 啓動的時候纔會讀取。

1)文件寫入

Client 向 NameNode 發起文件寫入的請求。

NameNode 根據文件大小和文件塊配置情況,返回給 Client 它所管理部分 DataNode 的信息。

Client 將文件劃分爲多個 Block,根據 DataNode 的地址信息,按順序寫入到每一個 DataNode 塊中。

2)文件讀取

Client 向 NameNode 發起文件讀取的請求。

NameNode 返回文件存儲的 DataNode 的信息。

Client 讀取文件信息。

6.      NameNode 本地磁盤保存了 Block 的位置信息。( 個人認爲正確,歡迎提出其它意見)

分析:

DataNode 是文件存儲的基本單元,它將 Block 存儲在本地文件系統中,保存了 Block 的 Meta-data,同時週期性地將所有存在的 Block 信息發送給 NameNode。

7.      DataNode 通過長連接與 NameNode 保持通信。錯誤

分析:

通過心跳機制。

(1).長連接

Client 方與 Server 方先建立通訊連接,連接建立後不斷開,然後再進行報文發送和接收。這種方式下由於通訊連接一直存在,此種方式常用於點對點通訊。

(2).短連接

Client 方與 Server 每進行一次報文收發交易時才進行通訊連接,交易完畢後立即斷開連接。此種方式常用於一點對多點通訊,比如多個 Client 連接一個 Server.

8.      Hadoop 自身具有嚴格的權限管理和安全措施保障集羣正常運行。(錯誤)

9.      Slave 節點要存儲數據,所以它的磁盤越大越好。(錯誤)

分析:

一旦 Slave 節點宕機,數據恢復是一個難題

10.  hadoop dfsadmin –report 命令用於檢測 HDFS 損壞塊。(錯誤)

分析:

hadoop dfsadmin -report

用這個命令可以快速定位出哪些節點 down 掉了,HDFS 的容量以及使用了多少,以及每個節點的硬盤使用情況。

當然 NameNode 有個 http 頁面也可以查詢,但是這個命令的輸出更適合我們的腳本監控 dfs 的使用狀況

11.  Hadoop 默認調度器策略爲 FIFO(正確 )

12.  集羣內每個節點都應該配 RAID,這樣避免單磁盤損壞,影響整個節點運行。(錯誤)

分析:

首先明白什麼是 RAID:磁盤陣列(Redundant Arrays of Independent Disks,RAID),有“獨立磁盤構成的具有冗餘能力的陣列”之意。

這句話錯誤的地方在於太絕對,具體情況具體分析。題目不是重點,知識才是最重要的。

因爲 hadoop 本身就具有冗餘能力,所以如果不是很嚴格不需要都配備 RAID。

13.  Hadoop 環境變量中的 HADOOP_HEAPSIZE 用於設置所有 Hadoop 守護線程的內存。它默認是 200 GB。( 錯誤)

分析:

hadoop 爲各個守護進程(namenode,secondarynamenode,jobtracker,datanode,tasktracker)統一分配的內存在 hadoop-env.sh 中設置,參數爲 HADOOP_HEAPSIZE,默認爲 1000M。

14.  DataNode 首次加入 cluster 的時候,如果 log 中報告不兼容文件版本,那需要 NameNode執行―Hadoopnamenode -format‖操作格式化磁盤。(錯誤 )

分析:

這個報錯是說明 DataNode 所裝的 Hadoop 版本和其它節點不一致,應該檢查 DataNode 的 Hadoop 版本

 

15.  D

16.  D

17.  的

18.   D

19.  的

20.   D的

21.   D的

22.   D

23.   d

2.1.2  Hdfs

1.      Block Size 是不可以修改的。(錯誤)

解析:

Hadoop 的基礎配置文件是 hadoop-default.xml,默認建立一個 Job 的時候會建立 Job 的 Config,Config

首先讀入hadoop-default.xml的配置,然後再讀入hadoop-site.xml的配置(這個文件初始的時候配置爲空),

hadoop-site.xml 中主要配置需要覆蓋的 hadoop-default.xml 的系統級配置。具體配置可以參考下:

<property>

  <name>dfs.block.size</name>//block 的大小,單位字節,後面會提到用處,必須是 512 的倍數,因

爲採用 crc 作文件完整性校驗,默認配置 512 是 checksum 的最小單元。

  <value>5120000</value>

  <description>The default block size for new files.</description>

</property>

2.      Hadoop 支持數據的隨機讀寫。(錯)

分析:

lucene 是支持隨機讀寫的,而 hdfs 只支持隨機讀。但是 HBase 可以來補救。

HBase 提供隨機讀寫,來解決 Hadoop 不能處理的問題。HBase 自底層設計開始即聚焦於各種可伸縮性問題:表可以很―高‖,有數十億個數據行;也可以很―寬‖,有數百萬個列;水平分區並在上千個普通商用機節點上自動複製。表的模式是物理存儲的直接反映,使系統有可能提高高效的數據結構的序列化、存儲和檢索。

3.      因爲 HDFS 有多個副本,所以 NameNode 是不存在單點問題的。(錯誤 )

分析:

副本針對DataName而講的

 

4.      的

5.      的

6.      的

2.1.3  MapReduce

1.      Hadoop 是 Java 開發的,所以 MapReduce 只支持 Java 語言編寫。(錯誤 )

分析:

支持c++等語言,需要通過接口。

2.      每個 map 槽就是一個線程。(錯誤)

分析:

一個task對應一個線程

分析:首先我們知道什麼是 map 槽,map 槽->map slot,map slot 只是一個邏輯值 ( org.apache.hadoop.mapred.TaskTracker.TaskLauncher.numFreeSlots ),而不是對應着一個線程或者進程

3.      Mapreduce 的 input split 就是一個 block。(錯誤)

分析:

   應該是一個block數組

1、運行mapred程序;
2、本次運行將生成一個Job,於是JobClient向JobTracker申請一個JobID以標識這個Job;
3、JobClient將Job所需要的資源提交到HDFS中一個以JobID命名的目錄中。這些資源包括JAR包、配置文件、InputSplit、等;
4、JobClient向JobTracker提交這個Job;
5、JobTracker初始化這個Job;
6、JobTracker從HDFS獲取這個Job的Split等信息;
7、JobTracker向TaskTracker分配任務;
8、TaskTracker從HDFS獲取這個Job的相關資源;
9、TaskTracker開啓一個新的JVM;
10、TaskTracker用新的JVM來執行Map或Reduce;

 

InputSplit也是一個interface,具體返回什麼樣的implement,這是由具體的InputFormat來決定的。InputSplit也只有兩個接口函數:
long getLength() throws IOException;
String[] getLocations() throws IOException;
這個interface僅僅描述了Split有多長,以及存放這個Split的Location信息(也就是這個Split在HDFS上存放的機器。它可能有多個replication,存在於多臺機器上)。除此之外,就再沒有任何直接描述Split的信息了。比如:Split對應於哪個文件?在文件中的起始和結束位置是什麼?等等重要的特徵都沒有描述到。
爲什麼會這樣呢?因爲關於Split的那些描述信息,對於MapReduce框架來說是不需要關心的。框架只關心Split的長度(主要用於一些統計信息)和Split的Location(主要用於Split的調度,後面會細說)。
而Split中真正重要的描述信息還是隻有InputFormat會關心。在需要讀取一個Split的時候,其對應的InputSplit會被傳遞到InputFormat的第二個接口函數getRecordReader,然後被用於初始化一個RecordReader,以解析輸入數據。也就是說,描述Split的重要信息都被隱藏了,只有具體的InputFormat自己知道。它只需要保證getSplits返回的InputSplit和getRecordReader所關心的InputSplit是同樣的implement就行了。這就給InputFormat的實現提供了巨大的靈活性。

4.      的

5.      的

6.      的

7.      D

8.      的

第3部分           敘述題

第3部分      

3.1     Hadoop敘述題

3.1.1  Hadoop部署

1.      hdfs的體系結構

解答:

hdfs有namenode、secondraynamenode、datanode組成。

爲n+1模式

namenode負責管理datanode和記錄元數據

secondraynamenode負責合併日誌

datanode負責存儲數據

 

2.      簡要描述如何安裝配置一個apache開原本hadoop,只描述即可,無需列出完整步驟,能列出步驟更好。

流程:

1.創建hadoop用戶

2.修改IP

3.安裝JDK,並配置環境變量

4.修改host文件映射

5.安裝SSH,配置無祕鑰通信

6.上傳解壓hadoop安裝包

7.配置conf文件夾下的hadoop-env.sh、core-site.xlmapre-site.xml、hdfs-site.xml

8.配置hadoop的環境變量

9.Hadoop namenode -format

10.start-all

3.      啓動hadoop集羣時報下圖錯誤,分析什麼原因:

解答:

1、權限問題,可能曾經用root啓動過集羣。(例如hadoop搭建的集羣,是tmp/hadoop-hadoop/.....)

2、可能是文件夾不存在

3、解決: 刪掉tmp下的那個文件,或改成當前用戶

 

4.      請列出hadoop的進程名稱

解答:

1.namenode:管理集羣,並記錄datanode文件信息。

2.Secondname:可以做冷備,對一定範圍內的數據做快照性備份。

3.Datanode:存儲數據。

4.Jobtracker:管理任務,並將任務分配給tasktracker。

5.Tasktracker:任務執行者

 

5.      Hadoop的核心配置是什麼?

解答:

Hadoop的核心配置通過兩個xml文件來完成:

1.hadoop-default.xml;

2.hadoop-site.xml。

這些文件都使用xml格式,因此每個xml中都有一些屬性,包括名稱和值,但是當下這些文件都已不復存在。

6.      那當下又該如何配置?

解答:

Hadoop現在擁有3個配置文件:

1,core-site.xml;

2,hdfs-site.xml;

3,mapred-site.xml。

這些文件都保存在conf/子目錄下。

7.      “jps”命令的用處?

解答:

這個命令可以檢查Namenode、Datanode、Task Tracker、 Job Tracker是否正常工作。

 

8.      簡要描述如何安裝配置一個apache 開源版 hadoop,描述即可,列出步驟更好

解答:

9.      請列出正常工作的 hadoop 集羣中 hadoop 都需要啓動哪些進程,他們的作用分別是什麼?

解答:

10.  啓動 hadoop 報如下錯誤,該如何解決?

error org.apache.hadoop.hdfs.server.namenode.NameNode

org.apache.hadoop.hdfs.server.common.inconsistentFSStateExceptio

n Directory /tmp/hadoop-root/dfs/name is in an inconsistent

state storage direction does not exist or is not accessible?

11.  請寫出以下執行命令

1)殺死一個 job?

2)刪除 hdfs 上的/tmp/aaa 目錄

3)加入一個新的存儲節點和刪除一個計算節點需要刷新集羣狀態命令?

解答:

hadoop job -list 記錄job-id、hadoop job -kill job-id

 

hadoop fs -rmr /tmp/aaa

 

添加新節點:

hadoop -daemon.sh start datanode

hadoop -daemon.sh start tasktracker

 

移除一個節點:

hadoop mradmin -refreshnodes

hadoop dfsadmin -refreshnodes

12.  請列出你所知道的 hadoop 調度器,並簡要說明其工作方法?

解答:

1.FIFO schedular:默認,先進先出的原則

2.Capacity schedular:計算能力調度器,選擇佔用最小,優先級高的先執行,以此類推。

3.Fair schedular:公平調度,所有的job具有相同的資源。

13.  請列出在你以前工作中所使用過的開發 mapreduce 的語言?

解答:

14.  你認爲用 Java,Streaming,pipe 方式開發 mapreduce,各有哪些優缺點?

解答:

15.  hadoop框架中怎麼來優化

解答:

(1)  從應用程序角度進行優化。由於mapreduce是迭代逐行解析數據文件的,怎樣在迭代的情況下,編寫高效率的應用程序,是一種優化思路。

(2)  對Hadoop參數進行調優。當前hadoop系統有190多個配置參數,怎樣調整這些參數,使hadoop作業運行儘可能的快,也是一種優化思路。

(3) 從系統實現角度進行優化。這種優化難度是最大的,它是從hadoop實現機制角度,發現當前Hadoop設計和實現上的缺點,然後進行源碼級地修改。該方法雖難度大,但往往效果明顯。

(4)linux內核參數調整

1. 使用自定義Writable

自帶的Text很好用,但是字符串轉換開銷較大,故根據實際需要自定義Writable,注意作爲Key時要實現WritableCompareable接口

避免output.collect(new Text( ),new Text())

提倡key.set( ) value.set( ) output.collect(key,value)

前者會產生大量的Text對象,使用完後Java垃圾回收器會花費大量的時間去收集這些對象

 

2. 使用StringBuilder

不要使用Formatter StringBuffer( 線程安全)

StringBuffer儘量少使用多個append方法,適當使用+

 

3. 使用DistributedCache加載文件

比如配置文件,詞典,共享文件,避免使用static變量

 

4. 充分使用Combiner Parttitioner Comparator。

Combiner : 對map任務進行本地聚合

Parttitioner : 合適的Parttitioner避免reduce端負載不均

Comparator : 二次排序

比如求每天的最大氣溫,map結果爲日期:氣溫,若氣溫是降序的,直接取列表首元素即可

 

5. 使用自定義InputFormat和OutputFormat

 

6. MR應避免

 

靜態變量:不能用於計數,應使用Counter

 

大對象:Map List

 

遞歸:避免遞歸深度過大

 

超長正則表達式:消耗性能,要在map或reduce函數外編譯正則表達式

 

不要創建本地文件:變向的把HDFS裏面的數據轉移到TaskTracker,佔用網絡帶寬

 

不要大量創建目錄和文件

 

不要大量使用System.out.println,而使用Logger

 

不要自定義過多的Counter,最好不要超過100個

 

不要配置過大內存,mapred.child.java.opts -Xmx2000m是用來設置mapreduce任務使用的最大heap量

 

7.關於map的數目

map數目過大[創建和初始化map的開銷],一般是由大量小文件造成的,或者dfs.block.size設置的太小,對於小文件可以archive文件或者Hadoop fs -merge合併成一個大文件.

map數目過少,造成單個map任務執行時間過長,頻繁推測執行,且容易內存溢出,並行性優勢不能體現出來。dfs.block.size一般爲256M-512M

壓縮的Text 文件是不能被分割的,所以儘量使用SequenceFile,可以切分

 

8.關於reduce的數目

reduce數目過大,產生大量的小文件,消耗大量不必要的資源,reduce數目過低呢,造成數據傾斜問題,且通常不能通過修改參數改變。

可選方案:mapred.reduce.tasks設爲-1變成AutoReduce。

Key的分佈,也在某種程度上決定了Reduce數目,所以要根據Key的特點設計相對應的Parttitioner 避免數據傾斜

 

9.Map-side相關參數優化

io.sort.mb(100MB):通常k個map tasks會對應一個buffer,buffer主要用來緩存map部分計算結果,並做一些預排序提高map性能,若map輸出結果較大,可以調高這個參數,減少map任務進行spill任務個數,降低 I/O的操作次數。若map任務的瓶頸在I/O的話,那麼將會大大提高map性能。如何判斷map任務的瓶頸?

io.sort.spill.percent(0.8):spill操作就是當內存buffer超過一定閾值(這裏通常是百分比)的時候,會將buffer中得數據寫到Disk中。而不是等buffer滿後在spill,否則會造成map的計算任務等待buffer的釋放。一般來說,調整 io.sort.mb而不是這個參數。

io.sort.factor(10):map任務會產生很多的spill文件,而map任務在正常退出之前會將這些spill文件合併成一個文件,即merger過程,缺省是一次合併10個參數,調大io.sort.factor,減少merge的次數,減少Disk I/O操作,提高map性能。

min.num.spill.for.combine:通常爲了減少map和reduce數據傳輸量,我們會制定一個combiner,將map結果進行本地聚集。這裏combiner可能在merger之前,也可能在其之後。那麼什麼時候在其之前呢?當spill個數至少爲min.num.spill.for.combine指定的數目時同時程序指定了Combiner,Combiner會在其之前運行,減少寫入到Disk的數據量,減少I/O次數。

 

10.壓縮(時間換空間)

MR中的數據無論是中間數據還是輸入輸出結果都是巨大的,若不使用壓縮不僅浪費磁盤空間且會消耗大量網絡帶寬。同樣在spill,merge(reduce也對有一個merge)亦可以使用壓縮。若想在cpu時間和壓縮比之間尋找一個平衡,LzoCodec比較適合。通常MR任務的瓶頸不在CPU而在於I/O,所以大部分的MR任務都適合使用壓縮。

 

11. reduce-side相關參數優化

reduce:copy->sort->reduce,也稱shuffle

mapred.reduce.parellel.copies(5):任一個map任務可能包含一個或者多個reduce所需要數據,故一個map任務完成後,相應的reduce就會立即啓動線程下載自己所需要的數據。調大這個參數比較適合map任務比較多且完成時間比較短的Job。

mapred.reduce.copy.backoff:reduce端從map端下載數據也有可能由於網絡故障,map端機器故障而失敗。那麼reduce下載線程肯定不會無限等待,當等待時間超過mapred.reduce.copy.backoff時,便放棄,嘗試從其他地方下載。需注意:在網絡情況比較差的環境,我們需要調大這個參數,避免reduce下載線程被誤判爲失敗。

io.sort.factor:recude將map結果下載到本地時,亦需要merge,如果reduce的瓶頸在於I/O,可嘗試調高增加merge的併發吞吐,提高reduce性能、

mapred.job.shuffle.input.buffer.percent(0.7):reduce從map下載的數據不會立刻就寫到Disk中,而是先緩存在內存中,mapred.job.shuffle.input.buffer.percent指定內存的多少比例用於緩存數據,內存大小可通過mapred.child.java.opts來設置。和map類似,buffer不是等到寫滿才往磁盤中寫,也是到達閾值就寫,閾值由mapred.job,shuffle.merge.percent來指定。若Reduce下載速度很快,容易內存溢出,適當增大這個參數對增加reduce性能有些幫助。

mapred.job.reduce.input.buffer.percent (0):當Reduce下載map數據完成之後,就會開始真正的reduce的計算,reduce的計算必然也是要消耗內存的,那麼在讀物reduce所需要的數據時,同樣需要內存作爲buffer,這個參數是決定多少的內存百分比作爲buffer。默認爲0,也就是說reduce全部從磁盤讀數據。若redcue計算任務消耗內存很小,那麼可以設置這個參數大於0,使一部分內存用來緩存數據。

 

16.  從應用程序角度進行優化

解答:

(1) 避免不必要的reduce任務

如果mapreduce程序中reduce是不必要的,那麼我們可以在map中處理數據, Reducer設置爲0。這樣避免了多餘的reduce任務。

(2) 爲job添加一個Combiner

爲job添加一個combiner可以大大減少shuffle階段從map task拷貝給遠程reduce task的數據量。一般而言,combiner與reducer相同。

(3) 根據處理數據特徵使用最適合和簡潔的Writable類型

Text對象使用起來很方便,但它在由數值轉換到文本或是由UTF8字符串轉換到文本時都是低效的,且會消耗大量的CPU時間。當處理那些非文本的數據時,可以使用二進制的Writable類型,如IntWritable, FloatWritable等。二進制writable好處:避免文件轉換的消耗;使map task中間結果佔用更少的空間。

(4) 重用Writable類型

很多MapReduce用戶常犯的一個錯誤是,在一個map/reduce方法中爲每個輸出都創建Writable對象。例如,你的Wordcout mapper方法可能這樣寫:

 

public void map(...) {

  …

 

  for (String word : words) {

    output.collect(new Text(word), new IntWritable(1));

  }

}

這樣會導致程序分配出成千上萬個短週期的對象。Java垃圾收集器就要爲此做很多的工作。更有效的寫法是:

class MyMapper … {

  Text wordText = new Text();

  IntWritable one = new IntWritable(1);

  public void map(...) {

    for (String word: words) {

      wordText.set(word);

      output.collect(wordText, one);

    }

  }

}

(5) 使用StringBuffer而不是String

當需要對字符串進行操作時,使用StringBuffer而不是String,String是read-only的,如果對它進行修改,會產生臨時對象,而StringBuffer是可修改的,不會產生臨時對象。

17.  datanode在什麼情況下不會備份

解答:

當分備份數爲1時。

18.  combiner出現在那個過程

解答:

出現在map階段的map方法後。

19.  3個datanode中有一個datanode出現錯誤會怎樣?

解答:

這個datanode的數據會在其他的datanode上重新做備份。

20.  描述一下hadoop中,有哪些地方使用了緩存機制,作用分別是什麼?

解答:

 

21.  如何確定hadoop集羣的健康狀態

解答:

 

22.  hadoop 的 namenode 宕機,怎麼解決

解答:

先分析宕機後的損失,宕機後直接導致client無法訪問,內存中的元數據丟失,但是硬盤中的元數據應該還存在,如果只是節點掛了,重啓即可,如果是機器掛了,重啓機器後看節點是否能重啓,不能重啓就要找到原因修復了。但是最終的解決方案應該是在設計集羣的初期就考慮到這個問題,做namenode的HA。

 

23.  一個datanode 宕機,怎麼一個流程恢復

解答:

Datanode宕機了後,如果是短暫的宕機,可以實現寫好腳本監控,將它啓動起來。如果是長時間宕機了,那麼datanode上的數據應該已經被備份到其他機器了,那這臺datanode就是一臺新的datanode了,刪除他的所有數據文件和狀態文件,重新啓動。

24.  的

25.  D

26.  的

27.  的

28.  的

29.  的

30.   d

3.1.2  Hadoop原理

1.      請簡述 hadoop 怎麼樣實現二級排序?

解答:

在Reduce階段,先對Key排序,再對Value排序

最常用的方法是將Value放到Key中,實現一個組合Key,然後自定義Key排序規則(爲Key實現一個WritableComparable)。

2.      如何使用MapReduce實現兩個表join,可以考慮一下幾種情況:(1)一個表大,一個表小(可放到內存中);(2)兩個表都是大表?

解答:

第一種情況比較簡單,只需將小表放到DistributedCache中即可;

第二種情況常用的方法有:map-side join(要求輸入數據有序,通常用戶Hbase中的數據表連接),reduce-side join,semi join(半連接)

3.      MapReduce中排序發生在哪幾個階段?這些排序是否可以避免?爲什麼?

解答:

一個MapReduce作業由Map階段和Reduce階段兩部分組成,這兩階段會對數據排序,從這個意義上說,MapReduce框架本質就是一個Distributed Sort。在Map階段,在Map階段,Map Task會在本地磁盤輸出一個按照key排序(採用的是快速排序)的文件(中間可能產生多個文件,但最終會合併成一個),在Reduce階段,每個Reduce Task會對收到的數據排序,這樣,數據便按照Key分成了若干組,之後以組爲單位交給reduce()處理。很多人的誤解在Map階段,如果不使用Combiner便不會排序,這是錯誤的,不管你用不用Combiner,Map Task均會對產生的數據排序(如果沒有Reduce Task,則不會排序, 實際上Map階段的排序就是爲了減輕Reduce端排序負載)。由於這些排序是MapReduce自動完成的,用戶無法控制,因此,在hadoop 1.x中無法避免,也不可以關閉,但hadoop2.x是可以關閉的。

 

4.      請簡述 mapreduce 中,combiner,partition 作用?

解答:

combiner是reduce的實現,在map端運行計算任務,減少map端的輸出數據。

作用就是優化。

但是combiner的使用場景是mapreduce的map輸出結果和reduce輸入輸出一樣。

 

partition的默認實現是hashpartition,是map端將數據按照reduce個數取餘,進行分區,不同的reduce來copy自己的數據。

partition的作用是將數據分到不同的reduce進行計算,加快計算效果。

 

 

1、combiner最基本是實現本地key的聚合,對map輸出的key排序,value進行迭代。如下所示:

  map: (K1, V1) → list(K2, V2)

  combine: (K2, list(V2)) → list(K2, V2)

  reduce: (K2, list(V2)) → list(K3, V3)

  2、combiner還具有類似本地的reduce功能.

  例如hadoop自帶的wordcount的例子和找出value的最大值的程序,combiner和reduce完全一致。如下所示:

  map: (K1, V1) → list(K2, V2)

  combine: (K2, list(V2)) → list(K3, V3)

  reduce: (K3, list(V3)) → list(K4, V4)

  3、如果不用combiner,那麼,所有的結果都是reduce完成,效率會相對低下。使用combiner,先完成的map會在本地聚合,提升速度。

  4、對於hadoop自帶的wordcount的例子,value就是一個疊加的數字,所以map一結束就可以進行reduce的value疊加,而不必要等到所有的map結束再去進行reduce的value疊加。

  combiner使用的合適,可以在滿足業務的情況下提升job的速度,如果不合適,則將導致輸出的結果不正確。

 

5.      解釋―hadoop‖和―hadoop 生態系統‖兩個概念

解答:

6.      說明 Hadoop 2.0 的基本構成

解答:

分別說明hdfs,yarn,mapreduce

7.      相比於 HDFS1.0,HDFS 2.0 最主要的改進在哪幾方面?

解答:

8.      試使用―步驟 1,步驟 2,步驟 3…..‖說明 YARN 中運行應用程序的基本流程

解答:

9.      ―MapReduce 2.0‖與―YARN‖是否等同,嘗試解釋說明

解答:

10.  MapReduce 2.0 中,MRAppMaster 主要作用是什麼,MRAppMaster如何實現任務容錯的?

解答:

11.  hdfs 原理,以及各個模塊的職責

解答:

12.  mr 的工作原理

解答:

Map—combiner—partition—sort—copy—sort—grouping—reduce

13.  map 方法是如何調用 reduce 方法的

解答:

14.  shell 如何判斷文件是否存在,如果不存在該如何處理?

解答:

15.  fsimage 和 edit 的區別?

解答:

16.  hadoop1 和 hadoop2 的區別?

解答:

17.  hdfs 中的 block 默認報錯幾份?

解答:

18.  哪個程序通常與 nn 在一個節點啓動?並做分析

解答:

19.  列舉幾個配置文件優化?

解答:

20.  datanode 首次加入 cluster 的時候,如果 log 報告不兼容文件版本,那需要 namenode 執行格式化操作,這樣處理的原因是?

解答:

21.  用mapreduce怎麼處理數據傾斜問題?

解答:

數據傾斜:map /reduce程序執行時,reduce節點大部分執行完畢,但是有一個或者幾個reduce節點運行很慢,導致整個程序的處理時間很長,這是因爲某一個key的條數比其他key多很多(有時是百倍或者千倍之多),這條key所在的reduce節點所處理的數據量比其他節點就大很多,從而導致某幾個節點遲遲運行不完,此稱之爲數據傾斜。

 

用hadoop程序進行數據關聯時,常碰到數據傾斜的情況,這裏提供一種解決方法。

自己實現partition類,用key和value相加取hash值:

方式1:

源代碼:

public int getPartition(K key, V value,

                          int numReduceTasks) {

    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;

  }

修改後

public int getPartition(K key, V value,

                          int numReduceTasks) {

    return ((key).hashCode()+value.hashCode() & Integer.MAX_VALUE) % numReduceTasks;

  }

 

方式2:

public class HashPartitioner<K, V> extends Partitioner<K, V> {

private int aa= 0;

  /** Use {@link Object#hashCode()} to partition. */

  public int getPartition(K key, V value,

                          int numReduceTasks) {

    return (key.hashCode()+(aa++) & Integer.MAX_VALUE) % numReduceTasks;

  }

 

 

22.  談談數據傾斜,如何發生的,並給出優化方案

解答:

23.  mapreduce 基本執行過程

解答:

24.  談談 hadoop1 和 hadoop2 的區別

解答:

25.  hadoop中Combiner的作用?

解答:

combiner是reduce的實現,在map端運行計算任務,減少map端的輸出數據。

作用就是優化。

但是combiner的使用場景是mapreduce的map和reduce輸入輸出一樣。

26.  Mapreduce 的 map 數量 和 reduce 數量 怎麼確定 ,怎麼配置

解答:

map的數量有數據塊決定,reduce數量隨便配置。

27.  在hadoop中文件的壓縮帶來了兩大好處:

解答:

(1)它減少了存儲文件所需的空間;

(2)加快了數據在網絡上或者從磁盤上或到磁盤上的傳輸速度;

28.  mapreduce的調度模式

解答:

一個MapReduce作業的生命週期大體分爲5個階段 【1】 :

1. 作業提交與初始化

2. 任務調度與監控

3. 任務運行環境準備

4. 任務執行

5. 作業完成

我們假設JobTracker已經啓動,那麼調度器是怎麼啓動的?JobTracker在啓動時有以下代碼:

JobTracker tracker = startTracker(new JobConf());

tracker.offerService();

其中offerService方法負責啓動JobTracker提供的各個服務,有這樣一行代碼:

taskScheduler.start();

taskScheduler即爲任務調度器。start方法是抽象類TaskScheduler提供的接口,用於啓動調度器。每個調度器類都要繼承TaskScheduler類。回憶一下,調度器啓動時會將各個監聽器對象註冊到JobTracker,以FIFO調度器JobQueueTaskScheduler爲例:

@Override

  public synchronized void start() throws IOException {

    super.start();

    taskTrackerManager.addJobInProgressListener(jobQueueJobInProgressListener);

    eagerTaskInitializationListener.setTaskTrackerManager(taskTrackerManager);

    eagerTaskInitializationListener.start();

    taskTrackerManager.addJobInProgressListener(

        eagerTaskInitializationListener);

  }

這裏註冊了兩個監聽器,其中eagerTaskInitializationListener負責作業初始化,而jobQueueJobInProgressListener則負責作業的執行和監控。當有作業提交到JobTracker時,JobTracker會執行所有訂閱它消息的監聽器的jobAdded方法。對於eagerTaskInitializationListener來說: 

@Override

  public void jobAdded(JobInProgress job) {

    synchronized (jobInitQueue) {

      jobInitQueue.add(job);

      resortInitQueue();

      jobInitQueue.notifyAll();

    }

  }

提交的作業的JobInProgress對象被添加到作業初始化隊列jobInitQueue中,並喚醒初始化線程(若原來沒有作業可以初始化):

class JobInitManager implements Runnable {

    public void run() {

      JobInProgress job = null;

      while (true) {

        try {

          synchronized (jobInitQueue) {

            while (jobInitQueue.isEmpty()) {

              jobInitQueue.wait();

            }

            job = jobInitQueue.remove(0);

          }

          threadPool.execute(new InitJob(job));

        } catch (InterruptedException t) {

          LOG.info("JobInitManagerThread interrupted.");

          break;

        }

      }

      threadPool.shutdownNow();

    }

  }

這種工作方式是一種“生產者-消費者”模式:作業初始化線程是消費者,而監聽器eagerTaskInitializationListener是生產者。這裏可以有多個消費者線程,放到一個固定資源的線程池中,線程個數通過mapred.jobinit.threads參數配置,默認爲4個。

下面我們重點來看調度器中的另一個監聽器。 jobQueueJobInProgressListener對象在調度器中初始化時連續執行了兩個構造器完成初始化:

public JobQueueJobInProgressListener() {

    this(new TreeMap<JobSchedulingInfo,

                     JobInProgress>(FIFO_JOB_QUEUE_COMPARATOR));

  }

  /**

   * For clients that want to provide their own job priorities.

   * @param jobQueue A collection whose iterator returns jobs in priority order.

   */

  protected JobQueueJobInProgressListener(Map<JobSchedulingInfo,

                                          JobInProgress> jobQueue) {

    this.jobQueue = Collections.synchronizedMap(jobQueue);

  }

其中,第一個構造器調用重載的第二個構造器。可以看到,調度器使用一個隊列jobQueue來保存提交的作業。這個隊列使用一個TreeMap對象實現,TreeMap的特點是底層使用紅黑樹實現,可以按照鍵來排序,並且由於是平衡樹,效率較高。作爲鍵的是一個JobSchedulingInfo對象,作爲值就是提交的作業對應的JobInProgress對象。另外,由於TreeMap本身不是線程安全的,這裏使用了集合類的同步方法構造了一個線程安全的Map。使用帶有排序功能的數據結構的目的是使作業在隊列中按照優先級的大小排列,這樣每次調度器只需從隊列頭部獲得作業即可。

作業的順序由優先級決定,而優先級信息包含在JobSchedulingInfo對象中:

static class JobSchedulingInfo {

    private JobPriority priority;

    private long startTime;

    private JobID id;

...

}

該對象包含了作業的優先級、ID和開始時間等信息。在Hadoop中,作業的優先級有以下五種:VERY_HIGH、HIGH、NORMAL、LOW、VERY_LOW。這些字段是通過作業的JobStatus對象初始化的。由於該對象作爲TreeMap的鍵,因此要實現自己的equals方法和hashCode方法:

@Override

    public boolean equals(Object obj) {

      if (obj == null || obj.getClass() != JobSchedulingInfo.class) {

        return false;

      } else if (obj == this) {

        return true;

      }

      else if (obj instanceof JobSchedulingInfo) {

        JobSchedulingInfo that = (JobSchedulingInfo)obj;

        return (this.id.equals(that.id) &&

                this.startTime == that.startTime &&

                this.priority == that.priority);

      }

      return false;

    }

我們看到,兩個JobSchedulingInfo對象相等的條件是類型一致,並且作業ID、開始時間和優先級都相等。hashCode的計算比較簡單:

@Override

    public int hashCode() {

      return (int)(id.hashCode() * priority.hashCode() + startTime);

    }

注意,監聽器的第一個構造器有一個比較器參數,用於定義 JobSchedulingInfo的比較方式:

static final Comparator<JobSchedulingInfo> FIFO_JOB_QUEUE_COMPARATOR

    = new Comparator<JobSchedulingInfo>() {

    public int compare(JobSchedulingInfo o1, JobSchedulingInfo o2) {

      int res = o1.getPriority().compareTo(o2.getPriority());

      if (res == 0) {

        if (o1.getStartTime() < o2.getStartTime()) {

          res = -1;

        } else {

          res = (o1.getStartTime() == o2.getStartTime() ? 0 : 1);

       }

      }

      if (res == 0) {

        res = o1.getJobID().compareTo(o2.getJobID());

      }

      return res;

    }

  };

從上面看出,首先比較作業的優先級,若優先級相等則比較開始時間(FIFO),若再相等則比較作業ID。 我們在實現自己的調度器時可能要定義自己的作業隊列,那麼作業在隊列中的順序(即 JobSchedulingInfo的比較器 )就要仔細定義,這是調度器能夠正常運行基礎。

Hadoop中的作業調度採用pull方式,即TaskTracker定時向JobTracker發送心跳信息索取一個新的任務,這些信息包括數據結點上作業和任務的運行情況,以及該TaskTracker上的資源使用情況。JobTracker會依據以上信息更新作業隊列的狀態,並調用調度器選擇一個或多個任務以心跳響應的形式返回給TaskTracker。從上面描述可以看出,JobTracker和taskScheduler之間的互相利用關係:前者利用後者爲TaskTracker分配任務;後者利用前者更新隊列和作業信息。接下來,我們一步步詳述該過程。

首先,當一個心跳到達JobTracker時(實際上這是一個來自TaskTracker的遠程過程調用 heartbeat方法 ,協議接口是InterTrackerProtocol),會執行兩種動作:更新狀態和下達命令 【1】 。下達命令稍後關注。有關更新狀態的一些代碼片段如下:

if (!processHeartbeat(status, initialContact, now)) {

      if (prevHeartbeatResponse != null) {

        trackerToHeartbeatResponseMap.remove(trackerName);

      }

      return new HeartbeatResponse(newResponseId,

                   new TaskTrackerAction[] {new ReinitTrackerAction()});

    }

具體的心跳處理,由私有函數processHeartbeat完成。該函數中有以下兩個方法調用:

updateTaskStatuses(trackerStatus);

    updateNodeHealthStatus(trackerStatus, timeStamp);

分別用來更新任務的狀態和結點的健康狀態。在第一個方法中有下面代碼片段:

TaskInProgress tip = taskidToTIPMap.get(taskId);

      // Check if the tip is known to the jobtracker. In case of a restarted

      // jt, some tasks might join in later

      if (tip != null || hasRestarted()) {

        if (tip == null) {

          tip = job.getTaskInProgress(taskId.getTaskID());

          job.addRunningTaskToTIP(tip, taskId, status, false);

        }

       

        // Update the job and inform the listeners if necessary

        JobStatus prevStatus = (JobStatus)job.getStatus().clone();

        // Clone TaskStatus object here, because JobInProgress

        // or TaskInProgress can modify this object and

        // the changes should not get reflected in TaskTrackerStatus.

        // An old TaskTrackerStatus is used later in countMapTasks, etc.

        job.updateTaskStatus(tip, (TaskStatus)report.clone());

        JobStatus newStatus = (JobStatus)job.getStatus().clone();

        // Update the listeners if an incomplete job completes

        if (prevStatus.getRunState() != newStatus.getRunState()) {

          JobStatusChangeEvent event =

            new JobStatusChangeEvent(job, EventType.RUN_STATE_CHANGED,

                                     prevStatus, newStatus);

          updateJobInProgressListeners(event);

        }

      } else {

        LOG.info("Serious problem.  While updating status, cannot find taskid "

                 + report.getTaskID());

      }

這裏的job對象通過從TaskTracker那裏得到的task狀態信息中抽取出來。注意,這裏拷貝了原有作業狀態的一個副本,然後修改這個副本的相關信息,調用的是updateJobStatus方法,更新任務的狀態信息和JobInProgress的相關信息,如map和reduce任務的進度等,這裏不展開了。這些信息的更新可以爲調度器的工作提供依據。

作業狀態的更新是通過updateJobInProgressListeners方法實現,該方法的參數是一個JobStatusChangeEvent對象,表示作業狀態變化的事件。這種事件的類型可以是運行狀態改變、開始時間改變、優先級改變等等。用戶也可以根據需要自定義事件類型。事件對象維護了兩個JobStatus對象,分別表示事件發生前後作業的狀態。 
進入該方法後,我們又看到了熟悉的觀察者模式:

// Update the listeners about the job

  // Assuming JobTracker is locked on entry.

  private void updateJobInProgressListeners(JobChangeEvent event) {

    for (JobInProgressListener listener : jobInProgressListeners) {

      listener.jobUpdated(event);

    }

  }

這次每個監聽器要回調jobUpdated方法,表示作業有更新。對於jobQueueJobInProgressListener來說是這樣做的:

@Override

  public synchronized void jobUpdated(JobChangeEvent event) {

    JobInProgress job = event.getJobInProgress();

    if (event instanceof JobStatusChangeEvent) {

      // Check if the ordering of the job has changed

      // For now priority and start-time can change the job ordering

      JobStatusChangeEvent statusEvent = (JobStatusChangeEvent)event;

      JobSchedulingInfo oldInfo = 

        new JobSchedulingInfo(statusEvent.getOldStatus());

      if (statusEvent.getEventType() == EventType.PRIORITY_CHANGED

          || statusEvent.getEventType() == EventType.START_TIME_CHANGED) {

        // Make a priority change

        reorderJobs(job, oldInfo);

      } else if (statusEvent.getEventType() == EventType.RUN_STATE_CHANGED) {

        // Check if the job is complete

        int runState = statusEvent.getNewStatus().getRunState();

        if (runState == JobStatus.SUCCEEDED

            || runState == JobStatus.FAILED

            || runState == JobStatus.KILLED) {

          jobCompleted(oldInfo);

        }

      }

    }

  }

首先,獲取作業更新 前 的狀態。然後根據事件的類型,進行相應的處理。比如,如果優先級變化了,則要重新排列隊列中作業的順序。這裏直接取出原有作業,重新插入隊列。插入後,作業會自動重新排序,體現了TreeMap的優越性。再比如,如果作業狀態變爲完成,那麼就從隊列中刪除該作業。

private void reorderJobs(JobInProgress job, JobSchedulingInfo oldInfo) {

    synchronized (jobQueue) {

      jobQueue.remove(oldInfo);

      jobQueue.put(new JobSchedulingInfo(job), job);

    }

  }

下面就是調度器中最關鍵的一步了:任務選擇。此時,作業隊列中信息已經更新完畢,可以選擇一些任務返回給TaskTracker執行了。heartbeat方法接下來會有這樣的代碼:

List<Task> tasks = getSetupAndCleanupTasks(taskTrackerStatus);

  if (tasks == null ) {

    tasks = taskScheduler.assignTasks(taskTrackers.get(trackerName));

  }

如果不需要setup和cleanup,就說明需要選擇map或reduce任務。調用TaskScheduler的assignTasks方法完成任務選擇。由於篇幅限制,我打算將這部分內容放到下一篇文章中,並關注heartbeat中JobTracker下達的命令過程以及JobInProgress和TaskInProgress對調度有影響的一些字段。

 

 

29.  是

30.   

3.1.3  Hadoop使用

1.      hdfs寫流程

流程:

1.client鏈接namenode存數據

2.namenode記錄一條數據位置信息(元數據),告訴client存哪。

3.client用hdfs的api將數據塊(默認是64M)存儲到datanode上。

4.datanode將數據水平備份。並且備份完將反饋client。

5.client通知namenode存儲塊完畢。

6.namenode將元數據同步到內存中。

7.另一塊循環上面的過程。

 

2.      hdfs讀流程

流程:

1.client鏈接namenode,查看元數據,找到數據的存儲位置。

2.client通過hdfs的api併發讀取數據。

3.關閉連接。

 

3.      舉一個簡單的例子說明mapreduce是怎麼來運行的 ?

解答:

 

    Word count例子接口

============================

一個MapReduce作業(job)通常會把輸入的數據集切分爲若干獨立的數據塊,由map任務(task)以完全並行的方式處理它們。框架會對map的輸出先進行排序,然後把結果輸入給reduce任務。通常作業的輸入和輸出都會被存儲在文件系統中。整個框架負責任務的調度和監控,以及重新執行已經失敗的任務。

  通常,MapReduce框架和分佈式文件系統是運行在一組相同的節點上的,也就是說,計算節點和存儲節點通常在一起。這種配置允許框架在那些已經存好數據的節點上高效地調度任務,這可以使整個集羣的網絡帶寬被非常高效地利用。

  MapReduce框架由一個單獨的master JobTracker和每個集羣節點一個slave TaskTracker共同組成。master負責調度構成一個作業的所有任務,這些任務分佈在不同的slave上,master監控它們的執行,重新執行已經失敗的任務。而slave僅負責執行由master指派的任務

 

4.      用mapreduce來實現下面需求?現在有10個文件夾,每個文件夾都有1000000個url.現在讓你找出top1000000url。

 

5.      yarn流程

解答:

1)      用戶向YARN 中提交應用程序, 其中包括ApplicationMaster 程序、啓動ApplicationMaster 的命令、用戶程序等。

2)      ResourceManager 爲該應用程序分配第一個Container, 並與對應的NodeManager 通信,要求它在這個Container 中啓動應用程序的ApplicationMaster。

3)      ApplicationMaster 首先向ResourceManager 註冊, 這樣用戶可以直接通過ResourceManage 查看應用程序的運行狀態,然後它將爲各個任務申請資源,並監控它的運行狀態,直到運行結束,即重複步驟4~7。

4)      ApplicationMaster 採用輪詢的方式通過RPC 協議向ResourceManager 申請和領取資源。

5)      一旦ApplicationMaster 申請到資源後,便與對應的NodeManager 通信,要求它啓動任務。

6)      NodeManager 爲任務設置好運行環境(包括環境變量、JAR 包、二進制程序等)後,將任務啓動命令寫到一個腳本中,並通過運行該腳本啓動任務。

7)      各個任務通過某個RPC 協議向ApplicationMaster 彙報自己的狀態和進度,以讓ApplicationMaster 隨時掌握各個任務的運行狀態,從而可以在任務失敗時重新啓動任務。在應用程序運行過程中,用戶可隨時通過RPC 向ApplicationMaster 查詢應用程序的當前運行狀態。

8)      應用程序運行完成後,ApplicationMaster 向ResourceManager 註銷並關閉自己。

 

 

6.      的

7.      的

8.      的

9.      的

10.  的

11.   

12.   的

13.   

3.2     Hive敘述題

3.2.1  Hive基礎

1.      hive 有哪些方式保存元數據,各有哪些特點?

解答:

1、內存數據庫derby,安裝小,但是數據存在內存,不穩定

2、mysql數據庫,數據存儲模式可以自己設置,持久化好,查看方便。

2.      hive內部表和外部表的區別

解答:

內部表:加載數據到hive所在的hdfs目錄,刪除時,元數據和數據文件都刪除

外部表:不加載數據到hive所在的hdfs目錄,刪除時,只刪除表結構。

3.      生產環境中爲什麼建議使用外部表?

解答:

1、因爲外部表不會加載數據到hive,減少數據傳輸、數據還能共享。

2、hive不會修改數據,所以無需擔心數據的損壞

3、刪除表時,只刪除表結構、不刪除數據。

4.      你們數據庫怎麼導入hive 的,有沒有出現問題

解答:

在導入hive的時候,如果數據庫中有blob或者text字段,會報錯。有個參數limit

5.      簡述Hive中的虛擬列作用是什麼,使用它的注意事項

解答:

Hive提供了三個虛擬列:

INPUT__FILE__NAME

BLOCK__OFFSET__INSIDE__FILE

ROW__OFFSET__INSIDE__BLOCK

但ROW__OFFSET__INSIDE__BLOCK默認是不可用的,需要設置hive.exec.rowoffset爲true纔可以。可以用來排查有問題的輸入數據。

INPUT__FILE__NAME, mapper任務的輸出文件名。

BLOCK__OFFSET__INSIDE__FILE, 當前全局文件的偏移量。對於塊壓縮文件,就是當前塊的文件偏移量,即當前塊的第一個字節在文件中的偏移量。

hive> SELECT INPUT__FILE__NAME, BLOCK__OFFSET__INSIDE__FILE, line

 

> FROM hive_text WHERE line LIKE '%hive%' LIMIT 2;

 

har://file/user/hive/warehouse/hive_text/folder=docs/

 

data.har/user/hive/warehouse/hive_text/folder=docs/README.txt  2243

 

har://file/user/hive/warehouse/hive_text/folder=docs/

 

data.har/user/hive/warehouse/hive_text/folder=docs/README.txt  3646

 

6.      hive partition分區

解答:

分區表,動態分區

7.      insert into 和 override write區別?

解答:

insert into:將某一張表中的數據寫到另一張表中

override write:覆蓋之前的內容。

8.      假如一個分區的數據主部錯誤怎麼通過hivesql刪除hdfs

解答:

alter table ptable drop partition (daytime='20140911',city='bj');

元數據,數據文件都刪除,但目錄daytime= 20140911還在

 

9.      Hive裏面用什麼代替in查詢

解答:

提示:Hive中的left semi join替換sql中的in操作

 

10.  的

11.  的

12.   d

 

3.3     Hbase

3.3.1  Hbase基礎

1.      介紹一下 hbase 過濾器

解答:

2.      hbase 集羣安裝注意事項

解答:

3.      hbase的rowkey怎麼創建好?列族怎麼創建比較好?

解答:

hbase存儲時,數據按照Row key的字典序(byte order)排序存儲。設計key時,要充分排序存儲這個特性,將經常一起讀取的行存儲放到一起。(位置相關性)

一個列族在數據底層是一個文件,所以將經常一起查詢的列放到一個列族中,列族儘量少,減少文件的尋址時間。

因爲hbase是列式數據庫,列非表schema的一部分,所以在設計初期只需要考慮rowkey 和 columnFamily即可,rowkey有位置相關性,所以如果數據是練習查詢的,最好對同類數據加一個前綴,而每個columnFamily實際上在底層是一個文件,那麼文件越小,查詢越快,所以講經常一起查詢的列設計到一個列簇,但是列簇不宜過多。

 

 Rowkey長度原則

Rowkey是一個二進制碼流,Rowkey的長度被很多開發者建議說設計在10~100個字節,不過建議是越短越好,不要超過16個字節。

原因如下:

(1)數據的持久化文件HFile中是按照KeyValue存儲的,如果Rowkey過長比如100個字節,1000萬列數據光Rowkey就要佔用100*1000萬=10億個字節,將近1G數據,這會極大影響HFile的存儲效率;

(2)MemStore將緩存部分數據到內存,如果Rowkey字段過長內存的有效利用率會降低,系統將無法緩存更多的數據,這會降低檢索效率。因此Rowkey的字節長度越短越好。

(3)目前操作系統是都是64位系統,內存8字節對齊。控制在16個字節,8字節的整數倍利用操作系統的最佳特性。

Rowkey散列原則

如果Rowkey是按時間戳的方式遞增,不要將時間放在二進制碼的前面,建議將Rowkey的高位作爲散列字段,由程序循環生成,低位放時間字段,這樣將提高數據均衡分佈在每個Regionserver實現負載均衡的機率。如果沒有散列字段,首字段直接是時間信息將產生所有新數據都在一個 RegionServer上堆積的熱點現象,這樣在做數據檢索的時候負載將會集中在個別RegionServer,降低查詢效率。

Rowkey唯一原則

必須在設計上保證其唯一性。

4.      簡述Hbase性能優化的思路

解答:

1、在庫表設計的時候,儘量考慮rowkey和columnfamily的特性

2、進行hbase集羣的調優

5.      簡述Hbase filter的實現原理是什麼?結合實際項目經驗,寫出幾個使用filter的場景。

解答:

hbase的filter是通過scan設置的,所以是基於scan的查詢結果進行過濾。

1.在進行訂單開發的時候,我們使用rowkeyfilter過濾出某個用戶的所有訂單

2.在進行雲筆記開發時,我們使用rowkey過濾器進行redis數據的恢復。

6.      ROWKEY的後綴匹配怎麼實現?列如ROWKEY是yyyyMMDD-UserID形式,如UserID爲條件查詢數據,怎麼實現。

解答:

 

7.      HBase的檢索支持3種方式:

解答:

(1) 通過單個Rowkey訪問,即按照某個Rowkey鍵值進行get操作,這樣獲取唯一一條記錄;

(2) 通過Rowkey的range進行scan,即通過設置startRowKey和endRowKey,在這個範圍內進行掃描。這樣可以按指定的條件獲取一批記錄;

(3) 全表掃描,即直接掃描整張表中所有行記錄。

 

8.      簡述HBase的瓶頸

解答:

HBase的瓶頸就是硬盤傳輸速度。HBase的操作,它可以往數據裏面insert,也可以update一些數據,但update的實際上也是insert,只是插入一個新的時間戳的一行。Delete數據,也是insert,只是insert一行帶有delete標記的一行。Hbase的所有操作都是追加插入操作。Hbase是一種日誌集數據庫。它的存儲方式,像是日誌文件一樣。它是批量大量的往硬盤中寫,通常都是以文件形式的讀寫。這個讀寫速度,就取決於硬盤與機器之間的傳輸有多快。而Oracle的瓶頸是硬盤尋道時間。它經常的操作時隨機讀寫。要update一個數據,先要在硬盤中找到這個block,然後把它讀入內存,在內存中的緩存中修改,過段時間再回寫回去。由於你尋找的block不同,這就存在一個隨機的讀。硬盤的尋道時間主要由轉速來決定的。而尋道時間,技術基本沒有改變,這就形成了尋道時間瓶頸。

 

9.      Hbase內部是什麼機制?

解答:

在HMaster、RegionServer內部,創建了RpcServer實例,並與Client三者之間實現了Rpc調用,HBase0.95內部引入了Google-Protobuf作爲中間數據組織方式,並在Protobuf提供的Rpc接口之上,實現了基於服務的Rpc實現,本文詳細闡述了HBase-Rpc實現細節。

HBase的RPC Protocol

 在HMaster、RegionServer內部,實現了rpc 多個protocol來完成管理和應用邏輯,具體如下protocol如下:

HMaster支持的Rpc協議:
MasterMonitorProtocol,Client與Master之間的通信,Master是RpcServer端,主要實現HBase集羣監控的目的。

MasterAdminProtocol,Client與Master之間的通信,Master是RpcServer端,主要實現HBase表格的管理。例如TableSchema的更改,Table-Region的遷移、合併、下線(Offline)、上線(Online)以及負載平衡,以及Table的刪除、快照等相關功能。

RegionServerStatusProtoco,RegionServer與Master之間的通信,Master是RpcServer端,負責提供RegionServer向HMaster狀態彙報的服務。

RegionServer支持的Rpc協議:

ClientProtocol,Client與RegionServer之間的通信,RegionServer是RpcServer端,主要實現用戶的讀寫請求。例如get、multiGet、mutate、scan、bulkLoadHFile、執行Coprocessor等。

AdminProtocols,Client與RegionServer之間的通信,RegionServer是RpcServer端,主要實現Region、服務、文件的管理。例如storefile信息、Region的操作、WAL操作、Server的開關等。

(備註:以上提到的Client可以是用戶Api、也可以是RegionServer或者HMaster)

 

 HBase-RPC實現機制分析

RpcServer配置三個隊列:

1)普通隊列callQueue,絕大部分Call請求存在該隊列中:callQueue上maxQueueLength爲${ipc.server.max.callqueue.length},默認是${hbase.master.handler.count}*DEFAULT_MAX_CALLQUEUE_LENGTH_PER_HANDLER,目前0.95.1中,每個Handler上CallQueue的最大個數默認值(DEFAULT_MAX_CALLQUEUE_LENGTH_PER_HANDLER)爲10。

2)優先級隊列: PriorityQueue。如果設置priorityHandlerCount的個數,會創建與callQueue相當容量的queue存儲Call,該優先級隊列對應的Handler的個數由rpcServer實例化時傳入。

3)拷貝隊列:replicationQueue。由於RpcServer由HMaster和RegionServer共用,該功能僅爲RegionServer提供,queue的大小爲${ipc.server.max.callqueue.size}指定,默認爲1024*1024*1024,handler的個數爲hbase.regionserver.replication.handler.count。

RpcServer由三個模塊組成:

Listener ===Queue=== Responder

 

這裏以HBaseAdmin.listTables爲例,     分析一個Rpc請求的函數調用過程:

1) RpcClient創建一個BlockingRpcChannel。

2)以channel爲參數創建執行RPC請求需要的stub,此時的stub已經被封裝在具體Service下,stub下定義了可執行的rpc接口。

3)stub調用對應的接口,實際內部channel調用callBlockingMethod方法。

RpcClient內實現了protobuf提供的BlockingRpcChannel接口方法callBlockingMethod,  @OverridepublicMessage callBlockingMethod(MethodDescriptor md, RpcController controller,Message param, Message returnType)throwsServiceException {returnthis.rpcClient.callBlockingMethod(md, controller, param, returnType, this.ticket,this.isa, this.rpcTimeout);}

通過以上的實現細節,最終轉換成rpcClient的調用,使用MethodDescriptor封裝了不同rpc函數,使用Message基類可以接收基於Message的不同的Request和Response對象。

4)RpcClient創建Call對象,查找或者創建合適的Connection,並喚醒Connection。

5)Connection等待Call的Response,同時rpcClient調用函數中,會使用connection.writeRequest(Call call)將請求寫入到RpcServer網絡流中。

6)等待Call的Response,然後層層返回給更上層接口,從而完成此次RPC調用。

RPCServer收到的Rpc報文的內部組織如下:

Magic

(4Byte)

Version

(1Byte)

AuthMethod

(1Byte)

Connection

HeaderLength

(4Byte)

ConnectionHeader

Request

“HBas”

 

 

 

 

 

驗證RpcServer的CURRENT_VERSION

與RPC報文一致

目前支持三類:

AuthMethod.SIMPLE

AuthMethod.KERBEROS

AuthMethod.DIGEST

RPC.proto定義
RPCProtos.ConnectionHeader
message ConnectionHeader {
optional UserInformation userInfo = 1;
optional string serviceName = 2;
// Cell block codec we will use sending over optional cell blocks.  Server throws exception
// if cannot deal.
optional string cellBlockCodecClass = 3 [default = "org.apache.hadoop.hbase.codec.KeyValueCodec"];
// Compressor we will use if cell block is compressed.  Server will throw exception if not supported.
// Class must implement hadoop’s CompressionCodec Interface
optional string cellBlockCompressorClass = 4;
}
序列化之後的數據

 

 

 

整個Request存儲是經過編碼之後的byte數組,包括如下幾個部分:

RequestHeaderLength(RawVarint32)

RequestHeader

ParamSize(RawVarint32)

Param

CellScanner

RPC.proto定義:
message RequestHeader {
// Monotonically increasing callId to keep track of RPC requests and their response
optional uint32 callId = 1;
optional RPCTInfo traceInfo = 2;
optional string methodName = 3;
// If true, then a pb Message param follows.
optional bool requestParam = 4;
// If present, then an encoded data block follows.
optional CellBlockMeta cellBlockMeta = 5;
// TODO: Have client specify priority
}
序列化之後的數據
並從Header中確認是否存在Param和CellScanner,如果確認存在的情況下,會繼續訪問。

Protobuf的基本類型Message,
Request的Param繼承了Message,
這個需要獲取的Method類型決定。

 

 

 

從功能上講,RpcServer上包含了三個模塊,

1)Listener。包含了多個Reader線程,通過Selector獲取ServerSocketChannel接收來自RpcClient發送來的Connection,並從中重構Call實例,添加到CallQueue隊列中。

 ”IPC Server listener on 60021″ daemon prio=10 tid=0x00007f7210a97800 nid=0x14c6 runnable [0x00007f720e8d0000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
- locked <0x00000000c43cae68> (a sun.nio.ch.Util$2)
- locked <0x00000000c43cae50> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000c4322ca8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:84)
at org.apache.hadoop.hbase.ipc.RpcServer$Listener.run(RpcServer.java:646)

2)Handler。負責執行Call,調用Service的方法,然後返回Pair<Message,CellScanner>

“IPC Server handler 0 on 60021″ daemon prio=10 tid=0x00007f7210eab000 nid=0x14c7 waiting on condition [0x00007f720e7cf000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000000c43cad90> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:399)
at org.apache.hadoop.hbase.ipc.RpcServer$Handler.run(RpcServer.java:1804)

3) Responder。負責把Call的結果返回給RpcClient。

 ”IPC Server Responder” daemon prio=10 tid=0x00007f7210a97000 nid=0x14c5 runnable [0x00007f720e9d1000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
- locked <0x00000000c4407078> (a sun.nio.ch.Util$2)
- locked <0x00000000c4407060> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000c4345b68> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
at org.apache.hadoop.hbase.ipc.RpcServer$Responder.doRunLoop(RpcServer.java:833)
at org.apache.hadoop.hbase.ipc.RpcServer$Responder.run(RpcServer.java:816)

RpcClient爲Rpc請求建立Connection,通過Connection將Call發送RpcServer,然後RpcClient等待結果的返回。

 

 

10.  的

11.  的

12.  的

13.  的

14.  的

 

3.4     Zookeeper

1.      寫出你對 zookeeper 的理解

解答:

2.      的

3.      的

4.      的

3.5     Storm

1.      storm 如果碰上了複雜邏輯,需要算很長的時間,你怎麼去優化

解答:

拆分複雜的業務到多個bolt中,這樣可以利用bolt的tree將速度提升

提高並行度

2.      開發流程,容錯機制

解答:

開發流程:

寫主類(設計spout和bolt的分發機制)

寫spout收集數據

寫bolt處理數據,根據數據量和業務的複雜程度,設計並行度。

 

容錯機制:

採用ack和fail進行容錯,失敗的數據重新發送。

3.      storm和spark-streaming:爲什麼用storm不同spark-streaming

解答:

 

 

4.      的

5.      的

6.      的

7.      的

3.6     Flume

1.      flume管道內存,flume宕機了數據丟失怎麼解決

解答:

1、Flume的channel分爲很多種,可以將數據寫入到文件

2、防止非首個agent宕機的方法數可以做集羣或者主備

 

2.      flume配置方式,flume集羣(問的很詳細)

解答:

Flume的配置圍繞着source、channel、sink敘述,flume的集羣是做在agent上的,而非機器上。

 

3.      flume不採集Nginx日誌,通過Logger4j採集日誌,優缺點是什麼?

解答:

優點:Nginx的日誌格式是固定的,但是缺少sessionid,通過logger4j採集的日誌是帶有sessionid的,而session可以通過redis共享,保證了集羣日誌中的同一session落到不同的tomcat時,sessionId還是一樣的,而且logger4j的方式比較穩定,不會宕機。

缺點:不夠靈活,logger4j的方式和項目結合過於緊密,而flume的方式比較靈活,拔插式比較好,不會影響項目性能。

4.      flume和kafka採集日誌區別,採集日誌時中間停了,怎麼記錄之前的日誌。

解答:

Flume採集日誌是通過流的方式直接將日誌收集到存儲層,而kafka試講日誌緩存在kafka集羣,待後期可以採集到存儲層。

Flume採集中間停了,可以採用文件的方式記錄之前的日誌,而kafka是採用offset的方式記錄之前的日誌。

 

5.      的

6.      的

3.7     Kafka

1.      Kafka容錯機制

解答:

分區備份,存在主備partition

2.      kafka數據流向

解答:

Producer à leader partition à follower partition(半數以上) àconsumer

3.      kafka+spark-streaming結合丟數據怎麼解決?

解答:

spark streaming從1.2開始提供了數據的零丟失,想享受這個特性,需要滿足如下條件:

數據輸入需要可靠的sources和可靠的receivers

應用metadata必須通過應用driver checkpoint

WAL(write ahead log)

可靠的sources和receivers

spark streaming可以通過多種方式作爲數據sources(包括kafka),輸入數據通過receivers接收,通過replication存儲於spark中(爲了faultolerance,默認複製到兩個spark executors),如果數據複製完成,receivers可以知道(例如kafka中更新offsets到zookeeper中)。這樣當receivers在接收數據過程中crash掉,不會有數據丟失,receivers沒有複製的數據,當receiver恢復後重新接收。

metadata checkpoint

可靠的sources和receivers,可以使數據在receivers失敗後恢復,然而在driver失敗後恢復是比較複雜的,一種方法是通過checkpoint metadata到HDFS或者S3。metadata包括:

configuration

code

一些排隊等待處理但沒有完成的RDD(僅僅是metadata,而不是data)

這樣當driver失敗時,可以通過metadata checkpoint,重構應用程序並知道執行到那個地方。

數據可能丟失的場景

可靠的sources和receivers,以及metadata checkpoint也不可以保證數據的不丟失,例如:

兩個executor得到計算數據,並保存在他們的內存中

receivers知道數據已經輸入

executors開始計算數據

driver突然失敗

driver失敗,那麼executors都會被kill掉

因爲executor被kill掉,那麼他們內存中得數據都會丟失,但是這些數據不再被處理

executor中的數據不可恢復

WAL

爲了避免上面情景的出現,spark streaming 1.2引入了WAL。所有接收的數據通過receivers寫入HDFS或者S3中checkpoint目錄,這樣當driver失敗後,executor中數據丟失後,可以通過checkpoint恢復。

At-Least-Once

儘管WAL可以保證數據零丟失,但是不能保證exactly-once,例如下面場景:

Receivers接收完數據並保存到HDFS或S3

在更新offset前,receivers失敗了

Spark Streaming以爲數據接收成功,但是Kafka以爲數據沒有接收成功,因爲offset沒有更新到zookeeper

隨後receiver恢復了

從WAL可以讀取的數據重新消費一次,因爲使用的kafka High-Level消費API,從zookeeper中保存的offsets開始消費

WAL的缺點

通過上面描述,WAL有兩個缺點:

降低了receivers的性能,因爲數據還要存儲到HDFS等分佈式文件系統

對於一些resources,可能存在重複的數據,比如Kafka,在Kafka中存在一份數據,在Spark Streaming也存在一份(以WAL的形式存儲在hadoop API兼容的文件系統中)

Kafka direct API

爲了WAL的性能損失和exactly-once,spark streaming1.3中使用Kafka direct API。非常巧妙,Spark driver計算下個batch的offsets,指導executor消費對應的topics和partitions。消費Kafka消息,就像消費文件系統文件一樣。

不再需要kafka receivers,executor直接通過Kafka API消費數據

WAL不再需要,如果從失敗恢復,可以重新消費

exactly-once得到了保證,不會再從WAL中重複讀取數據

總結

主要說的是spark streaming通過各種方式來保證數據不丟失,並保證exactly-once,每個版本都是spark streaming越來越穩定,越來越向生產環境使用發展。

 

4.      kafka中存儲目錄data/dir.....topic1和topic2怎麼存儲的,存儲結構,data.....目錄下有多少個分區,每個分區的存儲格式是什麼樣的?

解答:

1、topic是按照“主題名-分區”存儲的

2、分區個數由配置文件決定

3、每個分區下最重要的兩個文件是0000000000.log和000000.index,0000000.log以默認1G大小回滾。

 

5.      的

6.      D 的

3.8     Spark

1.      mr和spark區別,怎麼理解spark-rdd

解答:

Mr是文件方式的分佈式計算框架,是將中間結果和最終結果記錄在文件中,map和reduce的數據分發也是在文件中。

spark是內存迭代式的計算框架,計算的中間結果可以緩存內存,也可以緩存硬盤,但是不是每一步計算都需要緩存的。

Spark-rdd是一個數據的分區記錄集合………………

2.      Spark應用轉換流程

解答:

1、spark應用提交後,經歷了一系列的轉換,最後成爲task在每個節點上執行

2、RDD的Action算子觸發Job的提交,生成RDD DAG

3、由DAGScheduler將RDD DAG轉化爲Stage DAG,每個Stage中產生相應的Task集合

4、TaskScheduler將任務分發到Executor執行

5、每個任務對應相應的一個數據塊,只用用戶定義的函數處理數據塊

3.      Driver運行在Worker上

解答:

通過org.apache.spark.deploy.Client類執行作業,作業運行命令如下:

作業執行流程描述:

1、客戶端提交作業給Master

2、Master讓一個Worker啓動Driver,即SchedulerBackend。Worker創建一個DriverRunner線程,DriverRunner啓動SchedulerBackend進程。

3、另外Master還會讓其餘Worker啓動Exeuctor,即ExecutorBackend。Worker創建一個ExecutorRunner線程,ExecutorRunner會啓動ExecutorBackend進程。

4、ExecutorBackend啓動後會向Driver的SchedulerBackend註冊。SchedulerBackend進程中包含DAGScheduler,它會根據用戶程序,生成執行計劃,並調度執行。對於每個stage的task,都會被存放到TaskScheduler中,ExecutorBackend向SchedulerBackend彙報的時候把TaskScheduler中的task調度到ExecutorBackend執行。

5、所有stage都完成後作業結束。

 

4.      Driver運行在客戶端

解答:

作業執行流程描述:

1、客戶端啓動後直接運行用戶程序,啓動Driver相關的工作:DAGScheduler和BlockManagerMaster等。

2、客戶端的Driver向Master註冊。

3、Master還會讓Worker啓動Exeuctor。Worker創建一個ExecutorRunner線程,ExecutorRunner會啓動ExecutorBackend進程。

4、ExecutorBackend啓動後會向Driver的SchedulerBackend註冊。Driver的DAGScheduler解析作業並生成相應的Stage,每個Stage包含的Task通過TaskScheduler分配給Executor執行。

5、所有stage都完成後作業結束。

 

5.      的

6.      的

7.      的

8.      的

3.9     Sqoop

1.      命令:

sqoop import --connect jdbc:mysql://192.168.56.204:3306/sqoop --username hive --password hive --table jobinfo --target-dir /sqoop/test7 --inline-lob-limit 16777216 --fields-terminated-by '\t' -m 2

 

sqoop create-hive-table --connect jdbc:mysql://192.168.56.204:3306/sqoop --table jobinfo --username hive --password hive --hive-table sqtest --fields-terminated-by "\t" --lines-terminated-by "\n";

2.      sqoop在導入數據到mysql中,如何讓數據不重複導入?如果存在數據問題sqoop如何處理?

解答:

Sqoop是一個用來將Hadoop和關係型數據庫中的數據相互轉移的工具,可以將一個關係型數據庫(例如 : MySQL ,Oracle ,Postgres等)中的數據導進到Hadoop的HDFS中,也可以將HDFS的數據導進到關係型數據庫中。

 

首先需以下要準備:

第一:hadoop的NameNode節點下lib文件夾中要有相應數據庫驅動的jar包和sqoop的jar包。

第二:預先在相應的數據庫創建Table,注:在HDFS的某個目錄上的數據格式要和相應的表中的字段數量一致。

 

由於我這裏使用的是Oracle數據庫並且是使用Java來操作的。所以下面的代碼以及截圖都是以Java的例子:

首先標準化HDFS中文件格式,如下圖:

 

Java代碼如下:

Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://192.168.115.5:9000");
conf.set("hadoop.job.ugi", "hadooper,hadoopgroup");
conf.set("mapred.job.tracker", "192.168.115.5:9001");


ArrayList<String> list = new ArrayList<String>(); // 定義一個list
list.add("--table");
list.add("A_BAAT_CLIENT"); // Oracle中的表。將來數據要導入到這個表中。
list.add("--export-dir");
list.add("/home/hadoop/traffic/capuse/near7date/activeUser/capuse_near7_activeUser_2013-02-06.log"); // hdfs上的目錄。這個目錄下的數據要導入到a_baat_client這個表中。
list.add("--connect");
list.add("jdbc:oracle:thin:@10.18.96.107:1521:life"); // Oracle的鏈接
list.add("--username");
list.add("TRAFFIC"); // Oracle的用戶名
list.add("--password");
list.add("TRAFFIC"); // Oracle的密碼
list.add("--input-fields-terminated-by");
list.add("|"); // 數據分隔符號
list.add("-m");
list.add("1");// 定義mapreduce的數量。


String[] arg = new String[1];
ExportTool exporter = new ExportTool();
Sqoop sqoop = new Sqoop(exporter);
sqoop.setConf(conf);
arg = list.toArray(new String[0]);
int result = Sqoop.runSqoop(sqoop, arg);
System.out.println("res:" + result); // 打印執行結果。

 

最後再在Main方法中運行即可,生成後表數據如下圖所示:

通過上面的操作以及代碼即可在Java中實現把HDFS數據生成對應的表數據;

不過除了可以用Java來實現,使用基本的命令也是可以的,命令如下:

在Hadoop bin目錄中:

sqoop export --connect jdbc:oracle:thin:@10.18.96.107:1521:life \

--table A_BAAT_CLIENT --username TRAFFIC --password TRAFFIC \
--input-fields-terminated-by '|' \
--export-dir /home/hadoop/traffic/capuse/near7date/activeUser/test.log  -m 1

意思和上面Java中代碼一樣。

 

注意:

1、數據庫表名、用戶名、密碼使用大寫(這有可能會出現問題,因爲我在測試過程中,使用小寫時出現錯誤,出現No Columns這個經典錯誤。所以推薦大寫,當然這不是必須);

2、預先建好相應的Table;

 

 

3.      

4.      

5.      

6.      

3.10其他

3.10.1 Redis

1.      Redis,傳統數據庫,hbase,hive 每個之間的區別

解答:

redis:分佈式緩存,強調緩存,內存中數據

傳統數據庫:注重關係

hbase:列式數據庫,無法做關係數據庫的主外鍵,用於存儲海量數據,底層基於hdfs

hive:數據倉庫工具,底層是mapreduce。不是數據庫,不能用來做用戶的交互存儲

 

 

2.      是

3.10.2 數據庫

1.      反向索引

解答:

倒排索引(Inverted index)

適用範圍:搜索引擎,關鍵字查詢

基本原理及要點:爲何叫倒排索引?一種索引方法,被用來存儲在全文搜索下某個單詞在一個文檔或者一組文檔中的存儲位置的映射。

以英文爲例,下面是要被索引的文本:

T0 = “it is what it is”

T1 = “what is it”

T2 = “it is a banana”

我們就能得到下面的反向文件索引:

“a”: {2}

“banana”: {2}

“is”: {0, 1, 2}

“it”: {0, 1, 2}

“what”: {0, 1}

檢索的條件”what”,”is”和”it”將對應集合的交集。

正向索引開發出來用來存儲每個文檔的單詞的列表。正向索引的查詢往往滿足每個文檔有序 頻繁的全文查詢和每個單詞在校驗文檔中的驗證這樣的查詢。在正向索引中,文檔佔據了中心的位置,每個文檔指向了一個它所包含的索引項的序列。也就是說文檔指向了它包含的那些單詞,而反向索引則是單詞指向了包含它的文檔,很容易看到這個反向的關係。

 

 

2.      數據庫的三大範式?

解答:

數據庫範式1NF 2NF 3NF BCNF(實例)
    設計範式(範式,數據庫設計範式,數據庫的設計範式)是符合某一種級別的關係模式的集合。構造數據庫必須遵循一定的規則。在關係數據庫中,這種規則就是範式。關係數據庫中的關係必須滿足一定的要求,即滿足不同的範式。目前關係數據庫有六種範式:第一範式(1NF)、第二範式(2NF)、第三範式(3NF)、第四範式(4NF)、第五範式(5NF)和第六範式(6NF)。滿足最低要求的範式是第一範式(1NF)。在第一範式的基礎上進一步滿足更多要求的稱爲第二範式(2NF),其餘範式以次類推。一般說來,數據庫只需滿足第三範式(3NF)就行了。下面我們舉例介紹第一範式(1NF)、第二範式(2NF)和第三範式(3NF)。
    在創建一個數據庫的過程中,範化是將其轉化爲一些表的過程,這種方法可以使從數據庫得到的結果更加明確。這樣可能使數據庫產生重複數據,從而導致創建多餘的表。範化是在識別數據庫中的數據元素、關係,以及定義所需的表和各表中的項目這些初始工作之後的一個細化的過程。
    下面是範化的一個例子 Customer Item purchased Purchase price Thomas Shirt $40 Maria Tennis shoes $35 Evelyn Shirt $40 Pajaro Trousers $25
如果上面這個表用於保存物品的價格,而你想要刪除其中的一個顧客,這時你就必須同時刪除一個價格。範化就是要解決這個問題,你可以將這個表化爲兩個表,一個用於存儲每個顧客和他所買物品的信息,另一個用於存儲每件產品和其價格的信息,這樣對其中一個表做添加或刪除操作就不會影響另一個表。

關係數據庫的幾種設計範式介紹

1 第一範式(1NF)
    在任何一個關係數據庫中,第一範式(1NF)是對關係模式的基本要求,不滿足第一範式(1NF)的數據庫就不是關係數據庫。
    所謂第一範式(1NF)是指數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重複的屬性。如果出現重複的屬性,就可能需要定義一個新的實體,新的實體由重複的屬性構成,新實體與原實體之間爲一對多關係。在第一範式(1NF)中表的每一行只包含一個實例的信息。例如,對於圖3-2 中的員工信息表,不能將員工信息都放在一列中顯示,也不能將其中的兩列或多列在一列中顯示;員工信息表的每一行只表示一個員工的信息,一個員工的信息在表中只出現一次。簡而言之,第一範式就是無重複的列。

2 第二範式(2NF)
    第二範式(2NF)是在第一範式(1NF)的基礎上建立起來的,即滿足第二範式(2NF)必須先滿足第一範式(1NF)。第二範式(2NF)要求數據庫表中的每個實例或行必須可以被惟一地區分。爲實現區分通常需要爲表加上一個列,以存儲各個實例的惟一標識。如圖3-2 員工信息表中加上了員工編號(emp_id)列,因爲每個員工的員工編號是惟一的,因此每個員工可以被惟一區分。這個惟一屬性列被稱爲主關鍵字或主鍵、主碼。
第二範式(2NF)要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關係。爲實現區分通常需要爲表加上一個列,以存儲各個實例的惟一標識。簡而言之,第二範式就是非主屬性非部分依賴於主關鍵字。

3 第三範式(3NF)
    滿足第三範式(3NF)必須先滿足第二範式(2NF)。簡而言之,第三範式(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息。例如,存在一個部門信息表,其中每個部門有部門編號(dept_id)、部門名稱、部門簡介等信息。那麼在圖3-2的員工信息表中列出部門編號後就不能再將部門名稱、部門簡介等與部門有關的信息再加入員工信息表中。如果不存在部門信息表,則根據第三範式(3NF)也應該構建它,否則就會有大量的數據冗餘。簡而言之,第三範式就是屬性不依賴於其它非主屬性。
數據庫設計三大範式應用實例剖析

     數據庫的設計範式是數據庫設計所需要滿足的規範,滿足這些規範的數據庫是簡潔的、結構明晰的,同時,不會發生插入(insert)、刪除(delete)和更新(update)操作異常。反之則是亂七八糟,不僅給數據庫的編程人員製造麻煩,而且面目可憎,可能存儲了大量不需要的冗餘信息。
    設計範式是不是很難懂呢?非也,大學教材上給我們一堆數學公式我們當然看不懂,也記不住。所以我們很多人就根本不按照範式來設計數據庫。
實質上,設計範式用很形象、很簡潔的話語就能說清楚,道明白。本文將對範式進行通俗地說明,並以筆者曾經設計的一個簡單論壇的數據庫爲例來講解怎樣將這些範式應用於實際工程。

範式說明
    第一範式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。

    例如,如下的數據庫表是符合第一範式的:

    字段1 字段2 字段3 字段4

    而這樣的數據庫表是不符合第一範式的:

    字段1 字段2 字段3 字段4
    字段3.1 字段3.2 

    很顯然,在當前的任何關係數據庫管理系統(DBMS)中,傻瓜也不可能做出不符合第一範式的數據庫,因爲這些DBMS不允許你把數據庫表的一列再分成二列或多列。因此,你想在現有的DBMS中設計出不符合第一範式的數據庫都是不可能的。 
    第二範式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些字段決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴於任意一組候選關鍵字。

    假定選課關係表爲SelectCourse(學號, 姓名, 年齡, 課程名稱, 成績, 學分),關鍵字爲組合關鍵字(學號, 課程名稱),因爲存在如下決定關係:
    (學號, 課程名稱) → (姓名, 年齡, 成績, 學分) 

    這個數據庫表不滿足第二範式,因爲存在如下決定關係:
    (課程名稱) → (學分)
    (學號) → (姓名, 年齡)
    即存在組合關鍵字中的字段決定非關鍵字的情況。 
    由於不符合2NF,這個選課關係表會存在如下問題:
    (1) 數據冗餘:
    同一門課程由n個學生選修,"學分"就重複n-1次;同一個學生選修了m門課程,姓名和年齡就重複了m-1次。
    (2) 更新異常:
    若調整了某門課程的學分,數據表中所有行的"學分"值都要更新,否則會出現同一門課程學分不同的情況。
    (3) 插入異常:
    假設要開設一門新的課程,暫時還沒有人選修。這樣,由於還沒有"學號"關鍵字,課程名稱和學分也無法記錄入數據庫。
    (4) 刪除異常:
    假設一批學生已經完成課程的選修,這些選修記錄就應該從數據庫表中刪除。但是,與此同時,課程名稱和學分信息也被刪除了。很顯然,這也會導致插入異常。
    把選課關係表SelectCourse改爲如下三個表:
    學生:Student(學號, 姓名, 年齡);
    課程:Course(課程名稱, 學分);
    選課關係:SelectCourse(學號, 課程名稱, 成績)。
    這樣的數據庫表是符合第二範式的, 消除了數據冗餘、更新異常、插入異常和刪除異常。
    另外,所有單關鍵字的數據庫表都符合第二範式,因爲不可能存在組合關鍵字。

    第三範式(3NF):在第二範式的基礎上,數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三範式。所謂傳遞函數依賴,指的是如果存在"A → B → C"的決定關係,則C傳遞函數依賴於A。因此,滿足第三範式的數據庫表應該不存在如下依賴關係:
    關鍵字段 → 非關鍵字段x → 非關鍵字段y
    假定學生關係表爲Student(學號, 姓名, 年齡, 所在學院, 學院地點, 學院電話),關鍵字爲單一關鍵字"學號",因爲存在如下決定關係:
    (學號) → (姓名, 年齡, 所在學院, 學院地點, 學院電話)
    這個數據庫是符合2NF的,但是不符合3NF,因爲存在如下決定關係:
    (學號) → (所在學院) → (學院地點, 學院電話)
    即存在非關鍵字段"學院地點"、"學院電話"對關鍵字段"學號"的傳遞函數依賴。   
    它也會存在數據冗餘、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
    把學生關係表分爲如下兩個表:
    學生:(學號, 姓名, 年齡, 所在學院);
   學院:(學院, 地點, 電話)。 

    這樣的數據庫表是符合第三範式的,消除了數據冗餘、更新異常、插入異常和刪除異常。
鮑依斯-科得範式(BCNF):在第三範式的基礎上,數據庫表中如果不存在任何字段對任一候選關鍵字段的傳遞函數依賴則符合第三範式。
    假設倉庫管理關係表爲StorehouseManage(倉庫ID, 存儲物品ID, 管理員ID, 數量),且有一個管理員只在一個倉庫工作;一個倉庫可以存儲多種物品。這個數據庫表中存在如下決定關係:
    (倉庫ID, 存儲物品ID) →(管理員ID, 數量)
    (管理員ID, 存儲物品ID) → (倉庫ID, 數量)
    所以,(倉庫ID, 存儲物品ID)和(管理員ID, 存儲物品ID)都是StorehouseManage的候選關鍵字,表中的唯一非關鍵字段爲數量,它是符合第三範式的。但是,由於存在如下決定關係:
    (倉庫ID) → (管理員ID)
    (管理員ID) → (倉庫ID)
    即存在關鍵字段決定關鍵字段的情況,所以其不符合BCNF範式。它會出現如下異常情況:
    (1) 刪除異常:
    當倉庫被清空後,所有"存儲物品ID"和"數量"信息被刪除的同時,"倉庫ID"和"管理員ID"信息也被刪除了。
    (2) 插入異常:
    當倉庫沒有存儲任何物品時,無法給倉庫分配管理員。
    (3) 更新異常:
    如果倉庫換了管理員,則表中所有行的管理員ID都要修改。
    把倉庫管理關係表分解爲二個關係表:
    倉庫管理:StorehouseManage(倉庫ID, 管理員ID);
    倉庫:Storehouse(倉庫ID, 存儲物品ID, 數量)。
    這樣的數據庫表是符合BCNF範式的,消除了刪除異常、插入異常和更新異常。
範式應用
    我們來逐步搞定一個論壇的數據庫,有如下信息:
    (1) 用戶:用戶名,email,主頁,電話,聯繫地址
    (2) 帖子:發帖標題,發帖內容,回覆標題,回覆內容
    第一次我們將數據庫設計爲僅僅存在表:
    用戶名 email 主頁 電話 聯繫地址 發帖標題 發帖內容 回覆標題 回覆內容
    這個數據庫表符合第一範式,但是沒有任何一組候選關鍵字能決定數據庫表的整行,唯一的關鍵字段用戶名也不能完全決定整個元組。我們需要增加"發帖ID"、"回覆ID"字段,即將表修改爲:
    用戶名 email 主頁 電話 聯繫地址 發帖ID 發帖標題 發帖內容 回覆ID 回覆標題 回覆內容 
    這樣數據表中的關鍵字(用戶名,發帖ID,回覆ID)能決定整行:
    (用戶名,發帖ID,回覆ID) → (email,主頁,電話,聯繫地址,發帖標題,發帖內容,回覆標題,回覆內容)
    但是,這樣的設計不符合第二範式,因爲存在如下決定關係:
    (用戶名) → (email,主頁,電話,聯繫地址)
    (發帖ID) → (發帖標題,發帖內容)
    (回覆ID) → (回覆標題,回覆內容)
    即非關鍵字段部分函數依賴於候選關鍵字段,很明顯,這個設計會導致大量的數據冗餘和操作異常。
我們將數據庫表分解爲(帶下劃線的爲關鍵字):
(1) 用戶信息:用戶名,email,主頁,電話,聯繫地址
(2) 帖子信息:發帖ID,標題,內容
(3) 回覆信息:回覆ID,標題,內容
(4) 發貼:用戶名,發帖ID
(5) 回覆:發帖ID,回覆ID
    這樣的設計是滿足第1、2、3範式和BCNF範式要求的,但是這樣的設計是不是最好的呢?
不一定。
    觀察可知,第4項"發帖"中的"用戶名"和"發帖ID"之間是1:N的關係,因此我們可以把"發帖"合併到第2項的"帖子信息"中;第5項"回覆"中的"發帖ID"和"回覆ID"之間也是1:N的關係,因此我們可以把"回覆"合併到第3項的"回覆信息"中。這樣可以一定量地減少數據冗餘,新的設計爲:
(1) 用戶信息:用戶名,email,主頁,電話,聯繫地址
(2) 帖子信息:用戶名,發帖ID,標題,內容
(3) 回覆信息:發帖ID,回覆ID,標題,內容
    數據庫表1顯然滿足所有範式的要求;
    數據庫表2中存在非關鍵字“標題”、“內容”對關鍵字段“發帖ID”的部分函數依賴,即不滿足第二範式的要求,但是這一設計並不會導致數據冗餘和操作異常;
    數據庫表3中也存在非關鍵字段"標題"、"內容"對關鍵字段"回覆ID"的部分函數依賴,也不滿足第二範式的要求,但是與數據庫表2相似,這一設計也不會導致數據冗餘和操作異常。
    由此可以看出,並不一定要強行滿足範式的要求,對於1:N關係,當1的一邊合併到N的那邊後,N的那邊就不再滿足第二範式了,但是這種設計反而比較好!
    對於M:N的關係,不能將M一邊或N一邊合併到另一邊去,這樣會導致不符合範式要求,同時導致操作異常和數據冗餘。
    對於1:1的關係,我們可以將左邊的1或者右邊的1合併到另一邊去,設計導致不符合範式要求,但是並不會導致操作異常和數據冗餘。

 

3.       

4.      是

第4部分           解答題

第4部分      

4.1     Hadoop解答題

4.1.1  MapReduce編程題

1.      當前日誌採樣格式爲,請用你最熟悉的語言編寫一個 mapreduce,並計算第四列每個元素出現的個數。

1.  a,b,c,d

2.  b,b,f,e

3.  a,a,c,f

2.      給定 a、b 兩個文件,各存放 50 億個 url,每個 url 各佔 64 字節,內存限制是 4G,讓你找出 a、b 文件共同的 url?

解答:

方案 1:將大文件分成能夠被內存加載的小文件。

可以估計每個文件安的大小爲 50G×64=320G,遠遠大於內存限制的 4G。所以不可能將其完全加載到內存中處理。考慮採取分而治之的方法。

s 遍歷文件 a,對每個 url 求取 ,然後根據所取得的值將 url 分別存儲到 1000 個小文件(記爲 )中。

這樣每個小文件的大約爲 300M。

s 遍歷文件 b,採取和 a 相同的方式將 url 分別存儲到 1000 各小文件(記爲 )。這樣處理後,所有可能相同的 url 都在對應的小文件( )中,不對應的小文件不可能有相同的 url。然後我們只要求出 1000 對小文件中相同的 url 即可。

s 求每對小文件中相同的 url 時,可以把其中一個小文件的 url 存儲到 hash_set 中。然後遍歷另一個小文件的每個 url,看其是否在剛纔構建的 hash_set 中,如果是,那麼就是共同的 url,存到文件裏面就可以了。

方案 2:內存映射成 BIT 最小存儲單元。

如果允許有一定的錯誤率,可以使用 Bloom filter,4G 內存大概可以表示 340 億 bit。將其中一個文件中的url使用Bloom filter映射爲這340億bit,然後挨個讀取另外一個文件的url,檢查是否與Bloom filter,如果是,那麼該 url 應該是共同的 url(注意會有一定的錯誤率)。

3.      有 10 個文件,每個文件 1G,每個文件的每一行存放的都是用戶的 query,每個文件的 query 都可能重複。要求你按照query 的頻度排序。

解答:

方案 1:

s 順序讀取 10 個文件,按照 hash(query)%10 的結果將 query 寫入到另外 10 個文件(記爲 )中。這樣新生成的文件每個的大小大約也 1G(假設 hash 函數是隨機的)。

s 找一臺內存在 2G 左右的機器,依次對 用 hash_map(query, query_count)來統計每個 query 出現的次數。利用快速/堆/歸併排序按照出現次數進行排序。將排序好的 query 和對應的 query_cout 輸出到文件中。這樣得到了 10 個排好序的文件(記爲 )。

s 對 這 10 個文件進行歸併排序(內排序與外排序相結合)。

方案 2:

一般 query 的總量是有限的,只是重複的次數比較多而已,可能對於所有的 query,一次性就可以加入到內存了。這樣,我們就可以採用 trie 樹/hash_map 等直接來統計每個 query 出現的次數,然後按出現

次數做快速/堆/歸併排序就可以了。

方案 3:

與方案 1 類似,但在做完 hash,分成多個文件後,可以交給多個文件來處理,採用分佈式的架構來處

理(比如 MapReduce),最後再進行合併。

//一般在大文件中找出出現頻率高的,先把大文件映射成小文件,模 1000,在小文件中找到高頻的

4.      有一個 1G 大小的一個文件,裏面每一行是一個詞,詞的大小不超過 16 字節,內存限制大小是 1M。返回頻數最高的 100 個詞。

解答:

方案 1:順序讀文件中,對於每個詞 x,取 ,然後按照該值存到 5000 個小文件(記爲 )中。這樣每個文件大概是 200k 左右。如果其中的有的文件超過了 1M 大小,還可以按照類似的方法繼續往下分,知道分解得到的小文件的大小都不超過 1M。 對每個小文件,統計每個文件中出現的詞以及相應的頻率(可以採用 trie 樹/hash_map 等),並取出出現頻率最大的 100 個詞(可以用含 100 個結 點的最小堆),並把 100詞及相應的頻率存入文件,這樣又得到了 5000 個文件。下一步就是把這 5000 個文件進行歸併(類似與歸併排序)的過程了。

方案2:

1.       將文件逐行讀寫到另一個文件中,並將每行單詞全變成小寫

2.       十六次循環執行,將每行單詞按照a-z寫到不同文件裏

3.       最後相同的單詞都寫在了通一個文件裏

4.       再將文件讀寫到各自另一個文件裏,內容是“單詞 個數”

5.       定義一個treemap,大小是100,依次插入大的,移除小的

6.       最後得出結果

5.      海量日誌數據,提取出某日訪問百度次數最多的那個 IP。

解答:

 

1.       先根據日期在日誌文件中提取出ip,根據ip哈希進行分寫N個文件。

2.       採用mapreduce的word cont

方案 1:首先是這一天,並且是訪問百度的日誌中的 IP 取出來,逐個寫入到一個大文件中。注意到 IP是 32 位的,最多有 個 IP。同樣可以採用映射的方法,比如模 1000,把整個大文件映射爲 1000 個小文件,再找出每個小文中出現頻率最大的 IP(可以採用 hash_map 進行頻率統計,然後再找出頻率最大的幾個)及相應的頻率。然後再在這 1000 個最大的 IP 中,找出那個頻率最大的 IP,即爲所求。

6.      在 2.5 億個整數中找出不重複的整數,內存不足以容納這 2.5 億個整數。

解答:

方案 1:採用 2-Bitmap(每個數分配 2bit,00 表示不存在,01 表示出現一次,10 表示多次,11 無意義)進 行,共需內存 內存,還可以接受。然後掃描這 2.5 億個整數,查看 Bitmap 中相對應位,如果是00 變 01,01 變 10,10 保持不變。所描完事後,查看 bitmap,把對應位是 01 的整數輸出即可。

方案 2:也可採用上題類似的方法,進行劃分小文件的方法。然後在小文件中找出不重複的整數,並排序。然後再進行歸併,注意去除重複的元素。

方案3:

1.       將2.5億個整數重寫到一個文件裏,內個整數佔一行。

2.       進行對半排序重寫到新的文件裏,這樣最後2.5億個整數在文件裏便是有序的了

3.       讀取文本,將不重複的寫到一個新的文件裏即可。

7.      海量數據分佈在 100 臺電腦中,想個辦法高校統計出這批數據的 TOP10。

解答:

方案 1:(方法不正確,取出來得不一定是top10)

s 在每臺電腦上求出 TOP10,可以採用包含 10 個元素的堆完成(TOP10 小,用最大堆,TOP10 大,用最小堆)。比如求 TOP10 大,我們首先取前 10 個元素調整成最小堆,如果發現,然後掃描後面的數據,並與堆頂元素比較,如果比堆頂元素大,那麼用該元素替換堆頂,然後再調整爲最小堆。最後堆中的元 素就是 TOP10 大。

s 求出每臺電腦上的 TOP10 後,然後把這 100 臺電腦上的 TOP10 組合起來,共 1000 個數據,再利用上面類似的方法求出 TOP10 就可以了。

8.      怎麼在海量數據中找出重複次數最多的一個?

解答:

方案 1:(同上,方法錯誤)

先做 hash,然後求模映射爲小文件,求出每個小文件中重複次數最多的一個,並記錄重複次數。然後找出上一步求出的數據中重複次數最多的一個就是所求(具體參考前面的題)。

 

正確的方法,先排除

9.      上千萬或上億數據(有重複),統計其中出現次數最多的前 N 個數據。

解答:

10.  1000 萬字符串,其中有些是重複的,需要把重複的全部去掉,保留沒有重複的字符串。請怎麼設計和實現?

解答:

11.  一個文本文件,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前 10 個詞,請給出思想,給出時間複雜度分析。

解答:

方案 1:這題是考慮時間效率。用 trie 樹統計每個詞出現的次數,時間複雜度是 O(n*le)(le 表示單詞的平準長 度)。然後是找出出現最頻繁的前 10 個詞,可以用堆來實現,前面的題中已經講到了,時間複雜度是 O(n*lg10)。所以總的時間複雜度,是 O(n*le)與 O(n*lg10)中較大的哪一個。

12.  一個文本文件,找出前 10 個經常出現的詞,但這次文件比較長,說是上億行或十億行,總之無法一次讀入內存,問最優解。

解答:

13.  100w 個數中找出最大的 100 個數。

解答:

14.   

15.  D

16.  D

17.  D

第5部分           處理海量數據問題之六把密匙

第5部分       

5.1      密匙一、分而治之/Hash映射 + Hash統計 /快速/歸併排序

1、海量日誌數據,提取出某日訪問百度次數最多的那個IP。

    既然是海量數據處理,那麼可想而知,給我們的數據那就一定是海量的。針對這個數據的海量,我們如何着手呢?對的,無非就是分而治之/hash映射 + hash統計 + 堆/快速/歸併排序,說白了,就是先映射,而後統計,最後排序:

1. 分而治之/hash映射:針對數據太大,內存受限,只能是:把大文件化成(取模映射)小文件,即16字方針:大而化小,各個擊破,縮小規模,逐個解決

2. hash統計:當大文件轉化了小文件,那麼我們便可以採用常規的hash_map(ip,value)來進行頻率統計。

3. 堆/快速排序:統計完了之後,便進行排序(可採取堆排序),得到次數最多的IP。

   具體而論,則是: “首先是這一天,並且是訪問百度的日誌中的IP取出來,逐個寫入到一個大文件中。注意到IP是32位的,最多有個2^32個IP。同樣可以採用映射的方 法,比如模1000,把整個大文件映射爲1000個小文件,再找出每個小文中出現頻率最大的IP(可以採用hash_map進行頻率統計,然後再找出頻率 最大的幾個)及相應的頻率。然後再在這1000個最大的IP中,找出那個頻率最大的IP,即爲所求。”--十道海量數據處理面試題與十個方法大總結

    注:Hash取模是一種等價映射,不會存在同一個元素分散到不同小文件中去的情況,即這裏採用的是mod1000算法,那麼相同的IP在hash後,只可能落在同一個文件中,不可能被分散的。

    那到底什麼是hash映射呢?我換個角度舉個淺顯直白的例子,如本文的URL是:http://blog.csdn.net/v_july_v/article/details/7382693,當我把這個URL發表在微博上,便被映射成了:http://t.cn/zOixljh,於此,我們發現URL本身的長度被縮短了,但這兩個URL對應的文章的是同一篇即本文。OK,有興趣的,還可以再瞭解下一致性hash算法,見此文第五部分:http://blog.csdn.net/v_july_v/article/details/6879101

2、搜索引擎會通過日誌文件把用戶每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度爲1-255字節。

    假設目前有一千萬個記錄(這些查詢串的重複度比較高,雖然總數是1千萬,但如果除去重複後,不超過3百萬個。一個查詢串的重複度越高,說明查詢它的用戶越多,也就是越熱門),請你統計最熱門的10個查詢串,要求使用的內存不能超過1G。

    由上面第1題,我們知道,數據大則劃爲小的,但如果數據規模比較小,能一次性裝入內存呢?比如這第2題,雖然有一千萬個Query,但是由於重複度比較 高,因此事實上只有300萬的Query,每個Query255Byte,因此我們可以考慮把他們都放進內存中去,而現在只是需要一個合適的數據結構,在 這裏,Hash Table絕對是我們優先的選擇。所以我們摒棄分而治之/hash映射的方法,直接上hash統計,然後排序。So,

1. hash 統計:先對這批海量數據預處理(維護一個Key爲Query字串,Value爲該Query出現次數的HashTable,即 hash_map(Query,Value),每次讀取一個Query,如果該字串不在Table中,那麼加入該字串,並且將Value值設爲1;如果該 字串在Table中,那麼將該字串的計數加一即可。最終我們在O(N)的時間複雜度內用Hash表完成了統計;

2. 堆排序:第二步、藉助堆 這個數據結構,找出Top K,時間複雜度爲N‘logK。即藉助堆結構,我們可以在log量級的時間內查找和調整/移動。因此,維護一個K(該題目中是10)大小的小根堆,然後遍 歷300萬的Query,分別和根元素進行對比所以,我們最終的時間複雜度是:O(N) + N'*O(logK),(N爲1000萬,N’爲300萬)。

    別忘了這篇文章中所述的堆排序思路:“維 護k個元素的最小堆,即用容量爲k的最小堆存儲最先遍歷到的k個數,並假設它們即是最大的k個數,建堆費時O(k),並調整堆(費時O(logk))後, 有k1>k2>...kmin(kmin設爲小頂堆中最小元素)。繼續遍歷數列,每次遍歷一個元素x,與堆頂元素比較,若 x>kmin,則更新堆(用時logk),否則不更新堆。這樣下來,總費時O(k*logk+(n-k)*logk)=O(n*logk)。此方法 得益於在堆中,查找等各項操作時間複雜度均爲logk。”--第三章續、Top K算法問題的實現
    當然,你也可以採用trie樹,關鍵字域存該查詢串出現的次數,沒有出現爲0。最後用10個元素的最小推來對出現頻率進行排序。

3、有一個1G大小的一個文件,裏面每一行是一個詞,詞的大小不超過16字節,內存限制大小是1M。返回頻數最高的100個詞。
       由上面那兩個例題,分而治之 + hash統計 + 堆/快速排序這個套路,我們已經開始有了屢試不爽的感覺。下面,再拿幾道再多多驗證下。請看此第3題:又是文件很大,又是內存受限,咋辦?還能怎麼辦呢?無非還是:

1. 分 而治之/hash映射:順序讀文件中,對於每個詞x,取hash(x)%5000,然後按照該值存到5000個小文件(記爲 x0,x1,...x4999)中。這樣每個文件大概是200k左右。如果其中的有的文件超過了1M大小,還可以按照類似的方法繼續往下分,直到分解得到 的小文件的大小都不超過1M。

2. hash統計:對每個小文件,採用trie樹/hash_map等統計每個文件中出現的詞以及相應的頻率。

3. 堆/歸併排序:取出出現頻率最大的100個詞(可以用含100個結點的最小堆),並把100個詞及相應的頻率存入文件,這樣又得到了5000個文件。最後就是把這5000個文件進行歸併(類似於歸併排序)的過程了。

4、海量數據分佈在100臺電腦中,想個辦法高效統計出這批數據的TOP10。

    此題與上面第3題類似,

1. 堆排序:在每臺電腦上求出TOP10,可以採用包含10個元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。比如求TOP10大,我們首先取前10個元素調整成最小堆,如果發現,然後掃描後面的數據,並與堆頂元素比較,如果比堆頂元素大,那麼用該元素替換堆頂,然後再調整爲最小堆。最後堆中的元素就是TOP10大。

2. 求出每臺電腦上的TOP10後,然後把這100臺電腦上的TOP10組合起來,共1000個數據,再利用上面類似的方法求出TOP10就可以了。

    上述第4題的此解法,經讀者反應有問題,如舉個例子如比如求2個文件中的top2,照你這種算法,如果第一個文件裏有

a 49次

b 50次

c 2次

d 1次

    第二個文件裏有

a 9次

b 1次

c 11次

d 10次

     雖然第 一個文件裏出來top2是b(50次),a(49次),第二個文件裏出來top2是c(11次),d(10次),然後2個top2:b(50次)a(49 次)與c(11次)d(10次)歸併,則算出所有的文件的top2是b(50 次),a(49 次),但實際上是a(58 次),b(51 次)。是否真是如此呢?若真如此,那作何解決呢?

    正如老夢所述:

    首先,先把所有的數據遍歷一遍做一次hash(保證相同的數據條目劃分到同一臺電腦上進行運算),然後根據hash結果重新分佈到100臺電腦中,接下來的算法按照之前的即可。

    最後由於a可能出現在不同的電腦,各有一定的次數,再對每個相同條目進行求和(由於上一步驟中hash之後,也方便每臺電腦只需要對自己分到的條目內進行求和,不涉及到別的電腦,規模縮小)。

5、有10個文件,每個文件1G,每個文件的每一行存放的都是用戶的query,每個文件的query都可能重複。要求你按照query的頻度排序。

   直接上:

1. hash映射:順序讀取10個文件,按照hash(query)%10的結果將query寫入到另外10個文件(記爲)中。這樣新生成的文件每個的大小大約也1G(假設hash函數是隨機的)。

2. hash統計:找一臺內存在2G左右的機器,依次對用hash_map(query, query_count)來統計每個query出現的次數。注:hash_map(query,query_count)是用來統計每個query的出現次數,不是存儲他們的值,出現一次,則count+1

3. 堆/快速/歸併排序:利用快速/堆/歸併排序按照出現次數進行排序。將排序好的query和對應的query_cout輸出到文件中。這樣得到了10個排好序的文件(記爲)。對這10個文件進行歸併排序(內排序與外排序相結合)。

     除此之外,此題還有以下兩個方法:
    方案2:一般query的總量是有限的,只是重複的次數比較多而已,可能對於所有的query,一次性就可以加入到內存了。這樣,我們就可以採用trie樹/hash_map等直接來統計每個query出現的次數,然後按出現次數做快速/堆/歸併排序就可以了。

    方案3:與方案1類似,但在做完hash,分成多個文件後,可以交給多個文件來處理,採用分佈式的架構來處理(比如MapReduce),最後再進行合併。

6、 給定a、b兩個文件,各存放50億個url,每個url各佔64字節,內存限制是4G,讓你找出a、b文件共同的url?

    可以估計每個文件安的大小爲5G×64=320G,遠遠大於內存限制的4G。所以不可能將其完全加載到內存中處理。考慮採取分而治之的方法。

1. 分而治之/hash映射:遍歷文件a,對每個url求取 ,然後根據所取得的值將url分別存儲到1000個小文件(記爲 )中。這樣每個小文件的大約爲300M遍歷文件b,採取和a相同的方式將url分別存儲到1000小文件中(記爲 )。這樣處理後,所有可能相同的url都在對應的小文件( )中,不對應的小文件不可能有相同的url。然後我們只要求出1000對小文件中相同的url即可

2. hash統計:求每對小文件中相同的url時,可以把其中一個小文件的url存儲到hash_set中。然後遍歷另一個小文件的每個url,看其是否在剛纔構建的hash_set中,如果是,那麼就是共同的url,存到文件裏面就可以了。

    OK,此第一種方法:分而治之/hash映射 + hash統計 + 堆/快速/歸併排序,再看最後三道題,如下:

7、怎麼在海量數據中找出重複次數最多的一個?

    方案1:先做hash,然後求模映射爲小文件,求出每個小文件中重複次數最多的一個,並記錄重複次數。然後找出上一步求出的數據中重複次數最多的一個就是所求(具體參考前面的題)。

8、上千萬或上億數據(有重複),統計其中出現次數最多的錢N個數據。

    方案1:上千萬或上億的數據,現在的機器的內存應該能存下。所以考慮採用hash_map/搜索二叉樹/紅黑樹等來進行統計次數。然後就是取出前N個出現次數最多的數據了,可以用第2題提到的堆機制完成。

9、一個文本文件,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10個詞,請給出思想,給出時間複雜度分析。

     方案1:這題是考慮時間效率。用trie樹統計每個詞出現的次數,時間複雜度是O(n*le)(le表示單詞的平準長度)。然後是找出出現最頻繁的前 10個詞,可以用堆來實現,前面的題中已經講到了,時間複雜度是O(n*lg10)。所以總的時間複雜度,是O(n*le)與O(n*lg10)中較大的 哪一個。

    接下來,咱們來看第二種方法,雙層捅劃分。

 

5.2      密匙二、雙層桶劃分

雙層桶劃分----其實本質上還是分而治之的思想,重在“分”的技巧上!
  適用範圍:第k大,中位數,不重複或重複的數字
  基本原理及要點:因爲元素範圍很大,不能利用直接尋址表,所以通過多次劃分,逐步確定範圍,然後最後在一個可以接受的範圍內進行。可以通過多次縮小,雙層只是一個例子。
  擴展:
  問題實例:

        10、2.5億個整數中找出不重複的整數的個數,內存空間不足以容納這2.5億個整數。
  有點像鴿巢原理,整數個數爲2^32,也就是,我們可以將這2^32個數,劃分爲2^8個區域(比如用單個文件代表一個區域),然後將數據分離到不同的區域,然後不同的區域在利用bitmap就可以直接解決了。也就是說只要有足夠的磁盤空間,就可以很方便的解決。

       11、5億個int找它們的中位數。
   這個例子比上面那個更明顯。首先我們將int劃分爲2^16個區域,然後讀取數據統計落到各個區域裏的數的個數,之後我們根據統計結果就可以判斷中位數 落到那個區域,同時知道這個區域中的第幾大數剛好是中位數。然後第二次掃描我們只統計落在這個區域中的那些數就可以了。
  實際上,如果不是 int是int64,我們可以經過3次這樣的劃分即可降低到可以接受的程度。即可以先將int64分成2^24個區域,然後確定區域的第幾大數,在將該區 域分成2^20個子區域,然後確定是子區域的第幾大數,然後子區域裏的數的個數只有2^20,就可以直接利用direct addr table進行統計了。

 

5.3      密匙三:Bloom filter/Bitmap

Bloom filter

關於什麼是Bloom filter,請參看此文:海量數據處理之Bloom Filter詳解
  適用範圍:可以用來實現數據字典,進行數據的判重,或者集合求交集
  基本原理及要點:
   對於原理來說很簡單,位數組+k個獨立hash函數。將hash函數對應的值的位數組置1,查找時如果發現所有hash函數對應位都是1說明存在,很明 顯這個過程並不保證查找的結果是100%正確的。同時也不支持刪除一個已經插入的關鍵字,因爲該關鍵字對應的位會牽動到其他的關鍵字。所以一個簡單的改進 就是 counting Bloom filter,用一個counter數組代替位數組,就可以支持刪除了。
  還有一個比較重要的問題,如何 根據輸入元素個數n,確定位數組m的大小及hash函數個數。當hash函數個數k=(ln2)*(m/n)時錯誤率最小。在錯誤率不大於E的情況下,m 至少要等於n*lg(1/E)才能表示任意n個元素的集合。但m還應該更大些,因爲還要保證bit數組裏至少一半爲0,則m應該>=nlg(1 /E)*lge 大概就是nlg(1/E)1.44倍(lg表示以2爲底的對數)。
  舉個例子我們假設錯誤率爲0.01,則此時m應大概是n的13倍。這樣k大概是8個。
  注意這裏m與n的單位不同,m是bit爲單位,而n則是以元素個數爲單位(準確的說是不同元素的個數)。通常單個元素的長度都是有很多bit的。所以使用bloom filter內存上通常都是節省的。

  擴展:
   Bloom filter將集合中的元素映射到位數組中,用k(k爲哈希函數個數)個映射位是否全1表示元素在不在這個集合中。Counting bloom filter(CBF)將位數組中的每一位擴展爲一個counter,從而支持了元素的刪除操作。Spectral Bloom Filter(SBF)將其與集合元素的出現次數關聯。SBF採用counter中的最小值來近似表示元素的出現頻率。

        12、給你A,B兩個文件,各存放50億條URL,每條URL佔用64字節,內存限制是4G,讓你找出A,B文件共同的URL。如果是三個乃至n個文件呢?

   根據這個問題我們來計算下內存的佔用,4G=2^32大概是40億*8大概是340億,n=50億,如果按出錯率0.01算需要的大概是650億個 bit。現在可用的是340億,相差並不多,這樣可能會使出錯率上升些。另外如果這些urlip是一一對應的,就可以轉換成ip,則大大簡單了。

    同時,上文的第5題:給定a、b兩個文件,各存放50億個url,每個url各佔64字節,內存限制是4G,讓你找出a、b文件共同的url?如果允許有 一定的錯誤率,可以使用Bloom filter,4G內存大概可以表示340億bit。將其中一個文件中的url使用Bloom filter映射爲這340億bit,然後挨個讀取另外一個文件的url,檢查是否與Bloom filter,如果是,那麼該url應該是共同的url(注意會有一定的錯誤率)。

Bitmap

    至於什麼是Bitmap,請看此文:http://blog.csdn.net/v_july_v/article/details/6685962。下面關於Bitmap的應用,直接上題,如下第9、10道:

      13、在2.5億個整數中找出不重複的整數,注,內存不足以容納這2.5億個整數。

    方案1:採用2-Bitmap(每個數分配2bit,00表示不存在,01表示出現一次,10表示多次,11無意義)進行,共需內存2^32 * 2 bit=1 GB內存,還可以接受。然後掃描這2.5億個整數,查看Bitmap中相對應位,如果是00變01,01變10,10保持不變。所描完事後,查看 bitmap,把對應位是01的整數輸出即可。
    方案2:也可採用與第1題類似的方法,進行劃分小文件的方法。然後在小文件中找出不重複的整數,並排序。然後再進行歸併,注意去除重複的元素。

      14、騰訊面試題:給40億個不重複的unsigned int的整數,沒排過序的,然後再給一個數,如何快速判斷這個數是否在那40億個數當中?
    方案1:frome oo,用位圖/Bitmap的方法,申請512M的內存,一個bit位代表一個unsigned int值。讀入40億個數,設置相應的bit位,讀入要查詢的數,查看相應bit位是否爲1,爲1表示存在,爲0表示不存在。

 

5.4      密匙四、Trie/數據庫/倒排索引

Trie樹

  適用範圍:數據量大,重複多,但是數據種類小可以放入內存
  基本原理及要點:實現方式,節點孩子的表示方式
  擴展:壓縮實現。

  問題實例:

1. 有10個文件,每個文件1G,每個文件的每一行都存放的是用戶的query,每個文件的query都可能重複。要你按照query的頻度排序。

2. 1000萬字符串,其中有些是相同的(重複),需要把重複的全部去掉,保留沒有重複的字符串。請問怎麼設計和實現?

3. 尋找熱門查詢:查詢串的重複度比較高,雖然總數是1千萬,但如果除去重複後,不超過3百萬個,每個不超過255字節。

4. 上面的第8題:一個文本文件,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10個詞。其解決方法是:用trie樹統計每個詞出現的次數,時間複雜度是O(n*le)(le表示單詞的平準長度),然後是找出出現最頻繁的前10個詞。

    更多有關Trie樹的介紹,請參見此文:從Trie樹(字典樹)談到後綴樹

數據庫索引
  適用範圍:大數據量的增刪改查
  基本原理及要點:利用數據的設計實現方法,對海量數據的增刪改查進行處理。

    關於數據庫索引及其優化,更多可參見此文:http://www.cnblogs.com/pkuoliver/archive/2011/08/17/mass-data-topic-7-index-and-optimize.html。同時,關於MySQL索引背後的數據結構及算法原理,這裏還有一篇很好的文章:http://www.codinglabs.org/html/theory-of-mysql-index.html

倒排索引(Inverted index)
  適用範圍:搜索引擎,關鍵字查詢
  基本原理及要點:爲何叫倒排索引?一種索引方法,被用來存儲在全文搜索下某個單詞在一個文檔或者一組文檔中的存儲位置的映射。
 以英文爲例,下面是要被索引的文本:
    T0 = "it is what it is"
    T1 = "what is it"
    T2 = "it is a banana"
    我們就能得到下面的反向文件索引:
    "a":      {2}
    "banana": {2}
    "is":     {0, 1, 2}
    "it":     {0, 1, 2}
    "what":   {0, 1}
 檢索的條件"what","is"和"it"將對應集合的交集。

   正向索引開發出來用來存儲每個文檔的單詞的列表。正向索引的查詢往往滿足每個文檔有序頻繁的全文查詢和每個單詞在校驗文檔中的驗證這樣的查詢。在正向索 引中,文檔佔據了中心的位置,每個文檔指向了一個它所包含的索引項的序列。也就是說文檔指向了它包含的那些單詞,而反向索引則是單詞指向了包含它的文檔, 很容易看到這個反向的關係。
  擴展:
  問題實例:文檔檢索系統,查詢那些文件包含了某單詞,比如常見的學術論文的關鍵字搜索。

    關於倒排索引的應用,更多請參見:第二十三、四章:楊氏矩陣查找,倒排索引關鍵詞Hash不重複編碼實踐,及第二十六章:基於給定的文檔生成倒排索引的編碼與實踐

 

5.5        密匙五、外排序

適用範圍:大數據的排序,去重
  基本原理及要點:外排序的歸併方法,置換選擇敗者樹原理,最優歸併樹
  擴展:
  問題實例:
1).有一個1G大小的一個文件,裏面每一行是一個詞,詞的大小不超過16個字節,內存限制大小是1M。返回頻數最高的100個詞。
  這個數據具有很明顯的特點,詞的大小爲16個字節,但是內存只有1Mhash明顯不夠,所以可以用來排序。內存可以當輸入緩衝區使用。

    關於多路歸併算法及外排序的具體應用場景,請參見此文:第十章、如何給10^7個數據量的磁盤文件排序

 

5.6        密匙六、分佈式處理之Mapreduce

 適用範圍:數據量大,但是數據種類小可以放入內存
  基本原理及要點:將數據交給不同的機器去處理,數據劃分,結果歸約。
  擴展:
  問題實例:

1. The canonical example application of MapReduce is a process to count the appearances of each different word in a set of documents:

2. 海量數據分佈在100臺電腦中,想個辦法高效統計出這批數據的TOP10。

3. 一共有N個機器,每個機器上有N個數。每個機器最多存O(N)個數並對它們操作。如何找到N^2個數的中數(median)?

    更多具體闡述請參見:Hadhoop框架與MapReduce模式中談海量數據處理,及MapReduce技術的初步瞭解與學習

 

 

18.   

19.  的

第6部分           設計題

5.7     日誌收集分析系統

1.      日誌分佈在各個業務系統中,我們需要對當天的日誌進行實時彙總統計,同時又能離線查詢歷史的彙總數據(PV、UV、IP)

解答:

1、通過flume將不同系統的日誌收集到kafka中

2、通過storm實時的處理PV、UV、IP

3、通過kafka的consumer將日誌生產到hbase中。

4、通過離線的mapreduce或者hive,處理hbase中的數據

 

2.      Hive語言實現word count

解答:

1.建表

2.分組(group by)統計wordcount

select word,count(1) from table1 group by word;

 

3.      實時數據統計會用到哪些技術,他們各自的應用場景及區別是什麼?

解答:

flume:日誌收集系統,主要用於系統日誌的收集

kafka:消息隊列,進行消息的緩存和系統的解耦

storm:實時計算框架,進行流式的計算。

 

 

4.      的

5.      的

6.      的

5.8     MapReduce

1.      有兩個文本文件,文件中的數據按行存放,請編寫MapReduce程序,找到兩個文件中彼此不相同的行(寫出思路即可)

解答:

寫個mapreduce鏈  用依賴關係,一共三個mapreduce,第一個處理第一個文件,第二個處理第二個文件,第三個處理前兩個的輸出結果,第一個mapreduce將文件去重,第二個mapreduce也將文件去重,第三個做wordcount,wordcount爲1的結果就是不同的

 

2.      共同朋友

1. A B CD E F

2. B A CD E

3. C A B E

4. D B E

5. E A BC D

6. F A

                   第一個字母表示本人,其他事他的朋友,找出有共同朋友的人,和共同的朋友是誰

解答:

思路:例如A,他的朋友是B\C\D\E\F\,那麼BC的共同朋友就是A。所以將BC作爲key,將A作爲value,在map端輸出即可!其他的朋友循環處理。

import java.io.IOException;

import java.util.Set;

import java.util.StringTokenizer;

import java.util.TreeSet;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

10. import org.apache.hadoop.mapreduce.Mapper;

11. import org.apache.hadoop.mapreduce.Reducer;

12. import org.apache.hadoop.mapreduce.Mapper.Context;

13. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

14. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

15. import org.apache.hadoop.util.GenericOptionsParser;

 

public class FindFriend {

 

          public static class ChangeMapper extends Mapper<Object, Text, Text,

Text>{                      

                    @Override

                    public void map(Object key, Text value, Context context) throws

IOException, InterruptedException {

                              StringTokenizer itr = new StringTokenizer(value.toString());

                                  Text owner = new Text();

                                  Set<String> set = new TreeSet<String>();

                              owner.set(itr.nextToken());

                              while (itr.hasMoreTokens()) {

                                      set.add(itr.nextToken());

                              }             

                             String[] friends = new String[set.size()];

                             friends = set.toArray(friends);

                              

                             for(int i=0;i<friends.length;i++){

                                      for(int j=i+1;j<friends.length;j++){

                                              String outputkey = friends[i]+friends[j];

                                              context.write(new Text(outputkey),owner);

                                      }                                     

                              }

                    }

           }

           

           public static class FindReducer extends Reducer<Text,Text,Text,Text>

{                          

                         public void reduce(Text key, Iterable<Text> values, 

                                         Context context) throws IOException,

InterruptedException {

                                   String  commonfriends =""; 

                               for (Text val : values) {

                                  if(commonfriends == ""){

                                          commonfriends = val.toString();

                                   }else{

                                          commonfriends =

commonfriends+":"+val.toString();

                                   }

                                }

                              context.write(key, new

Text(commonfriends));                                

                         }                          

           }

          

 

        public static void main(String[] args) throws IOException,

         InterruptedException, ClassNotFoundException {

                 

            Configuration conf = new Configuration();

             String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

             if (otherArgs.length < 2) {

               System.err.println("args error");

               System.exit(2);

            }

             Job job = new Job(conf, "word count");

            job.setJarByClass(FindFriend.class);

             job.setMapperClass(ChangeMapper.class);

             job.setCombinerClass(FindReducer.class);

             job.setReducerClass(FindReducer.class);

             job.setOutputKeyClass(Text.class);

             job.setOutputValueClass(Text.class);

             for (int i = 0; i < otherArgs.length - 1; ++i) {

               FileInputFormat.addInputPath(job, new Path(otherArgs[i]));

             }

             FileOutputFormat.setOutputPath(job,

               new Path(otherArgs[otherArgs.length - 1]));

             System.exit(job.waitForCompletion(true) ? 0 : 1);

                 

        }

 

}

 

結果:

1. AB      E:C:D

2. AC      E:B

3. AD      B:E

4. AE      C:B:D

5. BC      A:E

6. BD      A:E

7. BE      C:D:A

8. BF      A

9. CD      E:A:B

10. CE      A:B

11. CF      A

12. DE      B:A

13. DF      A

14. EF      A

 

3.      的

4.      的

5.      的

6.      的

5.9     優化

1.      如果要存儲海量的小文件(大小都是幾百K-幾M)請簡述自己的設計方案

解答:

1.將小文件打成har文件存儲

2.將小文件序列化到hdfs中

 

2.       

3.      的

第7部分           涉及Java基礎部分

1.      ArrayList、Vector、LinkedList的區別及其優缺點?HashMap、HashTable的區別及優缺點?

解答:

ArrayList 和Vector是採用數組方式存儲數據的,是根據索引來訪問元素的,都可以根據需要自動擴展內部數據長度,以便增加和插入元素,都允許直接序號索引元素,但是插入數據要涉及到數組元素移動等內存操作,所以索引數據快插入數據慢,他們最大的區別就是synchronized同步的使用。

LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向後遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入數度較快!

如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那麼使用Vector或ArrayList都可以。如果是對其它指定位置的插入、刪除操作,最好選擇LinkedList

HashMap、HashTable的區別及其優缺點:

HashTable 中的方法是同步的 HashMap的方法在缺省情況下是非同步的 因此在多線程環境下需要做額外的同步機制。

HashTable不允許有null值 key和value都不允許,而HashMap允許有null值 key和value都允許 因此HashMap 使用containKey()來判斷是否存在某個鍵。

HashTable 使用Enumeration ,而HashMap使用iterator。

Hashtable是Dictionary的子類,HashMap是Map接口的一個實現類。

 

2.      的

3.      的

第8部分           十道海量數據處理面試題

第6部分      

第7部分      

第8部分      

8.1     海量日誌數據,提取出某日訪問百度次數最多的那個 IP 。

此題,在我之前的一篇文章算法裏頭有所提到,當時給出的方案是:IP 的數目還是有限的,最多 2^32個,所以可以考慮使用 hash 將 ip 直接存入內存,然後進行統計。再詳細介紹下此方案:首先是這一天,並且是訪問百度的日誌中的 IP 取出來,逐個寫入到一個大文件中。注意到 IP 是 32 位的,最多有個 2^32 個 IP。同樣可以採用映射的方法,比如模 1000,把整個大文件映射爲 1000 個小文件,再找出每個小文中出現頻率最大的 IP(可以採用 hash_map 進行頻率統計,然後再找出頻率最大的幾個)及相應的頻率。然後再在這 1000 個最大的 IP 中,找出那個頻率最大的 IP,即爲所求。

 

8.2     2 、搜 索引擎會通過日誌文件把用戶每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度爲1-255  字節。假設目前有一千萬個記錄(這些查詢串的重複度比較高,雖然總數是 1 千萬,但如果除去重複後,不超過 3 百萬個。一個查詢串的重複度越高,說明查詢它的用戶越多,也就是越熱門。),請你統計最熱門的10 個查詢串,要求使用的內存不能超過 1G。

 

 

典型的 Top K 算法,還是在這篇文章裏頭有所闡述。文中,給出的最終算法是:第一步、先對這批海量數據預處理,在 O(N)的時間內用 Hash 表完成排序;然後,第二步、藉助堆這個數據結構,找出 TopK,時間複雜度爲 N‗logK。即,藉助堆結構,我們可以在 log 量級的時間內查找和調整/移動。因此,維護一個 K(該題目中是 10)大小的小根堆,然後遍歷 300 萬的 Query,分別和根元素進行對比所以,我們最終的時間複雜度是:O(N) + N'*O(logK),(N 爲 1000 萬,N‘爲 300 萬)。ok,更多,詳情,請參考原文。或者:採用 trie 樹,關鍵字域存該查詢串出現的次數,沒有出現爲 0。最後用 10 個元素的最小推來對出現頻率進行排序。

 

8.3     有一個 1G 過 大小的一個文件,裏面每一行是一個詞,詞的大小不超過 16  字節,內存限制大小是

1M 。返回頻數最高的 100  個詞。方案:順序讀文件中,對於每個詞 x,取 hash(x)%5000,然後按照該值存到 5000 個小文件(記爲

www.aboutyun.com

x0,x1,...x4999)中。這樣每個文件大概是 200k 左右。如果其中的有的文件超過了 1M 大小,還可以按照類似的方法繼續往下分,直到分解得到的小文件的大小都不超過 1M。 對每個小文件,統計每個文件中出現的詞以及相應的頻率(可以採用 trie 樹/hash_map等),並取出出現頻率最大的 100 個詞(可以用含 100 個結點的最小堆),並把 100 個詞及相應的頻率存入文件,這樣又得到了 5000個文件。下一步就是把這 5000 個文件進行歸併(類似與歸併排序)的過程了。

 

8.4     4 有 10 個文件 件,每個文件 1G ,每個文件的每一行存放的都是用戶的 query ,每個文件的 query照 都可能重複。

 

要求你按照 query  的頻度排序。還是典型的 TOP K 算法,解決方案如下:

 

方案 1:順序讀取 10 個文件,按照 hash(query)%10 的結果將 query 寫入到另外 10 個文件(記爲)中。這樣新生成的文件每個的大小大約也 1G(假設 hash 函數是隨機的)。找一臺內存在 2G 左右的機器,依次對用 hash_map(query, query_count)來統計每個 query 出現的次數。利用快速/堆/歸併排序按照出現次數進行排序。將排序好的query 和對應的 query_cout 輸出到文件中。這樣得到了 10 個排好序的文件(記爲)。對這 10 個文件進行歸併排序(內排序與外排序相結合)。

 

 

方案 2:一般 query 的總量是有限的,只是重複的次數比較多而已,可能對於所有的 query,一次性就可以加入到內存了。這樣,我們就可以採用trie 樹/hash_map 等直接來統計每個 query 出現的次數,然後按出現次數做快速/堆/歸併排序就可以了。

 

方案 3:與方案 1 類似,但在做完 hash,分成多個文件後,可以交給多個文件來處理,採用分佈式的架構來處理(比如 MapReduce),最後再進行合併。

 

8.5     5、  給定 a、、b 兩個文件,各存放50  億個 url ,每個 url  各佔 64  字節,內存限制是 4G ,讓你找出 a 、b 文件共同的 url ?

 

 

方案 1:可以估計每個文件安的大小爲 5G×64=320G,遠遠大於內存限制的 4G。所以不可能將其完全

加載到內存中處理。考慮採取分而治之的方法。

遍歷文件 a,對每個 url 求取 hash(url)%1000,然後根據所取得的值將 url 分別存儲到 1000 個小文件

(記爲 a0,a1,...,a999)中。這樣每個小文件的大約爲 300M。

遍歷文件 b,採取和 a 相同的方式將 url 分別存儲到 1000 小文件(記爲 b0,b1,...,b999)。這樣處理後,

所有可能相同的 url 都在對應的小文件(a0vsb0,a1vsb1,...,a999vsb999)中,不對應的小文件不可能有相

www.aboutyun.com

同的 url。然後我們只要求出 1000 對小文件中相同的 url 即可。

求每對小文件中相同的 url 時,可以把其中一個小文件的 url 存儲到 hash_set 中。然後遍歷另一個小

文件的每個 url,看其是否在剛纔構建的 hash_set 中,如果是,那麼就是共同的url,存到文件裏面就可以

了。

方案 2:如果允許有一定的錯誤率,可以使用 Bloom filter,4G 內存大概可以表示 340 億 bit。將其中

一個文件中的url使用Bloom filter映射爲這340億bit,然後挨個讀取另外一個文件的url,檢查是否與Bloom

filter,如果是,那麼該 url 應該是共同的 url(注意會有一定的錯誤率)。

Bloom filter 日後會在本 BLOG 內詳細闡述。

8.6     在 2.5  億個整數中找出不重複的整數,注,內存不足以容納這 2.5  億個整數。

 

方案 1:採用 2-Bitmap(每個數分配 2bit,00 表示不存在,01 表示出現一次,10 表示多次,11 無意

義)進行,共需內存內存,還可以接受。然後掃描這2.5 億個整數,查看 Bitmap 中相對應位,如果是 00

變 01,01 變 10,10 保持不變。所描完事後,查看 bitmap,把對應位是 01 的整數輸出即可。

方案 2:也可採用與第 1 題類似的方法,進行劃分小文件的方法。然後在小文件中找出不重複的整數,

並排序。然後再進行歸併,注意去除重複的元素。

8.7     騰訊面試題:給 40  億個不重複的 unsigned int  的整數,沒排過序的,然後再給一個數,如何快那速判斷這個數是否在那 40  億個數當中?

與上第 6 題類似,我的第一反應時快速排序+二分查找。以下是其它更好的方法: 方案 1:oo,申請

512M 的內存,一個 bit 位代表一個 unsigned int 值。讀入 40 億個數,設置相應的 bit 位,讀入要查詢的數,

查看相應 bit 位是否爲 1,爲 1 表示存在,爲 0 表示不存在。

dizengrong: 方案 2:這個問題在《編程珠璣》裏有很好的描述,大家可以參考下面的思路,探討一

下:又因爲 2^32 爲 40 億多,所以給定一個數可能在,也可能不在其中;這裏我們把 40 億個數中的每一

個用 32 位的二進制來表示假設這 40 億個數開始放在一個文件中。

然後將這 40 億個數分成兩類: 1.最高位爲 0 2.最高位爲 1 並將這兩類分別寫入到兩個文件中,其中一

個文件中數的個數<=20 億,而另一個>=20 億(這相當於折半了);與要查找的數的最高位比較並接着進

入相應的文件再查找

再然後把這個文件爲又分成兩類: 1.次最高位爲 0 2.次最高位爲 1

並將這兩類分別寫入到兩個文件中,其中一個文件中數的個數<=10 億,而另一個>=10 億(這相當於

折半了); 與要查找的數的次最高位比較並接着進入相應的文件再查找。 ....... 以此類推,就可以找到了,

而且時間複雜度爲 O(logn),方案 2 完。

附:這裏,再簡單介紹下,位圖方法: 使用位圖法判斷整形數組是否存在重複判斷集合中存在重複

是常見編程任務之一,當集合中數據量比較大時我們通常希望少進行幾次掃描,這時雙重循環法就不可取

了。

位圖法比較適合於這種情況,它的做法是按照集合中最大元素max創建一個長度爲max+1的新數組,

然後再次掃描原數組,遇到幾就給新數組的第幾位置上1,如遇到 5 就給新數組的第六個元素置 1,這樣下

次再遇到 5 想置位時發現新數組的第六個元素已經是 1 了,這說明這次的數據肯定和以前的數據存在着重

復。這種給新數組初始化時置零其後置一的做法類似於位圖的處理方法故稱位圖法。它的運算次數最壞的

情況爲 2N。如果已知數組的最大值即能事先給新數組定長的話效率還能提高一倍。

8.8     8 、怎麼在海量數據中找出重複次數最多的一個?

方案 1:先做 hash,然後求模映射爲小文件,求出每個小文件中重複次數最多的一個,並記錄重複次數。

然後找出上一步求出的數據中重複次數最多的一個就是所求(具體參考前面的題)。

8.9     9 、上千萬或上億數據(有重複),統計其中出現次數最多的錢 N  個數據。

方案 1:上千萬或上億的數據,現在的機器的內存應該能存下。所以考慮採用 hash_map/搜索二叉樹/紅黑樹等來進行統計次數。然後就是取出前 N 個出現次數最多的數據了,可以用第 2 題提到的堆機制完成。

8.1010 、一個文本文件,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10  個詞,請給出

思想,給出時間複雜度分析。

方案 1:

這題是考慮時間效率。用 trie 樹統計每個詞出現的次數,時間複雜度是O(n*le)(le 表示單詞的平準長度)。然後是找出出現最頻繁的前 10 個詞,可以用堆來實現,前面的題中已經講到了,時間複雜度是 O(n*lg10)。所以總的時間複雜度,是O(n*le)與 O(n*lg10)中較大的哪一個。附、100w 個數中找出最大的 100 個數。

 

方案1:

在前面的題中,我們已經提到了,用一個含100個元素的最小堆完成。複雜度爲O(100w*lg100)。

 

方案 2:

採用快速排序的思想,每次分割之後只考慮比軸大的一部分,知道比軸大的一部分在比 100多的時候,採用傳統排序算法排序,取前 100 個。複雜度爲 O(100w*100)。

 

方案 3:

採用局部淘汰法。選取前 100 個元素,並排序,記爲序列 L。然後一次掃描剩餘的元素 x,與排好序的 100 個元素中最小的元素比,如果比這個最小的要大,那麼把這個最小的元素刪除,並把 x 利用插入排序的思想,插入到序列 L 中。依次循環,知道掃描了所有的元素。複雜度爲 O(100w*100)。

第9部分           遺留

311、在線安裝ssh的命令以及文件解壓的命令?

312、把公鑰都追加到授權文件的命令?該命令是否在root用戶下執行?

313、HadoopHA集羣中,各個服務的啓動和關閉的順序?

314、HDFS中的block塊默認保存幾份?默認大小多少?

315、NameNode中的meta數據是存放在NameNode自身,還是DataNode等其他節點?DatNOde節點自身是否有Meta數據存在?

316、下列那個程序通常與NameNode在一個節點啓動?

317、下面那個程序負責HDFS數據存儲?

318、 在HadoopHA集羣中,簡述Zookeeper的主要作用,以及啓動和查看狀態的命令?

319、HBase在進行模型設計時重點在什麼地方?一張表中國定義多少個Column Family最合適?爲什麼?

320、如何提高HBase客戶端的讀寫性能?請舉例說明。

321、基於HadoopHA集羣進行MapReduce開發時,Configuration如何設置hbase.zookeeper,quorum屬性的值?

322、 在hadoop開發過程中使用過哪些算法?其應用場景是什麼?

323、MapReduce程序如何發佈?如果MapReduce中涉及到了第三方的jar包,該如何處理?

324、在實際工作中使用過哪些集羣的運維工具,請分別闡述其作用。

325、hadoop中combiner的作用?

326、IO的原理,IO模型有幾種?

327、Windows用什麼樣的模型,Linux用什麼樣的模型?

328、一臺機器如何應對那麼多的請求訪問,高併發到底怎麼實現,一個請求怎麼產生的,

在服務端怎麼處理的,最後怎麼返回給用戶的,整個的環節操作系統是怎麼控制的?

329、hdfs的client端,複製到第三個副本時宕機,hdfs怎麼恢復保證下次寫第三副本?block塊信息是先寫dataNode還是先寫nameNode?

330、快排現場寫程序實現?

331、jvm的內存是怎麼分配原理?

332、毒酒問題---1000桶酒,其中1桶有毒。而一旦吃了,毒性會在1周後發作。問最少需要多少隻老鼠可在一週內找出毒酒?

333、用棧實現隊列?

334、鏈表倒序實現?

335、多線程模型怎樣(生產,消費者)?平時併發多線程都用哪些實現方式?

336、synchonized是同步悲觀鎖嗎?互斥?怎麼寫同步提高效率?

337、4億個數字,找出哪些重複的,要用最小的比較次數,寫程序實現。

338、java是傳值還是傳址?

339、 java處理多線程,另一線程一直等待?

340、一個網絡商城1天大概產生多少G的日誌?

341、大概有多少條日誌記錄(在不清洗的情況下)?

342、日訪問量大概有多少個?

343、註冊數大概多少?

344、我們的日誌是不是除了apache的訪問日誌是不是還有其他的日誌?

345、假設我們有其他的日誌是不是可以對這個日誌有其他的業務分析?這些業務分析都有什麼?

346、問:你們的服務器有多少臺?

347、問:你們服務器的內存多大?

348、問:你們的服務器怎麼分佈的?(這裏說地理位置分佈,最好也從機架方面也談談)

349、問:你平常在公司都幹些什麼(一些建議)

350、hbase怎麼預分區?

351、hbase怎麼給web前臺提供接口來訪問(HTABLE可以提供對HTABLE的訪問,但是怎麼查詢同一條記錄的多個版本數據)?

352、.htable API有沒有線程安全問題,在程序中是單例還是多例?

353、我們的hbase大概在公司業務中(主要是網上商城)大概都幾個表,幾個表簇,大概都存什麼樣的數據?

354、hbase的併發問題?

Storm問題:

355、metaq消息隊列 zookeeper集羣 storm集羣(包括zeromq,jzmq,和storm本身)就可以完成對商城推薦系統功能嗎?還有沒有其他的中間件?

356、storm怎麼完成對單詞的計數?(個人看完storm一直都認爲他是流處理,好像沒有積攢數據的能力,都是處理完之後直接分發給下一個組件)

357、storm其他的一些面試經常問的問題?

二十三、面試題(18道):

358、你們的集羣規模?

開發集羣:10臺(8臺可用)8核cpu

359、你們的數據是用什麼導入到數據庫的?導入到什麼數據庫?

處理之前的導入:通過hadoop命令導入到hdfs文件系統

處理完成之後的導出:利用hive處理完成之後的數據,通過sqoop導出到mysql數據庫中,以供報表層使用。

360、你們業務數據量多大?有多少行數據?(面試了三家,都問這個問題)

開發時使用的是部分數據,不是全量數據,有將近一億行(8、9千萬,具體不詳,一般開發中也沒人會特別關心這個問題)

361、你們處理數據是直接讀數據庫的數據還是讀文本數據?

將日誌數據導入到hdfs之後進行處理

362、你們寫hive的hql語句,大概有多少條?

不清楚,我自己寫的時候也沒有做過統計

363、你們提交的job任務大概有多少個?這些job執行完大概用多少時間?(面試了三家,都問這個問題)

沒統計過,加上測試的,會與很多

364、hive跟hbase的區別是?

365、你在項目中主要的工作任務是?

利用hive分析數據

366、你在項目中遇到了哪些難題,是怎麼解決的?

某些任務執行時間過長,且失敗率過高,檢查日誌後發現沒有執行完就失敗,原因出在hadoop的job的timeout過短(相對於集羣的能力來說),設置長一點即可

367、你自己寫過udf函數麼?寫了哪些?

這個我沒有寫過

368、你的項目提交到job的時候數據量有多大?(面試了三家,都問這個問題)

不清楚是要問什麼

369、reduce後輸出的數據量有多大?

370、一個網絡商城1天大概產生多少G的日誌? 4tb

371、大概有多少條日誌記錄(在不清洗的情況下)? 7-8百萬條

372、日訪問量大概有多少個?百萬

373、註冊數大概多少?不清楚幾十萬吧

374、我們的日誌是不是除了apache的訪問日誌是不是還有其他的日誌?關注信息

375、假設我們有其他的日誌是不是可以對這個日誌有其他的業務分析?這些業務分析都有什麼?

二十四、面試題(1道):

376、有一千萬條短信,有重複,以文本文件的形式保存,一行一條,有重複。

請用5分鐘時間,找出重複出現最多的前10條。

分析:

常規方法是先排序,在遍歷一次,找出重複最多的前10條。但是排序的算法複雜度最低爲nlgn。

可以設計一個hash_table,hash_map<string, int>,依次讀取一千萬條短信,加載到hash_table表中,並且統計重複的次數,與此同時維護一張最多10條的短信表。

這樣遍歷一次就能找出最多的前10條,算法複雜度爲O(n)。

二十五、面試題(5道):

377、job的運行流程(提交一個job的流程)?

378、Hadoop生態圈中各種框架的運用場景?

379、hive中的壓縮格式RCFile、TextFile、SequenceFile各有什麼區別?

以上3種格式一樣大的文件哪個佔用空間大小.還有Hadoop中的一個HA壓縮。

380、假如:Flume收集到的數據很多個小文件,我需要寫MR處理時將這些文件合併

(是在MR中進行優化,不讓一個小文件一個MapReduce)

他們公司主要做的是中國電信的流量計費爲主,專門寫MR。

383、解釋“hadoop”和“hadoop生態系統”兩個概念。

384、說明Hadoop 2.0的基本構成。

385、相比於HDFS1.0, HDFS 2.0最主要的改進在哪幾方面?

386、試使用“步驟1,步驟2,步驟3…..”說明YARN中運行應用程序的基本流程。

387、“MapReduce 2.0”與“YARN”是否等同,嘗試解釋說明。

388、MapReduce 2.0中,MRAppMaster主要作用是什麼,MRAppMaster如何實現任務容錯的?

389、爲什麼會產生yarn,它解決了什麼問題,有什麼優勢?

397、Hadoop體系結構(HDFS與MapReduce的體系結構)、Hadoop相比傳統數據存儲方式(比如mysql)的優勢?

398、Hadoop集羣的搭建步驟、Hadoop集羣搭建過程中碰到了哪些常見問題(比如datanode沒有起來)、Hadoop集羣管理(如何動態增加和卸載節點、safe mode是什麼、常用的命令kill等)?

399、HDFS的namenode與secondarynamenode的工作原理(重點是日誌拉取和合並過程)、hadoop 1.x的HDFS的HA方案(namenode掛掉的情況如何處理、datanode掛掉的情況如何處理)?

400、HDFS的常用shell命令有哪些?分別對應哪些Client Java API?:顯示文件列表、創建目錄、文件上傳與下載、文件內容查看、刪除文件

401、HDFS的文件上傳與下載底層工作原理(或HDFS部分源碼分析):FileSystem的create()和open()方法源碼分析?

402、MapReduce計算模型、MapReduce基礎知識點(MapReduce新舊API的使用、在linux命令行運行MapReduce程序、自定義Hadoop數據類型)?

403、MapReduce執行流程:“天龍八步”,計數器、自定義分區、自定義排序、自定義分組、如何對value進行排序:次排序+自定義分組、歸約?

404、MapReduce的shuffle工作原理、MapReduce工作原理(MapReduce源碼、InputStream源碼、waitForCompletion()源碼)、jobtracker如何創建map任務和reduce任務是面試的重點。

405、MapReduce進階知識:Hadoop的幾種文件格式、常見輸入輸出格式化類、多輸入多輸出機制、MapReduce的常見算法(各種join原理和優缺點、次排序和總排序)?

406、MapReduce性能優化(shuffle調優、壓縮算法、更換調度器、設置InputSplit大小減少map任務數量、map和reduce的slot如何設置、數據傾斜原理和如何解決)?

407、HBase的體系結構和搭建步驟、shell命令與Java API、HBase作爲MapReduce的輸入輸出源、高級JavaAPI、工作原理(重點是combine和split原理)、行鍵設計原則、性能優化?

408、Hive的工作原理、兩種元數據存放方式、幾種表之間的區別、數據導入的幾種方式、幾種文件格式、UDF函數、性能調優(重點是join的時候如何放置大小表)?

409、Zookeeper、Flume、Pig、Sqoop的基本概念和使用方式,ZooKeeper被問到過其如何維護高可用(如果某個節點掛掉了它的處理機制)?

410、Hadoop2:體系結構、HDFS HA、YARN?

411、關係型數據庫和非關係型數據庫的區別?

提示:

關係型數據庫通過外鍵關聯來建立表與表之間的關係,非關係型數據庫通常指數據以對象的形式存儲在數據庫中,而對象之間的關係通過每個對象自身的屬性來決定。

對數據庫高併發讀寫、高可擴展性和高可用性的需求,對海量數據的高效率存儲和訪問的需求,存儲的結構不一樣,非關係數據庫是列式存儲,在存儲結構上更加自由。

412、hive的兩張表關聯,使用mapreduce是怎麼寫的?

提示:打標記笛卡爾乘積

413、hive相對於Oracle來說有那些優點?

提示:

hive是數據倉庫,oracle是數據庫,hive能夠存儲海量數據,hive還有更重要的作用就是數據分析,最主要的是免費。

414、現在我們要對Oracle和HBase中的某些表進行更新,你是怎麼操作?

提示:

disable '表名'

alter '表明', NAME => '列名', VERSIONS=>3

enable '表名'

415、HBase接收數據,如果短時間導入數量過多的話就會被鎖,該怎麼辦? 集羣數16臺 ,高可用性的環境。

參考:

通過調用HTable.setAutoFlush(false)方法可以將HTable寫客戶端的自動flush關閉,這樣可以批量寫入數據到HBase,而不是有一條put就執行一次更新,只有當put填滿客戶端寫緩存時,才實際向HBase服務端發起寫請求。默認情況下auto flush是開啓的。

416、說說你們做的hadoop項目流程?

417、你們公司的服務器架構是怎麼樣的(分別說下web跟hadoop)?

418、假如有1000W用戶同時訪問同一個頁面,怎麼處理?

提示:優化代碼、靜態化頁面、增加緩存機制、數據庫集羣、庫表散列。。。

419、怎樣將mysql的數據導入到hbase中?不能使用sqoop,速度太慢了

提示:

A、一種可以加快批量寫入速度的方法是通過預先創建一些空的regions,這樣當數據寫入HBase時,會按照region分區情況,在集羣內做數據的負載均衡。

B、hbase裏面有這樣一個hfileoutputformat類,他的實現可以將數據轉換成hfile格式,通過new 一個這個類,進行相關配置,這樣會在hdfs下面產生一個文件,這個時候利用hbase提供的jruby的loadtable.rb腳本就可以進行批量導入。

420、在hadoop組中你主要負責那部分?

提示:負責編寫mapreduce程序,各個部分都要參加

421、怎麼知道hbase表裏哪些做索引?哪些沒做索引?

提示:

有且僅有一個:rowkey,所以hbase的快速查找建立在rowkey的基礎的,而不能像一般的關係型數據庫那樣建立多個索引來達到多條件查找的效果。

422、hdfs的原理以及各個模塊的職責

423、mapreduce的工作原理

424、map方法是如何調用reduce方法的

425、fsimage和edit的區別?

提示:fsimage:是存儲元數據的鏡像文件,而edit只是保存的操作日誌。

426、hadoop1和hadoop2的區別?

提示:

(1) hdfs的namenode和mapreduce的jobtracker都是單點。

(2) namenode所在的服務器的內存不夠用時,那麼集羣就不能工作了。

(3)mapreduce集羣的資源利用率比較低。

單NN的架構使得HDFS在集羣擴展性和性能上都有潛在的問題,在集羣規模變大後,NN成爲了性能的瓶頸。Hadoop 2.0裏的HDFS Federation就是爲了解決這兩個問題而開發的。擴大NN容量,共享DN數據,且方便客戶端訪問。

427、hdfs中的block默認報錯幾份?

提示:3份

428、哪個程序通常與nn在一個節點啓動?並做分析

提示:jobtrack,將兩者放在一起,減少網絡訪問,IO訪問的時間,提高了效率。

429、列舉幾個配置文件優化?

430、寫出你對zookeeper的理解

提示:大部分分佈式應用需要一個主控、協調器或控制器來管理物理分佈的子進程(如資源、任務分配等)。目前,大部分應用需要開發私有的協調程序,缺乏一個通用的機制協調程序的反覆編寫浪費,且難以形成通用、伸縮性好的協調器。

ZooKeeper:提供通用的分佈式鎖服務,用以協調分佈式應用。

431、datanode首次加入cluster的時候,如果log報告不兼容文件版本,那需要namenode執行格式化操作,這樣處理的原因是?

提示:

這樣處理是不合理的,因爲那麼namenode格式化操作,是對文件系統進行格式化,namenode格式化時清空dfs/name下空兩個目錄下的所有文件,之後,會在目錄dfs.name.dir下創建文件。

文本不兼容,有可能時namenode 與 datanode 的 數據裏的namespaceID、clusterID不一致,找到兩個ID位置,修改爲一樣即可解決。

432、談談數據傾斜,如何發生的,並給出優化方案。

原因:

(1)key分佈不均勻

(2)業務數據本身的特性

(3)建表時考慮不周

(4)某些SQL語句本身就有數據傾斜

map處理數據量的差異取決於上一個stage的reduce輸出,所以如何將數據均勻的分配到各個reduce中,就是解決數據傾斜的根本所在。

優化:參數調節;

433、介紹一下HBase過濾器

434、mapreduce基本執行過程

435、談談hadoop1和hadoop2的區別

436、談談HBase集羣安裝注意事項?

提示:

需要注意的地方是 ZooKeeper的配置。這與 hbase-env.sh 文件相關,文件中HBASE_MANAGES_ZK 環境變量用來設置是使用hbase默認自帶的 Zookeeper還是使用獨立的ZooKeeper。HBASE_MANAGES_ZK=false時使用獨立的,爲true時使用默認自帶的。

某個節點的HRegionServer啓動失敗,這是由於這3個節點的系統時間不一致相差超過集羣的檢查時間30s。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章