大數據基石——Hadoop與MapReduce

本文始發於我的公衆號:TechFlow
近兩年AI成了最火熱領域的代名詞,各大高校紛紛推出了人工智能專業。但其實,人工智能也好,仍是前兩年的深度學習或者是機器學習也罷,都離不開底層的數據支持。對於動輒數以TB記級別的數據,顯然常規的數據庫是知足不了要求的。今天,咱們就來看看大數據時代的幕後英雄——Hadoop。
 
Hadoop這個關鍵詞其實有兩重含義,最先它其實指的就是單純的分佈式計算系統。可是隨着時代的發展,Hadoop系統擴大,現在hadoop已是成了一個完整的技術家族。從底層的分佈式文件系統(HDFS)到頂層的數據解析運行工具(Hive、Pig),再到分佈式系統協調服務(ZooKeeper)以及分佈式數據庫(HBase),都屬於Hadoop家族,幾乎涵蓋了大半大數據的應用場景。在Spark沒有流行以前,Hadoop一直是大數據應用中的絕對主流,即便是如今,依舊有大量的中小型公司,仍是依靠Hadoop搭建大數據系統。
 
現在的Hadoop雖然家族龐大,可是早年Hadoop的結構很是簡單,幾乎只有兩塊,一塊是分佈式文件系統,這個是整個數據的支撐,另外一個就是MapReduce算法。
 
 
 
分佈式文件系統
 
大數據時代,數據的量級大規模增加,動輒以TB甚至PB計。對於這麼海量的數據,若是咱們還使用常規的方法是很是困難的。由於即便是 O(n) 的算法,將全部的數據遍歷一遍,所消耗的時間也確定是以小時計,這顯然是不能接受的。不只如此,像是MySQL這樣的數據庫對於數據規模也是有限制的,一旦數據規模巨大,超過了數據庫的承載能力,那幾乎是系統級的噩夢(重要的數據不能丟棄,可是如今的系統沒法支撐)。
 
 
 
 
既然咱們把數據所有存儲在一塊兒,會致使系統問題,那麼咱們可不能夠把數據分紅不少份分別存儲,當咱們須要處理這些數據的時候,咱們對這些分紅許多小份的數據分別處理,最後再合併在一塊兒
 
答案固然是可行的,Hadoop的文件系統正是基於這個思路。
 
在HDFS當中,將數據分割成一個一個的小份。每一個小份叫作一個存儲塊,每一個存儲塊爲64MB。這樣一個巨大的文件會被打散存儲在許多存儲塊當中。當咱們須要操做這些數據的時候,Hadoop會同時起動許多個執行器(executor)來併發執行這些存儲塊。理論上來講,執行器的數量越多,執行的速度也就越快。只要咱們有足夠多的執行器,就能夠在短期內完成海量數據的計算工做。
 
可是有一個小問題,爲何每一個存儲塊恰恰是64MB,而不是128MB或者256MB呢?
 
緣由也很簡單,由於數據存儲在硬盤上,當咱們查找數據的時候,CPU實際上是不知道數據究竟存放在什麼地方的。須要有一個專門的程序去查找數據的位置,這個過程被稱爲尋址。尋址的時候會伴隨着硬盤的高速旋轉。硬盤的旋轉速度是有限的,天然咱們查找文件的速度也會存在瓶頸。若是存儲塊過小,那麼存儲塊的數量就會不少,咱們尋址的時間就會變長。
 
 
若是存儲塊設置得大一些行不行?也不行,由於咱們在執行的時候,須要把存儲塊的數據拷貝到執行器的內存裏執行。這個拷貝伴隨着讀寫和網絡傳輸的操做,傳輸數據一樣耗時很多。存儲塊過大,會致使讀寫的時間過長,一樣不利於系統的性能。根據業內的說法,但願尋址的耗時佔傳輸時間的1%,目前的網絡帶寬最多能夠作到100MB/s,根據計算,每一個存儲塊大約在100MB左右最佳。也許是程序員爲了湊整,因此選了64MB這個大小。
 
