天天看點

資料蔣堂 | Hadoop中理論與工程的錯位

Hadoop是目前重要的大資料計算平台,它試圖摒棄傳統資料庫的理念,重新建構一套新的大資料體系。但是,這并不是件很容易的事,在Hadoop的設計和實作中能看到一些先天不足的地方,其中一點就是把理論問題和工程問題給搞擰了。

所謂理論方法,是指試圖解決問題的一般情況,設計通用的算法能适應盡量多的情況,并努力使算法的複雜度降低。在研究問題時不會考慮具體環境下某個具體動作是否可以執行以及該動作消耗的資源,而會假想一個理想的環境;工程方法則相反,不需要考慮普遍的一般情況,而是針對某個具體問題,充分利用目前環境提供的便利,并充分考慮每個具體動作消耗的資源(包括時間),盡量高效率低成本地實作目标。原則上,在設計體系模型時要理論化,而在編碼實作時則要工程化,這樣才能做出一個即能解決足夠多問題且效率也可接受的産品。

但是,Hadoop在不少地方把這個事情搞反了。本該由理論解決的一般性問題被用工程方法簡化成特定問題,而具體實作時又把本該在工程層面優化的問題想得過于理論化。導緻的結果就是能友善解決的問題太少,而解決問題時效率又太低。一句話說就是理論問題工程化,工程問題理論化。

MapReduce是Hadoop中關鍵的并行機制,經過多輪封裝改進,這個模型現在仍然是Hadoop的算法核心。這個方法認為可以将一個大任務拆成一些無關的小任務,分别處理(Map)後再按某個鍵值歸攏到一起再做處理(Reduce)。Hadoop實作好這個架構後,程式員就隻要寫Map和Reduce動作即可了,這樣就編寫并行程式就會簡單很多。

MapReduce用來處理求和、計數等簡單問題也确實有效,但世界可沒有這麼簡單!

琢磨一下用MapReduce去實作JOIN運算的麻煩度就知道了(具體做法可以從網上找到,這裡不細說了),而這種有關聯的運算在現實需求中相當常見,其它一些次序有關的運算用MapReduce實作也很困難。也就是說,MapReduce算法能夠友善描述的運算太少了,這個模型的适應面太窄。基于這個理論實作的産品,面對複雜運算時基本上起不到減少工作量的目标,甚至根本無法應用。本該在理論上研究出更通用的算法,卻被工程化成簡單情況。

然而,Hadoop在實作MapReduce架構時,卻又缺乏對具體情況的考慮,而是假想了一個理想環境。Hadoop認為叢集節點機可以無窮多,任何性能問題都隻要增加節點就可以解決,這樣就沒興趣去關注單機性能了,肆意地跑出多個程序而很少采用經常效率更高(但不總是)的多線程手段;Hadoop不考慮外存讀寫的巨大延遲,Map過程 的中間結果要寫盤暫存,理論上複雜度其實也不算很高(讀寫次數基本是确定的),但實際運作效率之低令人難以容忍,很難想象有工程經驗的程式員敢采用這種機制。實測情況是大概四五個節點的hadoop叢集才能趕得上被充分工程優化後的單台機器性能。

Spark也有類似的問題。Spark前的Hadoop在工程上對記憶體利用不足(如前述的MapReduce總是要落盤),而Spark又走向另一個極端,從理論模型上就隻考慮記憶體計算了。我們知道,外存計算和記憶體計算是很不一樣的,外存計算要複雜困難得多,而大資料常常面臨外存計算,原則上我們應當改進目前的外存計算算法體系,努力降低複雜度并擴大适應範圍,而不是簡單避開這個困難,這就是刻意簡化問題了,适應面會大折折扣。

退一步講,就算隻考慮記憶體計算,能做好也是有相當意義的。但是,Spark在實作時卻又走入了理論化的窠臼,它把那個RDD搞成immutable,這個機制有很強的理論色彩,和數學運算中的抽象資料類型一緻,用來描述算法确實很美。可是,實際運作時将造成大量沒有必要的記憶體複制,本來是打算提高性能的,卻得不償失,然後又要再用其它手段去繞。

類似的情況,細糾下去還有。發明新理論确實很難,為降低難度而簡化問題還可以了解(其實傳統資料庫領域已經積累了不少這理論,隻是學會并不算很難),但在工程實作時又搞得理論化就難以了解了,這樣怎麼會有高性能?

原文釋出時間為:2018-03-30

本文作者:蔣步星