天天看點

《大資料系統建構:可擴充實時資料系統建構原理與最佳實踐》一1.6 全增量架構的問題

在最高的層次上,傳統的架構如圖1-3所示。

《大資料系統建構:可擴充實時資料系統建構原理與最佳實踐》一1.6 全增量架構的問題

這種架構的特征是讀/寫資料庫的使用以及随着新資料的可用,增量地維護這些資料庫中資料的狀态。例如,一個計算頁面浏覽量的增量方法,将通過對url計數器加1來處理新的頁面浏覽量。這種架構的特征比關系型與非關系型更基礎—事實上,幾十年來,絕大多數的關系型和非關系型資料庫都是用全增量架構來部署的。

值得強調的是,全增量架構應用得如此廣泛,以至于許多人沒有意識到可以使用另外一種不同的架構來避免它們的問題。這是熟悉的複雜性的典型示例—複雜性如此根深蒂固,以至于人們認為無法避免它。

研究全增量架構的問題意義重大。通過檢視任何全增量架構帶來的一般複雜性,我們将開始這個主題的探索。然後,我們将檢視針對相同問題的兩種截然不同的解決方案:一種是使用最好的全增量解決方案;另一種是使用lambda架構的解決方案。你會發現,全增量的版本在各方面明顯更加糟糕。

在全增量架構中有許多内在複雜性,給操作生産基礎架構造成了困難。這裡我們将關注其中一個方面—需要讀/寫資料庫來執行線上合并,以及為保證這項工作平穩運作所必須做的操作。

在讀/寫資料庫中,随着磁盤索引會逐漸增加和修改,但部分索引從未使用過。這些未使用的部分索引占用空間,最終需要被回收以防磁盤被填滿。如果索引一旦變成未使用的,回收空間就立刻回收,那樣付出的代價太高,是以空間在一個被稱為合并的程序中不定期地被批量予以回收。

合并是一類集中操作。在合并過程中,伺服器對cpu和磁盤有更高的要求,這大大降低了該時期機器的性能。衆所周知,資料庫(如hbase和cassandra)都需要仔細地配置和管理,以免在合并時出現問題或伺服器鎖定。合并時性能的損失是一類甚至會導緻級聯故障的複雜性—如果太多機器同時執行合并操作,那麼它們所支撐的負載将必須由叢集中的其他機器處理。這可能使剩餘的叢集過載,導緻徹底失敗。這種失敗已經出現過很多次了。

為了正确地管理合并,你必須在每個節點上都安排合并,以保證同一時間不會有太多節點受到影響;你必須知道一個合并操作會花多少時間以及時間的方差,以免有比預期更多的節點在執行合并;你必須確定節點上有足夠的磁盤容量,以保證在合并期間它們能夠維持正常的操作;你還必須確定叢集有足夠的容量,以保證在合并時資源丢失就不會造成過載。

所有這些都可以由一個合格的操作人員來管理,但我們的觀點是,處理任何一種複雜性的最好方式是完全擺脫這種複雜性。系統失敗模式越少,就越不可能遇到意外的故障時間。處理線上合并是全增量架構中固有的複雜性,但在lambda架構中,主資料庫不需要任何線上合并。

試圖讓系統高可用會導緻增量架構的複雜性。高可用系統甚至允許在機器或部分網絡發生故障時進行查詢和更新。

事實證明,實作高可用性将與另一個稱為一緻性的重要屬性直接競争。具備一緻性的系統傳回結果時,會考慮以前所有的寫操作。cap(consistency、availability、partition tolerance)原理表明,在網絡分區情況下,不可能在同一系統中同時實作高可用性和一緻性,是以在一個網絡分區中,高可用系統有時會傳回陳舊的結果。

本書将在第12章深入讨論cap原理—現在我們總是希望專注于不能實作的完全一緻性和高可用性上,這會影響建構系統的能力。事實證明,如果業務需求中對高可用性的需要超過完全一緻性,那麼你必須處理大量的複雜性。

一旦網絡分區結束,為了高可用性系統能回到一緻性狀态(即最終一緻性),應用程式需要許多幫助,例如,在資料庫中維護一個計數的基本用例,最顯而易見的方法是在資料庫中存儲一個數值,當接收到需要加和的事件時,就做增量。你也許會很驚訝地發現,如果采取這種方法,在網絡分區時,你會遇到海量資料丢失的情況。

導緻這種情況的原因是,分布式資料庫通過儲存所有被存儲資訊的多個副本來實作高可用性。當你儲存了相同資訊的多份副本時,即使機器出現故障或網絡分區,這些資訊仍然可用,如圖1-4所示。在網絡分區時,選擇成為高可用性的系統,隻要副本是可獲得的,就會有用戶端的更新。這将導緻副本産生分歧并接收不同的更新。隻有分區消失,副本才可以合并成一個共同的值。

《大資料系統建構:可擴充實時資料系統建構原理與最佳實踐》一1.6 全增量架構的問題