目前爲止,咱們已經搞清楚了Hadoop內部的數據存儲的原理。那麼,Hadoop又是怎麼併發計算的呢?這就下一個關鍵詞——MapReduce出場了。
 
MapReduce
 
嚴格提及來MapReduce並非一種算法, 而是一個計算思想。它由map和reduce兩個階段組成。
 
 
先說map,MapReduce中的map和Java或者是C++以及一些其餘語言的map容器不一樣,它表示的意思是映射。負責執行map操做的機器(稱做mapper)從HDFS當中拿到數據以後,會對這些數據進行處理,從其中提取出咱們須要用到的字段或者數據,將它組織成key->value的結構,進行返回。
 
爲何要返回key->value的結構呢?直接返回咱們要用到的value不行嗎?
 
不行,由於在map和reduce中間,Hadoop會根據key值進行排序,將key值相同的數據歸併到一塊兒以後,再發送給reducer執行。也就是說,key值相同的數據會被同一個reducer也就是同一臺機器處理,而且key相同的數據連續排列。reducer作的是經過mapper拿到的數據,生成咱們最終須要的結果。
 
Sample
 
這個過程應該不難理解, 可是初學者可能面臨困惑,爲何一開始的時候,要處理成key-value結構的呢?爲何又要將key值相同的數據放入一個reducer當中呢,這麼作有什麼意義?
 
這裏,咱們舉一個例子,就清楚了。
 
MapReduce有一個經典的問題,叫作wordCount,顧名思義就是給定一堆文本,最後計算出文本當中每一個單詞分別出現的次數。Map階段很簡單,咱們遍歷文本當中的單詞,每遇到一個單詞,就輸出單詞和數字1。寫成代碼很是簡單:
 
def map(text): for line in text: words = line.split(' ') for w in words: print(w, 1)
 
這樣固然仍是不夠的,咱們還須要把相同的單詞聚合起來,清點一下看看究竟出現了多少次,這個時候就須要用到reducer了。reducer也很簡單,咱們讀入的是map輸出的結果。因爲key相同的數據都會進入同一個reducer當中,因此咱們不須要擔憂遺漏,只須要直接統計就行:
def reduce(text): wordNow = None totCount = 0 for line in text: elements = line.split(' ') word, count = elements[0], int(elements[1]) # 碰到不一樣的key,則輸出以前的單詞以及數量 if word != wordNow: if wordNow is not None: print(wordNow, totCount) wordNow = word totCount = 1 #不然,更新totCount else: totCount += count
若是咱們map的結果不是key-value結構,那麼Hadoop就沒辦法根據key進行排序,並將key相同的數據歸併在一塊兒。那麼咱們在reduce的時候,同一個單詞就可能出如今不一樣的reducer當中,這樣的結果顯然是不正確的。
固然,若是咱們只作一些簡單的操做,也能夠捨棄reduce階段,只保留map產出的結果。
 
如今看MapReduce的思想其實並不複雜,可是當年大數據還未興起的時候,MapReduce橫空出世,既提高了計算性能,又保證告終果的準確。一舉解決了大規模數據並行計算的問題,回想起來,應該很是驚豔。雖然現在技術更新,尤爲是Spark的流行,搶走了Hadoop許多榮光。但MapReduce的思想依舊在許多領域普遍使用,好比Python就支持相似的MapReduce操做,容許用戶自定義map和reduce函數,對數據進行並行處理。
 
不過,MapReduce也有短板,好比像是數據庫表join的操做經過MapReduce就很難實現。並且相比於後來的Hive以及Spark SQL來講,MapReduce的編碼複雜度仍是要大一些。但無論怎麼說,瑕不掩瑜,對於初學者而言,它依舊很是值得咱們深刻了解。
 
掃碼關注,獲取更多文章:
相關文章
相關標籤/搜索