Lambda架構的質疑

Nathan Marz 寫了一篇非常受歡迎的部落格文章,描述了 Lambda 架構(如何打破CAP定理)。Lambda 架構是一種在 MapReduce 和 Storm 或類似系統之上構建流處理應用程式的方法。

1. 什麼是Lambda架構

Lambda架構類似於下圖:

這種架構的工作方式是接收日誌,並將其並行輸入批處理系統和流處理系統。我們需要兩次邏輯處理,一次在批處理系統中,一次在流處理系統中。我們可以在查詢時將兩個系統的結果融合在一起來產生完整的答案。

上述 Lambda 架構可以有很多變化,在這做了一些簡化。例如,我們可以切換到與 Kafka、Storm 和 Hadoop 等類似的系統上,並使用兩個不同的資料庫來存儲輸出表,其中一個針對實時做特定優化,另一個針對批次更新做特定優化。

Lambda 架構針對複雜非同步轉換構建的應用程式,這些應用程式需要以低延遲(例如幾秒鐘到幾小時)運行。一個很好的例子就是新聞推薦系統,該系統需要抓取各種新聞源,處理和規範化所有輸入,然後對它進行索引,排序和存儲以進行服務。

我曾在 LinkedIn 參與構建許多實時數據系統以及管道。其中有一些也是以這種方式工作,經過思考後我認為這不是我最好的方法。我認為有必要陳述一下該架構的優缺點,並給出我喜歡的替代方案。

2. 優點

我贊同 Lambda 架構強調保持輸入數據的不變性。我認為將數據處理建模為一系列的物化階段具有很多優點。這是使大型 MapReduce 工作流易於處理的原因之一,因為它使我們能夠獨立調試每個階段。我在 The Log: What every software engineer should know about real-time data』s unifying abstraction 寫了一些有關接收和轉換不可變數據流的想法。

我也喜歡這種架構解決了數據重處理(Reprocessing)的問題。重處理是流處理的主要挑戰之一,但經常被忽略。』重處理』 是指再一次處理輸入數據以重新獲取輸出結果。這是一個顯而易見但又經常被忽略的要求。程式碼可能會一直更改。因此,如果我們有從輸入流中獲取輸出數據的程式碼,只要程式碼更改,就需要重新計算輸出以查看更改的效果。

為什麼程式碼會發生更改?可能是應用程式在不斷演進,我們想計算以前不需要的新欄位。或者我們發現了一個錯誤並需要修改。無論如何,我們都需要重新計算輸出。我們發現,許多嘗試構建實時數據處理系統的人對此問題並沒有過多的思考,最終因為無法方便地重處理數據而無法快速發展。Lambda 結構值得一提,因為它解決了這個問題。

Lambda 結構還提出了許多其他目標,但我認為沒有太大意義。其中一個是,實時處理與批處理相比,本質上是近似的,但功能較弱且消耗更大。實際上我並不贊同。確實,現有的流處理框架還不如 MapReduce 成熟,但我們沒有理由說流處理系統不能像批處理系統那樣提供強大的語義保證。

我聽到的另一個解釋是,Lambda 結構允許混合使用具有不同權衡取捨的數據系統,從而在某種程度上』擊敗了CAP定理』。長話短說,儘管在流處理中肯定存在延遲與可用性之間的權衡,但因為這是非同步處理架構,所計算的結果不會立即與輸入數據保持一致。不幸的是,CAP定理仍然沒有打破。

3. 劣勢

Lambda 架構的問題在於,在兩個複雜的分散式系統中維護產生相同結果的程式碼會非常痛苦。我認為這個問題不會得到解決。

在像 Storm 和 Hadoop 這樣的分散式框架中進行編程一般會比較複雜。不可避免地針對其所運行的框架進行專門的程式碼編程。似乎每一個人都會認為實現 Lambda 架構會帶來操作複雜性。

為什麼不能對流處理系統進行改進來處理全部的問題呢?解決這個問題的一個建議方法是要有一種同時可以對實時框架和批處理框架進行抽象的語言或框架。我們使用這種更高層次的框架編寫程式碼,然後對其進行編譯來在後台進行流處理 或 MapReduce。Summingbird 就是這樣的一個框架,肯定會使事情變得更容易,但我認為這同樣不能解決問題。

最終,即使我們可以避免對應用程式進行兩次編碼,但運行和調試兩個系統的操作負擔也非常高。而且任何新的抽象都只能提供兩個系統所支援的功能的交集。更糟糕的是,致力於這種新的超級框架會與 Hadoop 生態系統(Hive,Pig,Crunch,Cascading,Oozie等)隔離開來。

類比,想想跨資料庫 ORM 框架臭名昭著的困難。並考慮到這隻能在非常相似的系統上進行抽象,使用(幾乎)標準化的介面語言提供幾乎相同的功能。在勉強穩定的分散式系統之上構建完全不同的編程範例的抽象要困難很多。

4. 實踐

實際上,我們已經在 LinkedIn 上進行了幾輪這樣的嘗試。我們建立了各種混合 Hadoop 架構,甚至建立了特定領域的 API,可以允許』透明』地在實時或在 Hadoop 中運行。這些方法都行得通,但沒有一個是令人高興或富有成效的。要使在兩個不同系統中編寫的程式碼完全同步非常困難。

隱藏底層框架的 API 被證明是抽象的最大漏洞。最終,我們必須需要具備豐富的 Hadoop 知識以及對實時層深入了解,並增加了新的要求,即在調試問題或嘗試調優性能時,我們需要對API如何轉換為底層系統必須有足夠的了解。