當網絡分區開始時,假設有兩個副本的計數為10。假設第一個副本得到兩個增量,第二個副本得到一個增量。當這些副本合并在一起時,值分别為12和11,合并後的值應該是多少?雖然正确的答案是13,但是沒有辦法通過檢視數值12和11得到該值。這兩個數可能在11的時候産生分歧(在這種情況下,答案會是12),或者它們可能會在0的時候産生分歧(在這種情況下,答案是23)。

圖1-4 使用副本增加可用性

為了做高可用性的、正确的計算,隻存儲一個計數是不夠的。當值出現分歧時,你需要一個負責合并的資料結構,并且需要實作一段用于分區結束後對值進行修複的代碼。為了維護一個簡單的計數,你必須處理令人難以置信的複雜性。

一般來說,在增量、高可用性系統中處理最終一緻性,是不直覺的且容易出錯的。在高可用、全增量系統中,這種複雜性是固有的。稍後你将看到lambda架構本身是如何以一種不同的方式,極大地減少實作高可用性、最終一緻性系統的負擔的。

我們希望指出的全增量架構的最後一個問題是,它們天生缺乏容忍人為錯誤的特性。增量系統不斷修改儲存在資料庫中的狀态,這意味着即使是一個錯誤也可以修改資料庫中的狀态。因為錯誤是不可避免的,是以全增量架構的資料庫肯定會受到破壞。

重要的是要注意,全增量架構中,這是不用重新思考架構就可以解決的少數複雜性之一。下面考慮如圖1-5所示的兩種架構:同步架構,應用程式直接更新資料庫;異步架構,在背景更新資料庫之前事件先進到一個隊列中。在這兩種情況下,每個事件都被永久地記錄到事件的資料存儲中。通過儲存每個事件,如果是人為錯誤導緻資料庫被破壞,那麼你可以傳回到事件存儲,為資料庫重建正确的狀态。因為事件存儲是不可變且不斷增長的,備援校驗,如權限,可以放入事件存儲,這使得不可能因出現某個錯誤而影響事件存儲。這種技術也是lambda架構的核心,我們将在第2章和第3章深入讨論。

《大資料系統建構:可擴充實時資料系統建構原理與最佳實踐》一1.6 全增量架構的問題

盡管附帶日志記錄的全增量架構可以解決無日志記錄的完全增量架構對人為錯誤缺乏容忍的缺陷,但是日志記錄對于前面讨論的其他複雜性于事無補。在下一節中你将看到,純粹基于完全增量計算的各種架構,包括那些附帶日志記錄的架構,需要努力解決很多問題。

貫穿整本書實作的示例查詢之一,适合作為全增量架構和lambda架構的一個很好的對比。這個查詢沒有任何矯揉造作的地方—事實上,它是基于我們職業生涯中多次面臨的現實生活中的問題的。這個查詢用于處理網頁浏覽分析,并且完成對傳入的兩類資料的查詢:

頁面通路資料,包括使用者id、url和時間戳。

等價資料,其中包含兩個使用者id。一份等價資料表明兩個使用者id是指同一個人。例如,你可能在電子郵箱[email protected]和使用者名sally之間有一份等價資料。如果[email protected]也注冊了使用者名sally2,那麼你在[email protected]和sally2之間有一份等價資料。通過傳遞性,你會知道使用者名sally和sally2指的是同一個人。

查詢的目的是計算一段時間内對一個url來說獨立訪客的數量。查詢應該将所有這段時間的資料加起來,并以最小的延遲(少于100ms)來響應。查詢的接口如下:

使得這個查詢實作起來有些棘手的就是那些等價資料。如果在一個時間範圍内,一個人用兩個使用者id通路了相同的url,通過等價資料的連接配接(甚至傳遞),這應該隻算一次通路。一個新的等價資料的傳入,可以改變任何url在任何時間範圍内任何查詢的結果。

在這一點上,我們将不去展示解決方案的細節,因為必須提及非常多的概念(如索引、分布式資料庫、批處理、hyperloglog等)才能了解它們。此時讓讀者淹沒在這些概念中往往會适得其反。相反,我們将專注于解決方案的特征和它們之間的顯著差異。最佳完全增量解決方案将在第10章詳細讨論,lambda架構解決方案将在第8、9、14和15章中進行讨論。

兩種解決方案可以在準确性、延遲和吞吐量三個軸上進行對比。lambda架構解決方案在各方面表現得更勝一籌。這兩種方案都必須實作近似值,但全增量版本被迫使用具有3~5倍甚至更糟糕的錯誤率的劣質近似技術。在全增量版本中執行查詢的代價更高,并且會影響延遲和吞吐量。但這兩種方案之間最顯著的差別是:全增量版本需要使用特殊的硬體來實作接近合理的吞吐量。因為全增量版本必須做許多随機通路查找來解決查詢問題,它實際上需要使用固态硬碟,以防磁盤尋道時間成為瓶頸。

lambda架構可以生成在每個方面都具有更高性能的解決方案,同時也避免了困擾全增量架構的複雜性,展示了正在發生的非常根本的事情—關鍵是掙脫全增量計算的束縛,采用不同的技術。現在讓我們看看lambda架構是如何做到這一點的。