MapReduce最先由Google提出,論文出處《DEAN, J., AND GHEMAWAT, S. MapReduce: Simplified data processing on large clusters.》,有興趣的話能夠去看看原文,固然也有翻譯。這篇文章和Google的《Bigtable: A Distributed Storage System for Structured Data 》是同期的,是Google對外介紹自身大規模數據處理架構的論文。程序員
MapReduce受Lisp等函數式編程語言的Map 和 Reduce 語義啓發,關於函數式編程語言,筆者瞭解的很少,關於其最主要的一點,是由程序運行時負責程序的調用、執行等,理解這一點很重要,由於由運行時負責調用是MR的核心,用戶不須要去關心程序如何實現,它的規模多大,如何並行計算,多少個線程等等,用戶只須要關心它們的語義,並按照語義去寫Map函數和Reduce函數便可。redis
Map 也即映射,將一個或多個數據源映射爲key-value樣式sql
Reduce 也即概括,將Mapper的Key-value進行計算,以得出結果(同爲key-value樣式)數據庫
整體而言很是好理解,但也所以容易引出個問題——Why?它與sql的select from where 有什麼區別呢?Mapper也要篩選,Reducer也要計算。由於如今不少語言和數據庫都引入了MR,這一問題變得尤其明顯,原本它只是在大規模數據集羣上計算,實在不理解還能用,「哦,框架就是這樣」搪塞過去,如今不行了。編程
這個問題也困擾過我,如今個人理解是一點——交集。不少數據會符合一堆規則,若是單獨的按照這些規則,一個一個挑出來,會形成重複計算,重複IO——不少時候符合條件A的數據也符合條件B,若是採用相似先計算選出選A,再選B的方式,則會有2次IO訪問或是重複計算,浪費了算力(天然也省了內存),但當數據量大到必定的程度,節省下來的內存便進入長尾效應,並且對計算速度的拖累也更大,綜合考慮下來,MR先使用Mapper無腦選候選數據,再使用Reducer計算更符合效率和成本。安全
關於DFS——Distributed File System.分佈式文件系統,是Hadoop HDFS 的核心,也即基礎設施,在面對大規模數據時,有這樣2點重點,一是,省錢,二是,安全。對於這點Google提出的觀點是,假設我買出錯率很高的硬盤,1/1000,那麼當我有3臺這樣的硬盤,它們同時出錯的機率是多少呢?1/1000*1/1000*1/1000=1/1000000000,變得可接受了,並且廉價硬盤也帶來了成本的降低,這樣的文件系統就能夠做爲大數據的基礎設施。架構
Hadoop(Hive)的MR是創建在HDFS之上的,原理也很是簡單粗暴,讀入文件,而後藉助MR框架,去大規模並行計算。Now,MR理論上能夠接受任何輸入,但本着開箱即用的道理,絕大部分人仍是會選擇從文件中讀取,而後進行計算,這樣的話,瓶頸就會在IO上面,並行計算的算力也沒被解放開來。app
想要MR爲你的計算實時服務,你就須要不少Wrapper從你的庫中獲取數據源,或者加速文件的讀取,因此後面Hadoop萌生出那麼多框架,也是有緣由的。框架
同時提到這句話,筆者注意到的一點是,在Google BigTable 論文中提到的Big Table是支持MR的,在其論文中有這樣一句話編程語言
Bigtable can be used with MapReduce [12], a framework for running large-scale parallel computations developed at Google. We have written a set of wrappers that allow a Bigtable to be used both as an input source
and as an output target for MapReduce jobs.
後續Hadoop的山寨版——Hbase,雖然也支持,不過貌似效率不高,更多的仍是用Hive進行使用,並且在程序中,基本仍是對HDFS的直接操做。對於Hbase而言,反而更像是繞了遠路,HDFS上的HFile讀取,而後到Hbase,再傳到Mapper裏面,性能怎麼樣更多的仍是看你,或者Hbase的優化,由於這下連文件都看不到了。Google也不傻,既然提了這一說,那麼BigTable底層實現和Hbase的區別,相比是很大的。
回顧完上面這些,不難發現,Hadoop,起碼早期版本,就是一個空蕩的平臺,這也爲後續一堆框架的提出埋下了伏筆。
提到MongoDB,這個後起之秀,就想起了一篇文章,《一個時代的終結——大數據已死》
Hadoop還面臨這樣的挑戰:NoSQL數據庫和對象存儲提供商在解決Hadoop最初旨在幫助解決的部分存儲和管理難題方面取得了進展。隨着時間的推移,在Hadoop上支持業務連續性面臨挑戰,加上支持實時、地理空間及其餘新興的分析使用場合方面缺少靈活性,這使得Hadoop面對海量數據時很難在批處理以外大有做爲。
我的以爲文章寫的仍是不錯的,每一個新興技術的出現都必將經歷一波炒做,再到冷卻,直至它做爲廣大技術棧中不起眼(基礎)的一隅,凡事總要經歷個過程,大數據已死是失去了熱度,它已做爲基礎能力,再也不適合被大書特書。
回到MR上面來,筆者目前的項目呢,也是爛大街的Hadoop,對於MR的使用能夠說是反面教材了,對數據集的中間結果處理使用了大量的 temp文件。並且還使用的是最簡單最低效的TextFormat,每次mr都有大量的parse,做爲程序員腦中的基礎概念,關於程序的性能主要就幾點,一個是IO,一個是算力(Taraflops),減小IO和沒必要要的計算是時刻記住的重點,而這項目能夠說2點禁忌全佔了。而我若是想改,其實不光是改MR的邏輯,還要改HDFS裏文件的存儲方式,這樣一來以新版和舊版爲分界線,就須要一個Adapter來作老數據的讀取……
那這樣一來問題其實很明顯,Hadoop自己就有紛繁複雜的技術棧, Hive,Spark,Hbase,Accumulo,Kylin,Storm ……要保證項目組的每個人深入理解這一堆技術棧,非但要調研成本,並且一旦換需求了,是否是還要對應改動呢?並且爲了知足一些實時性的需求,還不得不從Hive MR到HBase,再入redis以提供大規模低時延調用。對於不少時候,只想要使用MR而已,又何苦這麼麻煩呢。
在這種狀況下,像MongoDB這樣的庫就提供了一個折中的辦法,它不支持超大規模數據量的分析,這種狀況下性能堪憂,可是對於大規模(SQL已經自閉)的程度仍是OK的,經過MongoDB 的MR,咱們仍然能借助MR思惟去處理大規模數據,若是不是長期存儲的類型,MongoDB給出的方案反倒更爲經濟。
Java自1.8以後引入了Stream API,Map和Ruduce也做爲同期被引入,與Hadoop的MR不一樣,它只能做爲 Collection 接口下的方法,並不支持對每一個Key,value進行計算,而只能得出一個結果。而它的重點在於,若是使用了 parallelStream() ,便能輕鬆地執行並行化計算。
List<Integer> source=new ArrayList<>(); source.add(1); source.add(2); Optional<Integer> sum=source.stream().map(new Function<Integer, Integer>() { @Override public Integer apply(Integer t) { return t+1; } }).reduce(new BinaryOperator<Integer>() { @Override public Integer apply(Integer t, Integer u) { return t+u; } }); System.out.println(sum.get());
待續。