我的建議是,如果您對延遲不敏感,則使用像 MapReduce 這樣的批處理框架,如果敏感,則使用流處理框架,除非必須使用,否則不要嘗試同時使用這兩者。

那麼,我們為什麼對 Lambda 架構感興趣呢?我認為是因為人們越來越需要構建複雜的低延遲處理系統。他們擁有的兩個系統並不能完全解決他們的問題:一個是可以處理歷史數據的可伸縮高延遲的批處理系統,另一個是無法重處理的低延遲流處理系統。通過將這兩個系統進行融合,實際上可以構建可行的解決方案。

從這個意義上講,儘管可能很痛苦,但我認為 Lambda 架構解決了一個通常被忽略的重要問題。但是我不認為這就是大數據的新規範或未來。這只是由於現有工具的局限性所造成的一個臨時狀態。我認為還會有更好的選擇。

5. 代替方案

作為設計基礎架構的人,我認為一個明顯的問題是:為什麼不能僅僅改進流處理系統來處理全部問題呢?為什麼還需要和另外一個批處理系統配合運行?為什麼在程式碼更改時不能進行實時處理同時能重處理呢?流處理系統已經有了並行度的概念,為什麼不能通過增加並行度以及非常非常快地重播歷史數據來處理重新處理問題呢?答案是我們可以做到這一點,並且我認為如果我們今天正在構建這種類型的系統,那麼這實際上是一種合理的替代架構。

當我與其它人討論這個問題時,他們有時會告訴我,對於高吞吐量的歷史數據處理,流處理是不合適的。我認為這是一種錯覺,主要是因為他們所使用的系統的局限性,伸縮性很差或無法保存歷史數據等原因造成的。這樣一來,他們就認為流處理系統本質上就是從流快照中計算出結果,並不保留所有的原始數​​據。但這沒有理由證明這是對的,流處理中的底層抽象是數據流 DAG,它與傳統數據倉庫中的底層抽象完全相同。流處理只是此數據流模型的一般化形式,暴露中間結果的檢查點以及可以向用戶連續輸出結果。

那麼,如何直接從流處理作業中進行重處理呢?我首選的方法實際上非常簡單:

  • 使用 Kafka 或其它類似系統保存我們要重複處理的完整日誌,並且允許它有多個訂閱者。比如你要重複處理30天的數據,你就讓在 Kafka 中保留30天。
  • 當我們要進行重處理時,我們需要另外啟動一個流處理作業實例,從頭開始處理保留數據,並將輸出數據輸出到一個新的輸出表。
  • 當第二個作業完成後,切換應用程式從這個新表中讀取。
  • 停止老版本的作業,然後刪除舊的輸出表。

這種架構看起來像這樣:

與 Lambda 架構不同,這種方法我們僅在程式碼更改時才進行重處理,也就是我們需要重新計算結果的時候。當然,進行重新計算的作業只是對相同程式碼的改進版本,在相同框架上運行,並採用相同的輸入數據。自然地,我們希望提高重新處理作業的並行度,以快速完成。我們可以將其稱為 Kappa 架構,儘管它的思想比較簡單。

當然,我們可以進一步優化它。在許多情況下,我們可以合併兩個輸出表。但是,我認為在短時間內同時擁有兩個輸出表會更好一點。這可以使我們僅通過一個將應用程式重定向到舊錶的按鈕,立即恢復到舊邏輯。

請注意,這並不意味著我們的數據無法存入 HDFS;這只是意味著我們不在那裡進行重新處理。Kafka 與 Hadoop 集成比較好,因此將任何 Kafka 主題鏡像到 HDFS 都很容易。對於流處理作業的輸出以及中間流,對於使用 Hadoop 中的 Hive 等工具進行分析非常有用。

我們已經文檔記錄了此方法的實現以及使用 Samza 的重新處理架構。

6. 對比

我知道將 Samza 用作流處理系統這種方法非常出色,因為我們在 LinkedIn 已經實踐過。但是我不知道在 Storm 或其他流處理系統中會不會同樣的出色。因為我對 Storm 並不很熟,無法全面了解實際情況,因此很高興得知其他人已經這樣做了。無論如何,我認為總體思路是一套完全獨立的系統。

兩種方法在效率和資源權衡上有一定程度的不同。Lambda 架構需要一直運行重處理和實時處理,而我提出的建議僅在需要重處理時才運行作業的一個副本。但是,我的建議需要在輸出資料庫中暫時佔用2倍的存儲空間,並且需要一個支援大容量寫入的資料庫來進行重新載入。在這兩種情況下,重處理的額外負載可能會平均化。如果我們有很多這樣的作業,我們不會同時一次全部重新處理,因此在具有幾十個這樣的作業的共享集群上,你可能會為在任何給定時間激活重新處理的少數作業提供額外幾個百分點的容量預算。

Kappa 架構真正的優勢根本不在於效率,而在於允許我們在一個處理框架之上開發、測試、調試以及作業系統。因此,在簡單性很重要的情況下,請考慮使用這種方法替代 Lambda 架構。

Lambda架構:即可實時處理數據,也可以重處理數據。兩套系統需要編寫兩套程式碼,操作複雜、維護複雜。 Kappa 架構:根本目的不是關注效率而是提高便利性,我們可以在一個處理框架之上開發、測試、調試以及作業系統。