摘要:由於目標和現實的錯位,對很多使用者來講,Hadoop成了一個在技術、應用和成本上都很沉重的產品。
本文分享自華為雲社群《Hadoop Spark太重,esProc SPL很輕》,作者:石臻臻的雜貨鋪。
隨著巨量資料時代的來臨,資料量不斷增長,傳統小機上跑資料庫的模式擴容困難且成本高昂,難以支撐業務發展。很多使用者開始轉向分散式計算路線,用多臺廉價的PC伺服器組成叢集來完成巨量資料計算任務。Hadoop/Spark就是其中重要的軟體技術,由於開源免費而廣受歡迎。經過多年的應用和發展,Hadoop已經被廣泛接受,不僅直接應用於資料計算,還發展出很多基於它的新資料庫,比如Hive、Impala等。
Hadoop的設計目標是成百上千臺節點的叢集,為此,開發者實現了很多複雜、沉重的功能模組。但是,除了一些網際網路巨頭企業、國家級通訊運營商和大型銀行外,大多數場景的資料量並沒有那麼巨大。結果,經常能看到只有幾個到十幾個節點的Hadoop叢集。由於目標和現實的錯位,對很多使用者來講,Hadoop成了一個在技術、應用和成本上都很沉重的產品。
如果真的有幾千臺計算機組成的叢集,是不可能依靠手工個性化管理的。試想,將這些計算機羅列出來,運維人員看都看不過來,更別說管理和分配任務了。再說,這麼多機器,難免會不斷出現各種故障,怎麼保證計算任務順利執行?Hadoop/Spark的開發者為了解決這些問題,編寫了大量程式碼,用於實現自動化節點管理、任務分配和強容錯功能。
但是,這些功能本身就要佔用很多計算資源(CPU、記憶體和硬碟等),如果用到幾臺到十幾臺節點的叢集上,就太過沉重了。叢集本來就不大,Hadoop還要佔用相當一部分的資源,非常不划算。
不僅如此,Hadoop產品線很長,要把這些模組都放在一個平臺上執行,還要梳理好各個產品之間的相互依賴性,就不得不實現一個包羅萬象的複雜架構。雖然大多數場景只用其中一兩個產品,也必須接受這個複雜、沉重的平臺。
後來出現的Spark彌補了Hadoop對記憶體利用的不足,技術上是不是可以變輕呢?很遺憾,Spark走向了另一個極端,從理論模型上就只考慮記憶體計算了。特別是Spark 中的 RDD 採用了 immutable 機制,在每個計算步驟後都會複製出新的 RDD,造成記憶體和 CPU 的大量佔用和浪費,離開大記憶體甚至無法執行,所以技術上還是很重。
Hadoop技術上太過複雜,也就意味著安裝和運維會很麻煩。叢集只有幾臺計算機時,卻不得不使用為幾千臺節點叢集設計的節點管理、任務分配和容錯功能。可想而知,安裝、設定、偵錯都很困難,日常執行的維護、管理工作也不容易。
即使克服這些困難讓Hadoop執行起來了,編寫巨量資料計算程式碼時還會面臨更大的麻煩。Hadoop程式設計的核心框架是MapReduce,程式設計師要編寫並行程式,只要寫 Map 和 Reduce 動作即可,用來解決求和、計數等簡單問題也確實有效。但是,遇到複雜一些的業務邏輯,用MapReduce程式設計就會變得非常困難。例如,業務計算中很常見的JOIN計算,就很難用MapReduce實現。再比如,很多和次序有關的運算實現起來也很困難。
Spark的Scala語言具備一定的結構化資料計算能力,是不是能簡單一些呢?很可惜,Scala使用難度很大,難學更難精。遇到複雜一些的運算邏輯,Scala也很難寫出來。
MapReduce、Scala都這麼難,所以Hadoop/Spark計算語法開始迴歸SQL語言。Hive可以將SQL轉化為MapReduce所以很受歡迎,Spark SQL的應用也比Scala廣泛的多。但是,用SQL做一些常規查詢還算簡單,用於處理多步驟過程計算或次序相關運算還是非常麻煩,要寫很複雜的UDF。而且,許多計算場景雖然勉強能用SQL實現,但是計算速度卻很不理想,也很難進行效能調優。
雖然 Hadoop 軟體本身開源免費,但它技術複雜、使用困難,會帶來高昂的綜合成本。
前面說過,Hadoop自身會佔用過多的CPU、記憶體和硬碟,而Spark需要大記憶體支撐才能正常執行。所以不得不為Hadoop/Spark採購更高設定的伺服器,要增加硬體支出。
Hadoop/Spark使用困難,就需要投入更多的人力去完成安裝、運維,保證Hadoop/Spark的正常運轉;還要投入更多的開發人員,程式設計實現各種複雜的業務計算,要增加人力資源成本。
由於使用過於困難,很多使用者不得不採購商業公司的收費版本Hadoop/Spark,價格相當可觀,會大幅增加軟體採購成本。
既然Hadoop如此沉重,為什麼還有很多使用者會選擇它呢?答案很簡單:暫時找不到別的選擇,也只有Hadoop勉強可用,好歹知名度高一些。
如此一來,使用者就只能安裝、設定Hadoop的重型應用,並忍受Hadoop本身對計算資源的大量消耗。小規模叢集的伺服器數量本來就不多,Hadoop又浪費了不少,小馬拉大車,最後執行的效果可想而知。花了大價錢採購、費事費力的使用Hadoop,實際計算的效能卻不理想。
就沒有別的選擇了?
開源的esProc SPL是輕量級巨量資料計算引擎,採用了全新的實現技術,可以做到技術輕、使用簡單、成本低。
本文開頭說過,越來越大的資料量讓傳統資料庫撐不住,所以使用者只能轉向分散式計算技術。而資料庫之所以撐不住,是因為SQL難以實現高速演演算法,巨量資料運算效能只能指望資料庫的優化引擎,遇到複雜計算時,優化引擎又常常無能為力。
所以,我們應該想辦法設計更高效的演演算法,而不是一味地追求分散式計算。按照這個思路,SPL提供了眾多高效能演演算法(有許多是業界首創)以及高效的儲存方案,同等硬體環境下可以獲得遠超過資料庫的運算效能。安裝在單機上的SPL就可以完成很多巨量資料計算任務,架構比叢集簡單很多,從技術上自然就輕的多了。
SPL的高效能演演算法有下面這些:
對於資料量更大的情況,SPL實現了輕量級叢集計算功能。這一功能的設計目標是幾臺到十幾臺節點的叢集,採用了與Hadoop完全不同的實現方法。
SPL叢集不提供複雜沉重的自動化管理功能,而是允許對每個節點進行個性化設定。程式設計師可以根據資料特徵和計算目標來決定各節點儲存什麼樣的資料,完成哪些計算。這樣做,不僅大大降低了架構複雜度,也是提升效能的重要手段。
以訂單分析為例,訂單表很大,要通過產品號欄位與較小的產品表主鍵做關聯,再按照產品供應商分組彙總訂單金額。SPL叢集可以很容易的將訂單表分段存放在各個節點的硬碟上,再將較小的產品表讀入每個節點的記憶體中。計算時,每個節點僅對本機上的訂單分段和產品資料做關聯、分組彙總,可以縮短總計算時間;再將結果傳輸到一個節點上做二次彙總。由於傳輸的是第一次彙總的結果,資料量小、網路傳輸時間較短。總體來說,這個方案可以獲得最佳效能,雖然程式設計師需要做一些更細緻的工作,但對於小規模叢集來說,增加的工作量並不大。
SPL也不提供超強的容錯能力,不會像Hadoop那樣,在有節點故障的情況下,還要保證任何一個任務都會執行成功。實際上,大多數計算任務的執行時間都在幾個小時以內,而幾臺、十幾臺機器的叢集一般都能做到較長時間正常執行,不會這麼頻繁的出故障。即使偶爾出現節點故障導致任務執行失敗,再重新計算一遍也可以接受,畢竟這種情況不會經常發生。所以,SPL的容錯能力只是保證有少數節點故障的時候,整個叢集還能繼續工作並接受新任務(包括重算的任務),這就大大降低了SPL叢集的複雜度。
在記憶體計算方面,SPL沒有使用Spark RDD的 immutable機制,而是採用了指標式複用機制,利用地址(指標)存取記憶體,在資料結構沒有改變的情況下,直接用原資料的地址形成結果集,不必每個計算都將資料複製一遍,僅僅多儲存一個地址(指標),可以同時減少 CPU 和記憶體的消耗,執行起來要比Spark輕很多了。並且,SPL改進了當前的外存計算演演算法體系,降低了複雜度並擴大了適應範圍,可以做到內外存計算結合,充分提升計算效能的同時,還不像Spark那樣依賴大記憶體。
SPL採用輕量級技術,自然更容易安裝、設定和執行維護。SPL不僅可以作為獨立伺服器使用,還很容易整合到需要高效能運算的應用中,比如即時查詢系統,只要引入幾個jar包即可。Hadoop則很難整合,只能在邊上作為一個資料來源執行。有些臨時性資料需要隨時進行處理,則可使用SPL的桌面整合式開發環境視覺化地計算,快速得到結果。如果要安裝部署Hadoop,那麼等環境搭建好時臨時資料任務已經過期了。
前面展示的眾多SPL高效能演演算法,也能讓巨量資料計算程式設計變得簡單。程式設計師可以在較短時間內掌握這些演演算法函數,學習成本相對較低。而且,使用這些現成的函數很容易實現各種複雜的計算需求,不僅比MapReduce/Scala簡單,比SQL也簡單很多。
比如,以電商網站常見的漏斗分析為例,用SQL實現三步漏斗的程式碼大致如下:
with e1 as ( select gid,1 as step1,min(etime) as t1 from T where etime>= to_date('2021-01-10', 'yyyy-MM-dd') and etime<to_date('2021-01-25', 'yyyy-MM-dd') and eventtype='eventtype1' and … group by 1 ), with e2 as ( select gid,1 as step2,min(e1.t1) as t1,min(e2.etime) as t2 from T as e2 inner join e1 on e2.gid = e1.gid where e2.etime>= to_date('2021-01-10', 'yyyy-MM-dd') and e2.etime<to_date('2021-01-25', 'yyyy-MM-dd') and e2.etime > t1 and e2.etime < t1 + 7 and eventtype='eventtype2' and … group by 1 ), with e3 as ( select gid,1 as step3,min(e2.t1) as t1,min(e3.etime) as t3 from T as e3 inner join e2 on e3.gid = e2.gid where e3.etime>= to_date('2021-01-10', 'yyyy-MM-dd') and e3.etime<to_date('2021-01-25', 'yyyy-MM-dd') and e3.etime > t2 and e3.etime < t1 + 7 and eventtype='eventtype3' and … group by 1 ) select sum(step1) as step1, sum(step2) as step2, sum(step3) as step3 from e1 left join e2 on e1.gid = e2.gid left join e3 on e2.gid = e3.gid
SQL寫出來要三十多行,理解起來有相當的難度。如果用MapReduce/Scala來寫,會更加困難。即使是用SQL實現,寫出來的這段程式碼和漏斗的步驟數量相關,每增加一步就要再增加一段子查詢。
相比之下,SPL 就簡單得多,處理任意步驟數都是下面這樣簡潔的程式碼:
SPL叢集計算的程式碼也非常簡單,比如前面提到的訂單分析計算,具體要求是:大訂單表分段儲存在4個節點上,小產品表則載入到每個節點的記憶體中,兩表關聯之後要按照產品供應商分組彙總訂單金額。用SPL寫出來大致是下面這樣:
這段程式碼執行時,任務管理(記憶體載入、任務拆分、合併等)所需要的計算資源,遠遠小於關聯和分組彙總計算的消耗。如此輕便的任務管理功能,可以在任意節點、甚至是整合式開發環境IDE上執行。
與Hadoop相同,SPL也是開源軟體,不同的是SPL不僅軟體免費,綜合成本也非常低。
SPL安裝、設定、運維很容易,可以大大降低支援人員的人力資源成本。同時,由於SPL降低了巨量資料計算程式設計的難度,程式設計師很容易實現各種複雜的計算,開發效率顯著提高,也就節省了程式設計師的人力資源成本。
而且,由於SPL技術體系非常輕,平臺自身佔用的CPU、記憶體和硬碟很少,可以讓更多的資源用於業務計算,能大幅提高硬體利用率。SPL也不像Spark那樣依賴大記憶體,總體來說,大大減少了硬體採購成本。
SPL技術輕、自身消耗小,而且還提供了眾多高效能演演算法,所以,在幾個到幾十個節點的叢集,甚至單機的情況下,比Hadoop/Spark有更好的效能表現。
Spark:6節點,每節點4CPU核,平均計算時間:25秒。
SPL:單機,8執行緒計算,平均計算時間可達10秒。程式碼量僅有Spark Scala的一半。
Hadoop上某OLAP伺服器:虛擬機器器100CPU核,計算時間:120秒。
SPL:虛擬機器器12CPU核,計算時間:僅4秒。效能提高250倍。
基於Hadoop的某商用資料倉儲:高並行時無法達到秒級的響應速度,只好換用6臺ES叢集。
SPL單機:達到6臺ES叢集同樣的並行和響應能力。
總結來說,Hadoop/Spark是源自頭部網際網路企業的重型解決方案,適合需要有超大規模叢集的巨大企業。很多場景的資料雖然也不少,但小叢集甚至無叢集就足夠處理,遠沒多到這些巨大企業的規模,也沒有那麼多的硬體裝置和維護人員。這種情況下,輕量級的巨量資料計算引擎SPL是首選,投入很低的成本,就可以做到技術輕、使用簡便,而且還能提高開發效率、達到更高的效能。