1. <video id="z7bfh"></video>

            您的位置:知識庫 ? 互聯網

            首席工程師揭秘:LinkedIn大數據后臺是如何運作的

            作者: Jay Kreps  來源: CSDN  發布時間: 2015-04-10 18:51  閱讀: 9614 次  推薦: 9   原文鏈接   [收藏]  
            摘要:Jay Kreps是來自LinkedIn的首席工程師,他表示日志幾乎在計算機產生的時候就存在,除了可用在分布式計算或者抽象分布式計算模型內部之外,還有廣泛的用途。本文中他講述的日志的原理和通過把日志用做單獨服務來實現數據集成、實時數據處理以及分布式系統設計。文章內容非常干貨,值得學習。

              英文原文:The Log: What every software engineer should know about real-time data's unifying abstraction

              我在六年前的一個令人興奮的時刻加入到LinkedIn公司。從那個時候開始我們就破解單一的、集中式數據庫的限制,并且啟動到特殊的分布式系統套件的轉換。這是一件令人興奮的事情:我們構建、部署,而且直到今天仍然在運行的分布式圖形數據庫、分布式搜索后端、Hadoop安裝以及第一代和第二代鍵值數據存儲。

              從這一切里我們體會到的最有益的事情是我們構建的許多東西的核心里都包含一個簡單的理念:日志。有時候也稱作預先寫入日志或者提交日志或者事務日志,日志幾乎在計算機產生的時候就存在,同時它還是許多分布式數據系統和實時應用結構的核心。

              不懂得日志,你就不可能完全懂得數據庫,NoSQL存儲,鍵值存儲,復制,paxos,Hadoop,版本控制以及幾乎所有的軟件系統;然而大多數軟件工程師對它們不是很熟悉。我愿意改變這種現狀。在這篇博客文章里,我將帶你瀏覽你必須了解的有關日志的所有的東西,包括日志是什么,如何在數據集成、實時處理和系統構建中使用日志等。

              第一部分:日志是什么?

            日志

              日志是一種簡單的不能再簡單的存儲抽象。它是一個只能增加的,完全按照時間排序的一系列記錄。日志看起來如下:

            我們可以給日志的末尾添加記錄,并且可以從左到右讀取日志記錄。每一條記錄都指定了一個唯一的有一定順序的日志記錄編號。

              日志記錄的排序是由“時間”來確定的,這是因為位于左邊的日志記錄比位于右邊的要早些。日志記錄編號可以看作是這條日志 記錄的“時間戳”。在一開始就把這種排序說成是按時間排序顯得有點多余 ,不過 ,與任何一個具體的物理時鐘相比,時間 屬性是非常便于使用的屬性。在我們運行多個分布式系統的時候,這個屬性就顯得非常重要。

              對于這篇討論的目標而言,日志記錄的內容和格式不怎么重要。另外提醒一下,在完全耗盡存儲空間的情況下,我們不可能 再給日志添加記錄。稍后我們將會提到這個問題。

              日志并不是完全不同于文件或者數據表的。文件是由一系列字節組成,表是由一系列記錄組成,而日志實際上只是按照時間順序存儲記錄的 一種數據表或者文件。

              此時,你可能奇怪為什么要討論這么簡單的事情呢? 不同環境下的一個只可增加的有一定順序的日志記錄是怎樣與數據系統關聯起來的呢?答案是日志有其特定的應用目標:它記錄了什么時間發生了什么事情。 而對分布式數據系統許多方面而言, 這才是問題的真正核心。

              不過,在我們進行更加深入的討論之前,讓我先澄清有些讓人混淆的概念。每個編程人員都熟悉另一種日志記錄-應用使用syslog或者log4j可能寫入到本地文件里的沒有結構的錯誤信息或者追蹤信息。為了區分開來,我們把這種情形的日志記錄稱為“應用日志記錄”。應用日志記錄是我在這兒所說的日志的一種低級的變種。最大的區別是:文本日志意味著主要用來方便人們閱讀,而我所說明的“日志”或者“數據日志”的建立是方便程序訪問。

              (實際上,如果你對它進行深入的思考,那么人們讀取某個機器上的日志這種理念有些不順應時代潮流。當涉及到許多服務和服務器的時候,這種方法很快就變成一個難于管理的方式,而且為了認識多個機器的行為,日志的目標很快就變成查詢和圖形化這些行為的輸入了-對多個機器的某些行為而言,文件里的英文形式的文本同這兒所描述的這種結構化的日志相比幾乎就不適合了。)

              數據庫日志

              我不知道日志概念起源于何處-可能它就像二進制搜索一樣:發明者認為它太簡單而不能當作一項發明。它早在IBM的系統R出現時候就出現了。數據庫里的用法是在崩潰的時候用它來同步各種數據結構和索引。為了保證操作的原子性和持久性,在對數據庫維護的所有各種數據結構做更改之前,數據庫把即將修改的信息謄寫到日志里。日志記錄了發生了什么,而且其中的每個表或者索引都是一些數據結構或者索引的歷史映射。由于日志是即刻永久化的,可以把它當作崩潰發生時用來恢復其他所有永久性結構的可信賴數據源。

              隨著時間的推移,日志的用途從實現ACID細節成長為數據庫間復制數據的一種方法。利用日志的結果就是發生在數據庫上的更改順序與遠端復制數據庫上的更改順序需要保持完全同步。

              Oracle,MySQL 和PostgreSQL都包括用于給備用的復制數據庫傳輸日志的日志傳輸協議。Oracle還把日志產品化為一個通用的數據訂閱機制,這樣非Oracle數據訂閱用戶就可以使用XStreams和GoldenGate訂閱數據了,MySQL和PostgreSQL上的類似的實現則成為許多數據結構的關鍵組件。
              正是由于這樣的起源,機器可識別的日志的概念大部分都被局限在數據庫內部。日志用做數據訂閱的機制似乎是偶然出現的,不過要把這種 抽象用于支持所有類型的消息傳輸、數據流和實時數據處理是不切實際的。

              分布式系統日志

              日志解決了兩個問題:更改動作的排序和數據的分發,這兩個問題在分布式數據系統里顯得尤為重要。協商出一致的更改動作的順序(或者說保持各個子系統本身的做法,但可以進行存在副作用的數據拷貝)是分布式系統設計的核心問題之一。

              以日志為中心實現分布式系統是受到了一個簡單的經驗常識的啟發,我把這個經驗常識稱為狀態機復制原理:如果兩個相同的、確定性的進程從同一狀態開始,并且以相同的順序獲得相同的輸入,那么這兩個進程將會生成相同的輸出,并且結束在相同的狀態。

              這也許有點難以理解,讓我們更加深入的探討,弄懂它的真正含義。

              確定性意味著處理過程是與時間無關的,而且任何其他“外部的“輸入不會影響到處理結果。例如,如果一個程序的輸出會受到線程執行的具體順序影響,或者受到gettimeofday調用、或者其他一些非重復性事件的影響,那么這樣的程序一般最有可能被認為是非確定性的。

              進程狀態是進程保存在機器上的任何數據,在進程處理結束的時候,這些數據要么保存在內存里,要么保存在磁盤上。

              以相同的順序獲得相同輸入的地方應當引起注意-這就是引入日志的地方。這兒有一個重要的常識:如果給兩段確定性代碼相同的日志輸入,那么它們就會生成相同的輸出。

              分布式計算這方面的應用就格外明顯。你可以把用多臺機器一起執行同一件事情的問題縮減為實現分布式一致性日志為這些進程輸入的問題。這兒日志的目的是把所有非確定性的東西排除在輸入流之外,來確保每個復制進程能夠同步地處理輸入。

              當你理解了這個以后,狀態機復制原理就不再復雜或者說不再深奧了:這或多或少的意味著“確定性的處理過程就是確定性的”。不管怎樣,我都認為它是分布式系統設計里較常用的工具之一。

              這種方式的一個美妙之處就在于索引日志的時間戳就像時鐘狀態的一個副本——你可以用一個單獨的數字描述每一個副本,這就是經過處理的日志的時間戳。時間戳與日志一一對應著整個副本的狀態。

              由于寫進日志的內容的不同,也就有許多在系統中應用這個原則的不同方式。舉個例子,我們記錄一個服務的請求,或者服務從請求到響應的狀態變化,或者它執行命令的轉換。理論上來說,我們甚至可以為每一個副本記錄一系列要執行的機器指令或者調用的方法名和參數。只要兩個進程用相同的方式處理這些輸入,這些進程就會保持副本的一致性。

              一千個人眼中有一千種日志的用法。數據庫工作者通常區分物理日志和邏輯日志。物理日志就是記錄每一行被改變的內容。邏輯日志記錄的不是改變的行而是那些引起行的內容被改變的SQL語句(insert,update和delete語句)。

              分布式系統通常可以寬泛分為兩種方法來處理數據和完成響應。“狀態機器模型”通常引用一個主動-主動的模型——也就是我們為之記錄請求和響應的對象。對此進行一個細微的更改,稱之為“預備份模型”,就是選出一個副本做為leader,并允許它按照請求到達的時間來進行處理并從處理過程中輸出記錄其狀態改變的日志。其他的副本按照leader狀態改變的順序而應用那些改變,這樣他們之間達到同步,并能夠在leader失敗的時候接替leader的工作。

            日志

              為了理解兩種方式的不同,我們來看一個不太嚴謹的例子。假定有一個算法服務的副本,保持一個獨立的數字作為它的狀態(初始值為0),并對這個值進行加法和乘法運算。主動-主動方式應該會輸出所進行的變換,比如“+1”,“*2”等。每一個副本都會應用這些變換,從而得到同樣的解集。主動-被動方式將會有一個獨立的主體執行這些變換并輸出結果日志,比如“1”,“3”,“6”等。這個例子也清楚的展示了為什么說順序是保證各副本間一致性的關鍵:一次加法和乘法的順序的改變將會導致不同的結果。

            日志

              分布式日志可以理解為一致性問題模型的數據結構。因為日志代表了后續追加值的一系列決策。你需要重新審視Paxos算法簇,盡管日志模塊是他們最常見的應用。 在Paxos算法中,它通常通過使用稱之為多paxos的協議,這種協議將日志建模為一系列的問題,在日志中每個問題都有對應的部分。在ZAB, RAFT等其它的協議中,日志的作用尤為突出,它直接對維護分布式的、一致性的日志的問題建模。

              我懷疑的是,我們就歷史發展的觀點是有偏差的,可能是由于過去的幾十年中,分布式計算的理論遠超過了其實際應用。在現實中,共識的問題是有點太簡單了。計算機系統很少需要決定單個值,他們幾乎總是處理成序列的請求。這樣的記錄,而不是一個簡單的單值寄存器,自然是更加抽象。

              此外,專注于算法掩蓋了 抽象系統需要的底層的日志。我懷疑,我們最終會把日志中更注重作為一個商品化的基石,不論其是否以同樣的方式 實施的,我們經常談論一個哈希表而不是糾結我們 得到是不是具體某個細節的哈希表,例如線性或者帶有什么什么其它變體哈希表。日志將成為一種大眾化的接口,為大多數算法和其實現提升提供最好的保證和最佳的性能。

              變更日志101: 表與事件的二相性

              讓我們繼續聊數據庫。數據庫中存在著大量變更日志和表之間的二相性。這些日志有點類似借貸清單和銀行的流程,數據庫表就是當前的盈余表。如果你有大量的變更日志,你就可以使用這些變更用以創建捕獲當前狀態的表。這張表將記錄每個關鍵點(日志中一個特別的時間點)的狀態信息。這就是為什么日志是非常基本的數據結構的意義所在:日志可用來創建基本表,也可以用來創建各類衍生表。同時意味著可以存儲非關系型的對象。

            八卦

              這個流程也是可逆的:如果你正在對一張表進行更新,你可以記錄這些變更,并把所有更新的日志發布到表的狀態信息中。這些變更日志就是你所需要的支持準實時的克隆。基于此,你就可以清楚的理解表與事件的二相性: 表支持了靜態數據而日志捕獲變更。日志的魅力就在于它是變更的完整記錄,它不僅僅捕獲了表的最終版本的內容,它還記錄了曾經存在過的其它版本的信息。日志實質上是表歷史狀態的一系列備份。

              這可能會引起你對源代碼的版本管理。源代碼管理和數據庫之間有密切關系。版本管理解決了一個大家非常熟悉的問題,那就是什么是分布式數據系統需要解決的— 時時刻刻在變化著的分布式管理。版本管理系統通常以補丁的發布為基礎,這實際上可能是一個日志。您可以直接對當前 類似于表中的代碼做出“快照”互動。你會注意到, 與其他分布式狀態化系統類似,版本控制系統 當你更新時會復制日志,你希望的只是更新補丁并將它們應用到你的當前快照中。

              最近,有些人從Datomic –一家銷售日志數據庫的公司得到了一些想法。這些想法使他們對如何 在他們的系統應用這些想法有了開闊的認識。 當然這些想法不是只針對這個系統,他們會成為 十多年分布式系統和數據庫文獻的一部分。

              這可能似乎有點過于理想化。但是不要悲觀!我們會很快把它實現。

              請讓我首先解釋 一下“數據集成”是什么意思,還有為什么我覺得它很重要,之后我們再來看看它和日志有什么關系。

              數據集成就是將數據組織起來,使得在與其有關的服務和系統中可以訪問它們。“數據集成”(data integration)這個短語應該不止這么簡單,但是我找不到一個更好的解釋。而更常見的術語 ETL 通常只是覆蓋了數據集成的一個有限子集(譯注:ETL,Extraction-Transformation-Loading的縮寫,即數據提取、轉換和加載)——相對于關系型數據倉庫。但我描述的東西很大程度上可以理解為,將ETL推廣至實時系統和處理流程。

            36大數據

              你一定不會聽到數據集成就興趣盎然屏住呼吸,并且天花亂墜的想到關于大數據的概念,不過,我相信世俗的問題“讓數據可被訪問” 是一個組織應該關注的有價值的事情。

              對數據的高效使用遵循一種 馬斯洛的需要層次理論 。金字塔的基礎部分包括捕獲所有相關數據,能夠將它們全部放到適當的處理環境(那個環境應該是一個奇妙的實時查詢系統,或者僅僅是文本文件和python腳本)。這些數據需要以統一的方式建模,這樣就可以方便讀取和數據處理。如果這種以統一的方式捕獲數據的基本需求得到滿足,那么就可以在基礎設施上以若干種方法處理這些數據——映射化簡(MapReduce),實時查詢系統,等等。

              很明顯,有一點值得注意:如果沒有可靠的、完整的數據流,Hadoop集群除了象昂貴的且難于安裝的空間取暖器哪樣外不會做更多事情了。一旦數據和處理可用,人們就會關心良好數據模型和一致地易于理解的語法哪些更細致的問題。最后,人們才會關注更加高級的處理-更好的可視化、報表以及處理和預測算法。

              以我的經驗,大多數機構在數據金字塔的底部存在巨大的漏洞-它們缺乏可靠的、完整的數據流-而是打算直接跳到高級數據模型技術上。這樣做完全是反著來做的。因此,問題是我們如何構建通過機構內所有數據系統的可靠的數據流。

              數據集成:兩個并發癥

              兩種趨勢使數據集成變得更困難。

              事件數據管道

              第一個趨勢是增長的事件數據(event data)。事件數據記錄的是發生的事情,而不是存在的東西。在web系統中,這就意味著用戶活動日志,還有為了可靠的操作以及監控數據中心的機器的目的,所需要記錄的機器級別的事件和統計數字。人們傾向稱它們為“日志數據”,因為它們經常被寫到應用的日志中,但是這混淆了形式與功能。這種數據位于現代web的中心:歸根結底,Google的資產是由這樣一些建立在點擊和映像基礎之上的相關管道所生成的——那也就是事件。

              這些東西并不是僅限于網絡公司,只是網絡公司已經完全數字化,所以它們更容易用設備記錄。財務數據一直是面向事件的。RFID(無線射頻識別)將這種跟蹤能力賦予物理對象。我認為這種趨勢仍將繼續,伴隨著這個過程的是傳統商務活動的數字化。

              這種類型的事件數據記錄下發生的事情,而且往往比傳統數據庫應用要大好幾個數量級。這對于處理提出了重大挑戰。

              專門的數據系統的爆發

              第二個趨勢來自于專門的數據系統的爆發,通常這些數據系統在最近的五年中開始變得流行,并且可以免費獲得。專門的數據系統是為OLAP, 搜索, 簡單 在線 存儲, 批處理, 圖像分析, 等 等 而存在的。

              更多的不同類型數據的組合,以及將這些數據存放到更多的系統中的愿望,導致了一個巨大的數據集成問題。

              日志結構數據流

              為了處理系統之間的數據流,日志是最自然的數據結構。其中的秘訣很簡單:

              將所有組織的數據提取出來,并將它們放到一個中心日志,以便實時查閱。

              每個邏輯數據源都可以建模為它自己的日志。一個數據源可以是一個應用程序的事件日志(如點擊量或者頁面瀏覽量),或者是一個接受修改的數據庫表。每個訂閱消息的系統都盡可能快的從日志讀取信息,將每條新的記錄保存到自己的存儲,并且提升其在日志中的地位。訂閱方可以是任意一種數據系統 —— 一個緩存,Hadoop,另一個網站中的另一個數據庫,一個搜索系統,等等。

            36大數據

              例如,日志針對每個更改給出了邏輯時鐘的概念,這樣所有的訂閱方都可以被測量。推導不同的訂閱系統的狀態也因此變得相對簡單的多,因為每個系統都有一個讀取動作的“時間點”。

              為了讓這個顯得更具體,我們考慮一個簡單的案例,有一個數據庫和一組緩存服務器集群。日志提供了一種同步更新所有這些系統,并推導出每一個系統的接觸時間點的方法。我們假設寫了一條日志X,然后需要從緩存做一次讀取。如果我們想保證看到的不是陳舊的數據,我們只需保證沒有從任何尚未復制X的緩存中讀取即可。

              日志也起到緩存的作用,使數據生產與數據消費相同步。由于許多原因這個功能很重要,特別是在多個訂閱方消費數據的速度各不相同的時候。這意味著一個訂閱數據系統可以宕機,或者下線維護,之后重新上線以后再趕上來:訂閱方按照自己控制的節拍來消費數據。批處理系統,如Hadoop或者是一個數據倉庫,或許只是每小時或者每天消費一次數據,而實時查詢系統可能需要及時到秒。由于無論是原始數據源還是日志,都沒有各種目標數據系統的相關知識,因此消費方系統可以被添加和刪除,而無需傳輸管道的變化。

            36大數據

            每個工作數據管道設計得就像是一個日志;每個損壞的數據管道以其自己的方式損壞。”—Count Leo Tolstoy

              特別重要的是:目標系統只知道日志,不知道數據源系統的任何細節。消費方系統自身無需考慮數據到底是來自于一個RDBMS(關系型數據庫管理系統Relational Database Management System),一種新型的鍵值存儲,或者它不是由任何形式的實時查詢系統所生成的。這似乎是一個小問題,但實際上是至關重要的。

              這里我使用術語“日志”取代了“消息系統”或者“發布-訂閱”,因為它在語義上更明確,并且對支持數據復制的實際實現這樣的需求,有著更接近的描述。我發現“發布訂閱”并不比間接尋址的消息具有更多的含義——如果你比較任何兩個發布-訂閱的消息傳遞系統的話,你會發現他們承諾的是完全不同的東西,而且大多數模型在這一領域都不是有用的。你可以認為日志是一種消息系統,它具有持久性保證和強大的訂閱語義。在分布式系統中,這個通信模型有時有個(有些可怕的)名字叫做原子廣播。

              值得強調的是,日志仍然只是基礎設施。這并不是管理數據流這個故事的結束:故事的其余部分圍繞著元數據,模式,兼容性,以及處理數據結構的所有細節及其演化。除非有一種可靠的,一般的方法來處理數據流運作,語義在其中總是次要的細節。

              在 LinkedIn(SNS社交網站)

              在LinkedIn從集中式關系數據庫向分布式系統集合轉化的過程中,我看到這個數據集成問題迅速演變。

              現在主要的數據系統包括:

            • 搜索
            • 社交圖譜
            • Voldemort (鍵值存儲)(譯注:一種分布式數據庫)
            • Espresso (文檔存儲)
            • 推舉引擎
            • OLAP查詢引擎(譯注:OLAP聯機分析技術)
            • Hadoop
            • Terradata
            • Ingraphs (監控圖表和指標服務)

              這些都是專門的分布式系統,在其專業領域提供先進的功能。

            linkedin

              這種使用日志作為數據流的思想,甚至在我到這里之前就已經與LinkedIn相伴了。我們開發的一個最早的基礎設施之一,是一種稱為databus 的服務,它在我們早期的Oracle表上提供了一種日志緩存抽象,可伸縮訂閱數據庫修改,這樣我們就可以很好支持我們的社交網絡和搜索索引。

              我會給出一些歷史并交代一下上下文。我首次參與到這些大約是在2008年左右,在我們轉移鍵值存儲之后。我的下一個項目是讓一個工作中的Hadoop配置演進,并給其增加一些我們的推薦流程。由于缺乏這方面的經驗,我們自然而然的安排了數周計劃在數據的導入導出方面,剩下的時間則用來實現奇妙的預測算法。這樣我們就開始了長途跋涉。

              我們本來計劃是僅僅將數據從現存的Oracle數據倉庫中剖離。但是我們首先發現將數據從Oracle中迅速取出是一種黑暗藝術。更糟的是,數據倉庫的處理過程與我們為Hadoop而計劃的批處理生產過程不適合——其大部分處理都是不可逆轉的,并且與即將生成的報告具體相關。最終我們采取的辦法是,避免使用數據倉庫,直接訪問源數據庫和日志文件。最后,我們為了加載數據到鍵值存儲 并生成結果,實現了另外一種管道。
            這種普通的數據復制最終成為原始開發項目的主要內容之一。糟糕的是,在任何時間任意管道都有一個問題,Hadoop系統很大程度上是無用的——在錯誤的數據基礎上運行奇特的算法,只會產生更多的錯誤數據。

              雖然我們已經以一種通用的方式創建事物,但是每個數據源都需要自定義配置安裝。這也被證明是巨量錯誤與失敗的根源。我們在Hadoop上實現的網站功能已經開始流行起來,同時我們發現我們有一長串感興趣的工程師。每個用戶都有他們想要集成的一系列系統,他們想要的一系列新數據源。

            古希臘

            古希臘時代的 ETL(提取轉換加載Extract Transform and Load)。并沒有太多變化。

              有些東西在我面前開始漸漸清晰起來。

              首先,我們已建成的通道雖然有一些雜亂,但實質上它們是很有價值的。在采用諸如Hadoop的新的處理系統生成可用數據的過程,它開啟了大量的可能性。 基于這些數據過去很難實現的計算,如今變為可能。 許多新的產品和分析技術都來源于把分片的數據放在一起,這些數據過被鎖定在特定的系統中。

              第二, 眾所周知,可靠的數據加載需要數據通道的深度支持。如果我們可以捕獲所有我們需要的結構,我就就可以使得Hadoop數據全自動的加載,這樣就不需要額外的操作來增加新的數據源或者處理模式變更–數據就會自動的出現在HDFS,Hive表就會自動的生成對應于新數據源的恰當的列。

              第三,我們的數據覆蓋率仍然非常低。如果你查看存儲于Hadoop中的可用的Linked 數據的全部百分比,它仍然是不完整的。花費大量的努力去使得各個新的數據源運轉起來,使得數據覆蓋度完整不是一件容易的事情。

              我們正在推行的,為每個數據源和目標增建客戶化數據加載,這種方式很顯然是不可行的。我們有大量的數據系統和數據倉庫。把這些系統和倉庫聯系起來,就會導致任意一對系統會產生如下所示的客戶化通道。

            36大數據

              需要注意的是:數據是雙向流動的:例如許多系統諸如數據庫和Hadoop既是數據轉化的來源又是數據轉化的目的地。這就意味著我們我們不必為每個系統建立兩個通道:一個用于數據輸入,一個用于數據輸出。

              這顯然需要一大群人,而且也不具有可操作性。隨著我們接近完全連接,最終我們將有差不多O(N2)條管道。

              替代的,我們需要像這樣通用的東西:

            大數據

              我們需要盡可能的將每個消費者與數據源隔離。理想情形下,它們應該只與一個單獨的數據倉庫集成,并由此讓他們能訪問到所有東西。

              這個思想是增加一個新的數據系統——或者它是一個數據源或者它是一個數據目的地——讓集成工作只需連接到一個單獨的管道,而無需連接到每個數據消費方。

              這種經歷使得我關注創建Kafka來關聯我們在消息系統所見的與數據庫和分布式系統內核所發布的日志。我們希望一些實體作為中心的通道,首先用于所有的活動數據,逐步的擴展到其他用途,例如Hadoop外的數據實施,數據監控等。

              在相當長的時間內,Kafka是獨一無二的底層產品,它既不是數據庫,也不是日志文件收集系統,更不是傳統的消息系統。但是最近Amazon提供了非常類似Kafka的服務,稱之為Kinesis.相似度包括了分片處理的方式,數據的保持,甚至包括在Kafka API中,有點特別的高端和低端消費者分類。我很開心看到這些,這表明了你已經創建了很好的底層協議,AWS已經把它作為服務提供。他們對此的期待與我所描述的吻合:通道聯通了所有的分布式系統,諸如DynamoDB, RedShift, S3等,它同時作為使用EC2進行分布式流處理的基礎。

              與ETL和數據倉庫的關系

              我們再來聊聊數據倉庫。數據倉庫是清洗和歸一數據結構用于支撐數據分析的倉庫。這是一個偉大的理念。對不熟悉數據倉庫概念的人來說,數據倉庫方法論包括了:周期性的從數據源抽取數據,把它們轉化為可理解的形式,然后把它導入中心數據倉庫。對于數據集中分析和處理,擁有高度集中的位置存放全部數據的原始副本是非常寶貴的資產。在高層級上,也許你抽取和加載數據的順序略微調整,這個方法論不會有太多變化,無論你使用傳統的數據倉庫Oracle還是Teradata或者Hadoop。

              數據倉庫是極其重要的資產,它包含了原始的和規整的數據,但是實現此目標的機制有點過時了。

            數據倉庫

              對以數據為中心的組織關鍵問題是把原始的歸一數據聯結到數據倉庫。數據倉庫是批處理的基礎查詢:它們適用于各類報表和臨時性分析,特別是當查詢包含了簡單的計數、聚合和過濾。但是如果一個批處理系統僅僅包含了原始的完整的數據的數據倉庫,這就意味著這些數據對于實時數據處理、搜索索引和系統監控等實時的查詢是不可用的。

              依我之見,ETL包括兩件事:首先,它是抽取和數據清洗過程–特別是釋放被鎖在組織的各類系統中的數據,移除系統專有的無用物。第二,依照數據倉庫的查詢重構數據。例如使其符合關系數據庫類型系統,強制使用星號、雪花型模式,或者分解為高性能的柱狀格式等。合并這兩者是有困難的。這些規整的數據集應當可以在實時或低時延處理中可用,也可以在其它實施存儲系統索引。

              在我看來,正是因為這個原因有了額外好處:使得數據倉庫ETL更具了組織級的規模。數據倉庫的精典問題是數據倉庫負責收集和清洗組織中各個組所生成的全部數據。各組織的動機是不同的,數據的生產者并不知曉在數據倉庫中數據的使用情況,最終產生的數據很難抽取,或者需要花費規模化的轉化才可以轉化為可用的形式。當然, 中心團隊不可能恰到好處的掌握規模,使得這規模剛好與組織中其它團隊相匹配,因此數據的覆蓋率常常差別很大,數據流是脆弱的同時變更是緩慢的。

              較好的方法是有一個中心通道,日志和用于增加數據的定義良好的API。與通道集成的且提供良好的結構化的數據文件的職責依賴于數據的生產者所生成的數據文件。這意味著在設計和實施其它系統時應當考慮數據的輸出以及輸出的數據如何轉化為結構良好的形式并傳遞給中心通道。增加新的存儲系統倒是不必因為數據倉庫團隊有一個中心結點需要集成而關注數據倉庫團隊。數據倉庫團隊僅需處理簡單的問題,例如從中心日志中加載結構化的數據,向其它周邊系統實施個性化的數據轉化等。

            數據庫

              如圖所示:當考慮在傳統的數據倉庫之外增加額外的數據系統時,組織結構的可擴展性顯得尤為重要。例如,可以考慮為組織的完整的數據集提供搜索功能。或者提供二級的數據流監控實時數據趨勢和告警。無論是這兩者中的哪一個,傳統的數據倉庫架構甚至于Hadoop聚簇都不再適用。更糟的是,ETL的流程通道的目的就是支持數據加載,然而ETL似乎無法輸出到其它的各個系統,也無法通過引導程序,使得這些外圍的系統的各個架構成為適用于數據倉庫的重要資產。這就不難解釋為什么組織很難輕松的使用它的全部數據。反之,如果組織已建立起了一套標準的、結構良好的數據,那么任何新的系統要使用這些數據僅僅需要與通道進行簡單的集成就可以實現。

              這種架構引出了數據清理和轉化在哪個階段進行的不同觀點:

            • 由數據的生產者在把數據增加到公司全局日志之前。
            • 在日志的實時轉化階段進行,這將會產生一個新的轉化日志。
            • 在向目標系統加載數據時,做為加載過程的一部分進行。

              理想的模形是:由數據的生產者在把數據發布到日志之前對數據進行清理。這樣可以確保數據的權威性,不需要維護其它的遺留物例如為數據產生的特殊處理代碼或者維護這些數據的其它的存儲系統。這些細節應當由產生數據的團隊來處理,因為他們最了解他們自己的數據。這個階段所使用的任何邏輯都應該是無損的和可逆的。

              任何可以實時完成的增值轉化類型都應當基于原始日志進行后期處理。這一過程包括了事件數據的會話流程,或者增加大眾感興趣的衍生字段。原始的日志仍然是可用的,但是這種實時處理產生的衍生日志包含了參數數據。

              最終,只有針對目標系統的聚合需要做了加載流程的一部分。它包括了把數據轉化成特定的星型或者雪花狀模式,從而用于數據倉庫的分析和報表。因為在這個階段,大部分自然的映射到傳統的ETL流程中,而現在它是在一個更加干凈和規整的數據流集在進行的,它將會更加的簡單。

              日志文件和事件

              我們再來聊聊這種架構的優勢:它支持解耦和事件驅動的系統。

              在網絡行業取得活動數據的典型方法是把它記為文本形式的日志,這些文本文件是可分解進入數據倉庫或者Hadoop,用于聚合和查詢處理的。由此產生的問題與所有批處理的ETL的問題是相同的:它耦合了數據流進入數據倉庫系統的能力和流程的調度。

              在LinkedIn中,我們已經以中心日志的方式構建了事件數據處理。我們正在使用Kafka做為中心的、多訂閱者事件日志。我們已經定義了數百種事件類型,每種類型都會捕獲用于特定類型動作的獨特的屬性。這將會覆蓋包括頁面視圖、表達式、搜索以及服務調用、應用異常等方方面面。

              為了進一步理解這一優勢:設想一個簡單的事務–在日志頁面顯示已發布的日志。這個日志頁面應當只包括顯示日志所需要的邏輯。然而,在相當多的動態站點中,日志頁面常常變的添加了很多與顯示日志無關的邏輯。例如,我們將對如下的系統進行集成:

            1. 需要把數據傳送到Hadoop和數據倉庫中用于離線數據處理。
            2. 需要對視圖進行統計,確保視圖訂閱者不會攻擊一些內容片段。
            3. 需要聚合這些視圖,視圖將用于作業發布者的分析頁面顯示。
            4. 需要記錄視圖以確保我們為作業推薦的使用者提供了恰當的印象覆蓋,我們不想一次次的重復同樣的事情。
            5. 推薦系統需要記錄日志用于正確的跟蹤作業的普及度。
            6. 等等。

              不久,簡單的作業顯示變得相當的復雜。我們增加了作業顯示的其它終端–移動終端應用等–這些邏輯必須繼續存在,復雜度不斷的增加。更糟的是我們需要與之做接口交互的系統現在是錯綜復雜的–在為顯示日作業而工作的工程師們需要知曉多個其它系統和它們的特征,才可以確保它們被正確的集成了。這僅僅是問題的簡單版本,真實的的應用系統只會更加的復雜。

              “事件驅動”的模式提供了一種簡化這類問題的機制。作業顯示頁面現在只顯示作業并記錄與正在顯示的作業,作業訂閱者相關的其它屬性,和其它與作業顯示相關的其它有價值的屬性。每個與此相關的其它系統諸如推薦系統、安全系統、作業推送分析系統和數據倉庫,所有這些只是訂閱種子文件,并進行它們的操作。顯示代碼并不需要關注其它的系統,也不需要因為增加了數據的消費者而相應的進行變更。

              構建可伸縮的日志

              當然,把發布者與訂閱者分離不再是什么新鮮事了。但是如果你想要確保提交日志的行為就像多個訂閱者實時的分類日志那樣記錄網站發生的每件事時,可擴展性就會成為你所面臨的首要挑戰。如果我們不能創建快速、高性價比和可擴展性靈活的日志以滿足實際的可擴展需求,把日志做為統一的集成機制不再是美好的想像。

              人們普遍認為分布式日志是緩慢的、重量經的概念(并且通常會把它僅僅與“原數據”類型的使用聯系起來,對于這類使用Zookeeper可以適用)。但是深入實現并重點關注分類記錄大規模的數據流,這種需求是不切實際的。在LinkedIn, 我們現在每天通過Kafka運行著超過600億個不同的消息寫入點(如果統計鏡相與數據中心之間的寫入,那么這個數字會是數千億。)

              我們在Kafk中使用了一些小技巧來支持這種可擴展性:

            • 日志分片
            • 通過批處理讀出和寫入優化吞吐力
            • 規避無用的數據復制。

              為了確保水平可擴展性,我們把日志進行切片:

            數據庫

              每個切片都是一篇有序的日志,但是各片之間沒有全局的次序(這個有別于你可能包含在消息中的掛鐘時間)。把消息分配到特定的日志片段這是由寫入者控制的,大部分使用者會通過用戶ID等鍵值來進行分片。分片可以把日志追加到不存在協作的片段之間,也可以使系統的吞吐量與Kafka聚簇大小成線性比例關系。

              每個分片都是通過可配置數量的復制品復制的,每個復制品都有分片的一份完全一致的拷貝。無論何時,它們中的任一個都可以做為主分片,如果主分片出錯了,任何一個復制品都可以接管并做為主分片。

              缺少跨分片的全局順序是這個機制的局限性,但是我們不認為它是最主要的。事實上,與日志的交互主要來源于成百上千個不同的流程,以致于對于它們的行為排一個總體的順序是沒什么意義的。相反,我們可以確保的是我們提供的每個分片都是按順序保留的。Kafka保證了追加到由單一發送者送出的特定分片會按照發送的順序依次處理。

              日志,就像文件系統一樣,是容易優化成線性可讀可寫的樣式的。日志可以把小的讀入和寫出組合成大的、高吞吐量的操作。Kafka一直至立于實現這一優化目標。批處理可以發生在由客戶端向服務器端發送數據、寫入磁盤;在服務器各端之間復制;數據傳遞給消費者和確認提交數據等諸多環節。

              最終,Kafka使用簡單的二進制形式維護內存日志,磁盤日志和網絡數據傳送。這使得我們可以使用包括“0數據復制傳送”在內的大量的優化機制。

              這些優化的積累效應是你常常進行的寫出和讀入數據的操作可以在磁盤和網絡上得到支持,甚至于維護內存以外的大量數據集。

              到此為止,我只是描述從端到端數據復制的理想機制。但是在存儲系統中搬運字節不是所要講述內容的全部。最終我們發現日志是流的另一種說法,日志是流處理的核心。

              但是,等等,什么是流處理呢?

              如果你是90年代晚期或者21世紀初數據庫文化或者數據基礎架構產品的愛好者,那么你就可能會把流處理與建創SQL引擎或者創建“箱子和箭頭”接口用于事件驅動的處理等聯系起來。

              如果你關注開源數據庫系統的大量出現,你就可能把流處理和一些開源數據庫系統關聯起來,這些系統包括了:Storm,Akka,S4和Samza.但是大部分人會把這些系統作為異步消息處理系統,這些系統與支持群集的遠程過程調用層的應用沒什么差別(而事實上在開源數據庫系統領域某些方面確實如此)。

              這些視圖都有一些局限性。流處理與SQL是無關的。它也局限于實時流處理。不存在內在的原因限制你不能處理昨天的或者一個月之前的流數據,且使用多種不同的語言表達計算。

            數據流

              我把流處理視為更廣泛的概念:持續數據流處理的基礎架構。我認為計算模型可以像MapReduce或者分布式處理架構一樣普遍,但是有能力處理低時延的結果。

              處理模型的實時驅動是數據收集方法。成批收集的數據是分批處理的。數據是不斷收集的,它也是按順序不斷處理的。

              美國的統計調查就是成批收集數據的良好典范。統計調查周期性的開展,通過挨門挨戶的走訪,使用蠻力發現和統計美國的公民信息。1790年統計調查剛剛開始時這種方式是奏效的。那時的數據收集是批處理的,它包括了騎著馬悠閑的行進,把信息寫在紙上,然后把成批的記錄傳送到人們統計數據的中心站點。現在,在描述這個統計過程時,人們立即會想到為什么我們不保留出生和死亡的記錄,這樣就可以產生人口統計信息這些信息或是持續的或者是其它維度的。

              這是一個極端的例子,但是大量的數據傳送處理仍然依賴于周期性的轉儲,批量轉化和集成。處理大容量轉儲的唯一方法就是批量的處理。但是隨著這些批處理被持續的供給所取代,人們自然而然的開始不間斷的處理以平滑的處理所需資源并且消除延遲。

              例如LinkedIn幾乎沒有批量數據收集。大部分的數據或者是活動數據或者是數據庫變更,這兩者都是不間斷發生的。事實上,你可以想到的任何商業,正如:Jack Bauer告訴我們的,低層的機制都是實時發生的不間斷的流程事件。數據是成批收集的,它總是會依賴于一些人為的步驟,或者缺少數字化或者是一些自動化的非數字化流程處理的遺留信息。當傳送和處理這些數據的機制是郵件或者人工的處理時,這一過程是非常緩慢的。首輪自動化總是保持著最初的處理形式,它常常會持續相當長的時間。

              每天運行的批量處理作業常常是模擬了一種一天的窗口大小的不間斷計算。當然,低層的數據也經常變化。在LinkedIn,這些是司空見貫的,并且使得它們在Hadoop運轉的機制是有技巧的,所以我們實施了一整套管理增量的Hadoop工作流的架構。

              由此看來,對于流處理可以有不同的觀點。流處理包括了在底層數據處理的時間概念,它不需要數據的靜態快照,它可以產生用戶可控頻率的輸出,而不用等待數據集的全部到達。從這個角度上講,流處理就是廣義上的批處理,隨著實時數據的流行,會兒更加普遍。

              這就是為什么從傳統的視角看來流處理是利基應用。我個人認為最大的原因是缺少實時數據收集使得不間斷的處理成為了學術性的概念。

              我想缺少實時數據收集就像是商用流處理系統注定的命運。他們的客戶仍然需要處理面向文件的、每日批量處理ETL和數據集成。公司建設流處理系統關注的是提供附著在實時數據流的處理引擎,但是最終當時極少數人真正使用了實時數據流。事實上,在我在LinkedIn工作的初期,有一家公司試圖把一個非常棒的流處理系統銷售給我們,但是因為當時我們的全部數據都按小時收集在的文件里,當時我們提出的最好的應用就是在每小時的最后把這些文件輸入到流處理系統中。他們注意到這是一個普遍性的問題。這些異常證明了如下規則:流處理系統要滿足的重要商業目標之一是:財務, 它是實時數據流已具備的基準,并且流處理已經成為了瓶頸。

              甚至于在一個健康的批處理系統中,流處理作為一種基礎架構的實際應用能力是相當廣泛的。它跨越了實時數據請求-應答服務和離線批量處理之間的鴻溝。現在的互聯網公司,大約25%的代碼可以劃分到這個類型中。

              最終這些日志解決了流處理中絕大部分關鍵的技術問題。在我看來,它所解決的最大的問題是它使得多訂閱者可以獲得實時數據。對這些技術細節感興趣的朋友,我們可以用開源的Samza,它是基于這些理念建設的一個流處理系統。這些應用的更多技術細節我們在此文檔中有詳細的描述。

              數據流圖

            大數據

              流處理最有趣的角度是它與流處理系統內部無關,但是與之密切相關的是如何擴展了我們談到的早期數據集成的數據獲取的理念。我們主要討論了基礎數據的獲取或日志–事件和各類系統執行中產生的數據等。但是流處理允許我們包括了計算其它數據的數據。這些衍生的數據在消費者看來與他們計算的原始數據沒什么差別。這些衍生的數據可以按任意的復雜度進行壓縮。

              讓我們再深入一步。我們的目標是:流處理作業可以讀取任意的日志并把日志寫入到日志或者其它的系統中。他們用于輸入輸出的日志把這些處理關聯到一組處理過程中。事實上,使用這種樣式的集中日志,你可以把組織全部的數據抓取、轉化和工作流看成是一系列的日志和寫入它們的處理過程。

              流處理器根本不需要理想的框架:它可能是讀寫日志的任何處理器或者處理器集合,但是額外的基礎設施和輔助可以提供幫助管理處理代碼。

              日志集成的目標是雙重的:

              首先,它確保每個數據集都有多個訂閱者和有序的。讓我們回顧一下狀態復制原則來記住順序的重要性。為了使這個更加具體,設想一下從數據庫中更新數據流–如果在處理過程中我們把對同一記錄的兩次更新重新排序,可能會產生錯誤的輸出。 TCP之類的鏈接僅僅局限于單一的點對點鏈接,這一順序的持久性要優于TCP之類的鏈接,它可以在流程處理失敗和重連時仍然存在。

              第二,日志提供了流程的緩沖。這是非常基礎的。如果處理流程是非同步的,那么上行生成流數據的作業比下行消費流數據的作業運行的更快。這將會導致處理流程阻塞,或者緩沖數據,或者丟棄數據。丟棄數據并不是可行的方法,阻塞將會導致整個流程圖立即停止。 日志實際上是一個非常大的緩沖,它允許流程重啟或者停止但不會影響流程圖其它部分的處理速度。如果要把數據流擴展到更大規模的組織,如果處理作業是由多個不同的團隊提供的,這種隔離性是極其重的。我們不能容忍一個錯誤的作業引發后臺的壓力,這種壓力會使得整個處理流程停止。

              Storm和Sama這兩者都是按非同步方式設計的,可以使用Kafka或者其它類似的系統作為它們的日志。

              有狀態的實時流處理

              一些實時流處理在轉化時是無狀態的記錄。在流處理中大部分的應用會是相當復雜的統計、聚合、不同窗口之間的關聯。例如有時人們想擴大包含用戶操作信息的事件流(一系列的單擊動作)–實際上關聯了用戶的單擊動作流與用戶的賬戶信息數據庫。不變的是這類流程最終會需要由處理器維護的一些狀態信息。例如數據統計時,你需要統計到目前為止需要維護的計數器。如果處理器本身失敗了,如何正確的維護這些狀態信息呢?

              最簡單的替換方案是把這些狀態信息保存在內存中。但是如果流程崩潰,它就會丟失中間狀態。如果狀態是按窗口維護的,流程就會回退到日志中窗口開始的時間點上。但是,如果統計是按小時進行的,那么這種方式就會變得不可行。

              另一個替換方案是簡單的存儲所有的狀態信息到遠程的存儲系統,通過網絡與這些存儲關聯起來。這種機制的問題是沒有本地數據和大量的網絡間通信。

              我們如何支持處理過程可以像表一樣分區的數據呢?

              回顧一下關于表和日志二相性的討論。這一機制提供了工具把數據流轉化為與處理過程協同定位的表,同時也提供了這些表的容錯處理的機制。

              流處理器可以把它的狀態保存在本地的表或索引–bdb,或者leveldb,甚至于類似于Lucene 或fastbit一樣不常見的索引。這些內容存儲在它的輸入流中(或許是使用任意的轉化)。生成的變更日志記錄了本地的索引,它允許存儲事件崩潰、重啟等的狀態信息。流處理提供了通用的機制用于在本地輸入流數據的隨機索引中保存共同分片的狀態。

              當流程運行失敗時,它會從變更日志中恢復它的索引。每次備份時,日志把本地狀態轉化成一系列的增量記錄。

              這種狀態管理的方法有一個優勢是把處理器的狀態也做為日志進行維護。我們可以把這些日志看成與數據庫表相對應的變更日志。事實上,這些處理器同時維護著像共同分片表一樣的表。因為這些狀態它本身就是日志,其它的處理器可以訂閱它。如果流程處理的目標是更新結點的最后狀態,這種狀態又是流程的輸出,那么這種方法就顯得尤為重要。

              為了數據集成,與來自數據庫的日志關聯,日志和數據庫表的二象性就更加清晰了。變更日志可以從數據庫中抽取出來,日志可以由不同的流處理器(流處理器用于關聯不同的事件流)按不同的方式進行索引。

              我們可以列舉在Samza中有狀態流處理管理的更多細節和大量實用的例子。

              日志壓縮

              當然,我們不能奢望保存全部變更的完整日志。除非想要使用無限空間,日志不可能完全清除。為了澄清它,我們再來聊聊Kafka的實現。在Kafka中,清理有兩種選擇,這取決于數據是否包括關鍵更新和事件數據。對于事件數據,Kafka支持僅維護一個窗口的數據。通常,配置需要一些時間,窗口可以按時間或空間定義。雖然對于關鍵數據而言,完整日志的重要特征是你可以重現源系統的狀態信息,或者在其它的系統重現。

              隨著時間的推移,保持完整的日志會使用越來越多的空間,重現所耗費的時間越來越長。因些在Kafka中,我們支持不同類型的保留。我們移除了廢棄的記錄(這些記錄的主鍵最近更新過)而不是簡單的丟棄舊日志。我們仍然保證日志包含了源系統的完整備份,但是現在我們不再重現原系統的全部狀態,而是僅僅重現最近的狀態。我們把這一特征稱為日志壓縮。

              我們最后要討論的是在線數據系統設計中日志的角色。

              在分布式數據庫數據流中日志的角色和在大型組織機構數據完整中日志的角色是相似的。在這兩個應用場景中,日志是對于數據源是可靠的,一致的和可恢復的。組織如果不是一個復雜的分布式數據系統呢,它究竟是什么?

              如果換個角度,你可以看到把整個組織系統和數據流看做是單一的分布式數據系統。你可以把所有的子查詢系統(諸如Redis, SOLR,Hive表等)看成是數據的特定索引。你可以把Storm或Samza一樣的流處理系統看成是發展良好的觸發器和視圖具體化機制。我已經注意到,傳統的數據庫管理人員非常喜歡這樣的視圖,因為它最終解釋了這些不同的數據系統到底是做什么用的–它們只是不同的索引類型而已。

              不可否認這類數據庫系統現在大量的出現,但是事實上,這種復雜性一直都存在。即使是在關系數據庫系統的鼎盛時期,組織中有大量的關系數據庫系統。或許自大型機時代開始,所有的數據都存儲在相同的位置,真正的集成是根本不存在的。存在多種外在需求,需要把數據分解成多個系統,這些外在需求包括:規模、地理因素、安全性,性能隔離是最常見的因素。這些需求都可以由一個優質的系統實現:例如,組織可以使用單一的Hadoop聚簇,它包括了全部的數據,可以服務于大型的和多樣性的客戶。

              因此在向分布式系統變遷的過程中,已經存在一種處理數據的簡便的方法:把大量的不同系統的小的實例聚合成為大的聚簇。許多的系統還不足以支持這一方法:因為它們不夠安全,或者性能隔離性得不到保證,或者規模不符合要求。不過這些問題都是可以解決的。

              依我之見,不同系統大量出現的原因是建設分布式數據庫系統很困難。通過削減到單一的查詢或者用例,每個系統都可以把規模控制到易于實現的程度。但是運行這些系統產生的復雜度依然很高。

              未來這類問題可能的發展趨勢有三種:

              第一種可能是保持現狀:孤立的系統還會或長或短的持續一段時間。這是因為建設分布式系統的困難很難克服,或者因為孤立系統的獨特性和便捷性很難達到。基于這些原因,數據集成的核心問題仍然是如何恰當的使用數據。因此,集成數據的外部日志非常的重要。

              第二種可能是重構:具備通用性的單一的系統逐步融合多個功能形成超極系統。這個超級系統表面看起來類似關系數據庫系統,但是在組織中你使用時最大的不同是你只需要一個大的系統而不是無數個小系統。在這個世界里,除了在系統內已解決的這個問題不存在什么真正的數據集成問題。我想這是因為建設這樣的系統的實際困難。

              雖然另一種可能的結果對于工程師來說是很有吸引力的。新一代數據庫系統的特征之一是它們是完全開源的。開源提供了第三種可能性 :數據基礎架構不必打包成服務集或者面向應用的系統接口。在Java棧中,你可以看到在一定程度上,這種狀況已經發生了。

              分類計價嗎?

            • Zookeeper用于處理多個系統之間的協調,或許會從諸如Helix 或者Curator等高級別的抽象中得到一些幫助。
            • Mesos和YARN用于處理流程可視化和資源管理。
            • Lucene和LevelDB等嵌入式類庫做為索引。
            • Netty,Jetty和Finagle,rest.li等封裝成高級別的用于處理遠程通信。
            • Avro,Protocol Buffers,Thrift和umpteen zillion等其它類庫用于處理序列化。
            • Kafka和Bookeeper提供支持日志。

              如果你把這些堆放在一起,換個角度看,它有點像是簡化版的分布式數據庫系統工程。你可以把這些拼裝在一起,創建大量的可能的系統。顯而易見,現在探討的不是最終用戶所關心的API或者如何實現,而是在不斷多樣化和模塊化的過程中如何設計實現單一系統的途徑。因為隨著可靠的、靈活的模塊的出現,實施分布式系統的時間周期由年縮減為周,聚合形成大型整體系統的壓力逐步消失。

              日志文件在系統結構中的地位

              那些提供外部日志的系統如今已允許個人電腦拋棄他們自身復雜的日志系統轉而使用共享日志。在我看來,日志可以做到以下事情:

            • 通過對節點的并發更新的排序處理數據的一致性(無論在及時還是最終情況下)
            • 提供節點之間的數據復制
            • 提供”commit“語法(只有當寫入器確保數據不會丟失時才會寫入)
            • 位系統提供外部的數據訂閱資源
            • 提供存儲失敗的復制操作和引導新的復制操作的能力
            • 處理節點間的數據平衡

              這實際上是一個數據分發系統最重要的部分,剩下的大部分內容與終端調用的API和索引策略相關。這正是不同系統間的差異所在,例如:一個全文本查詢語句需要查詢所有的分區,而一個主鍵查詢只需要查詢負責鍵數據的單個節點就可以了。

              下面我們來看下該系統是如何工作的。系統被分為兩個邏輯區域:日志和服務層。日志按順序捕獲狀態變化,服務節點存儲索引提供查詢服務需要的所有信息(鍵-值的存儲可能以B-tree或SSTable的方式進行,而搜索系統可能存在與之相反的索引)。寫入器可以直接訪問日志,盡管需要通過服務層代理。在寫入日志的時候會產生邏輯時間戳(即log中的索引),如果系統是分段式的,那么就會產生與段數目相同數量的日志文件和服務節點,這里的數量和機器數量可能會有較大差距。

            數據庫

              服務節點訂閱日志信息并將寫入器按照日志存儲的順序盡快應用到它的本地索引上。

              客戶端只要在查詢語句中提供對應的寫入器的時間戳,它就可以從任何節點中獲取”讀寫“語義。服務節點收到該查詢語句后會將其中的時間戳與自身的索引比較,如果必要,服務節點會延遲請求直到對應時間的索引建立完畢,以免提供舊數據。

              服務節點或許根本無需知道”控制“或”投標選擇(leader election)“的概念,對很多簡單的操作,服務節點可以愛完全脫離領導的情況下提供服務,日志即是信息的來源。

              分發系統所需要做的其中一個比較復雜的工作,就是修復失敗節點并移除幾點之間的隔離。保留修復的數據并結合上各區域內的數據快照是一種較為典型的做法,它與保留完整的數據備份并從垃圾箱內回收日志的做法幾乎等價。這就使得服務層簡單了很多,日志系統也更有針對性。

              有了這個日志系統,你可以訂閱到API,這個API提供了把ETL提供給其它系統的數據內容。事實上,許多系統都可以共享相同的日志同時提供不同的索引,如下所示:

            數據庫

              這樣一個以日志為中心的系統是如何做到既數據流的提供者又同時加載其它系統的數據的呢?因為流處理器既可以消費多個輸入的數據流,隨后又可以通過其它系統對數據做索引為它們提供服務。

              這個系統的視圖可以清晰的分解到日志和查詢API,因為它允許你從系統的可用性和一致性角度分解查詢的特征。這可以幫助我們對系統進行分解,并理解那些并沒按這種方式設計實施的系統。

              雖然Kafka和Bookeeper都是一致性日志,但這不是必須的,也沒什么意義。你可以輕松的把Dynamo之類的數據構分解為一致性的AP日志和鍵值對服務層。這樣的日志使用起來靈活,因為它重傳了舊消息,像Dynamo一樣,這樣的處理取決于消息的訂閱者。

              在很多人看來,在日志中另外保存一份數據的完整復本是一種浪費。事實上,雖然有很多因素使得這件事并不困難。首先,日志可以是一種有效的存儲機制。我們在Kafka生產環境的服務器上存儲了5 TB的數據。同時有許多的服務系統需要更多的內存來提供有效的數據服務,例如文本搜索,它通常是在內存中的。服務系統同樣也需樣硬盤的優化。例如,我們的實時數據系統或者在內存外提供服務或者使用固態硬盤。相反,日志系統只需要線性的讀寫,因此,它很樂于使用TB量級的硬盤。最終,如上圖所示,由多個系統提供的數據,日志的成本分攤到多個索引上,這種聚合使得外部日志的成本降到了最低點。

              LinkedIn就是使用了這種方式實現它的多個實時查詢系統的。這些系統提供了一個數據庫(使用數據總線做為日志摘要,或者從Kafka去掉專用的日志),這些系統在頂層數據流上還提供了特殊的分片、索引和查詢功能。這也是我們實施搜索、社交網絡和OLAP查詢系統的方式。事實上這種方式是相當普遍的:為多個用于實時服務的服務系統提供單一的數據(這些來自Hadoop的數據或是實時的或是衍生的)。這種方式已被證實是相當簡潔的。這些系統根本不需要外部可寫入的API,Kafka和數據庫被用做系統的記錄和變更流,通過日志你可以查詢系統。持有特定分片的結點在本地完成寫操作。這些結點盲目的把日志提供的數據轉錄到它們自己的存儲空間中。通過回放上行流日志可以恢復轉錄失敗的結點。

              這些系統的程度則取決于日志的多樣性。一個完全可靠的系統可以用日志來對數據分片、存儲結點、均衡負載,以及用于數據一致性和數據復制等多方面。在這一過程中,服務層實際上只不過是一種緩存機制,這種緩存機制允許直接寫入日志的流處理。

              結束語

              如果你對于本文中所談到的關于日志的大部內容,如下內容是您可以參考的其它資料。對于同一事務人們會用不同的術語,這會讓人有一些困惑,從數據庫系統到分布式系統,從各類企業級應用軟件到廣闊的開源世界。無論如何,在大方向上還是有一些共同之處。

            9
            0

            互聯網熱門文章

              互聯網最新文章

                最新新聞

                  熱門新聞

                    中文大香蕉在线影院