• <center id="ye0c0"><u id="ye0c0"></u></center>
  • <optgroup id="ye0c0"><acronym id="ye0c0"></acronym></optgroup>
  • 大數據專題

    日志是每個軟件工程師關心的統一數據抽象

      這是來自LinkedIn的Kreps發表的一篇博文,雖然很長,但是被稱為程序員史詩般必讀文章。日志原本應該是運維人員掌握的,如今也是研發人員必須關心的,這是符合DevOps原則

    我是在六年前一個令人興奮的時刻加入到里了LinkedIn公司。從那個時候我們就開始突破傳統整體的(monolithic)、集中式的數據庫限制,然后切換到一個特殊的分布式系統。這是一件令人興奮的事情:重新構建、部署,這些分布式圖形數據庫、分布式搜索后端、Hadoop以及第一代和第二代key/value的NoSQL數據存儲直到今天仍然在運行。

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

    不懂得日志,你就不可能完全理解關心數據庫、NoSQL存儲,鍵值Key/value存儲,數據復制,分布式paxos協議、大數據處理Hadoop、甚至版本控制等幾乎所有的軟件系統;然而大多數軟件工程師對它們不是很熟悉。我愿意改變這種現狀。在這篇博客文章里,將介紹有關日志的所有的事情,包括日志是什么,如何在數據集成、實時處理和系統構建中使用日志等。

    第一部分:日志是什么?

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

    只能給日志的末尾添加記錄(append 類似隊列),日志記錄是從左到右讀取的。每一條日志記錄都有一個唯一的序列編號(一般我們使用時間戳)。?

    日志記錄的排序是由"時間"決定,處于左邊的記錄比右邊的要早些。記錄編號可以看作是這條記錄的"時間戳"。當然剛開始我們就把這種排序說成是按時間排序顯得有點多余 ,不過 ,與任何一個具體的物理時鐘相比,時間屬性是非常便于使用的屬性。在多個分布式系統中,時間會非常重要。?

    日志在存儲空間完全耗盡的情況下,就不可能再給日志添加記錄。稍后我們將會提到這個問題。?日志只是按照時間順序存儲記錄的?一種數據表或者文件,可以表現為日志文件或日志數據庫。

    日志重要特點是:它記錄了在某個什么時間發生了什么事情。 而這對分布式數據系統而言才是問題的真正核心。

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

    (實際上,如果你對它進行深入的思考,那么人們自己讀取某個機器上的日志這種理念有些不順應時代潮流。當涉及到許多服務和服務器的時候,這種方法很快就變成一個難于管理的。)

     

    數據庫日志

    我不知道日志概念是起源于何時何處-可能它就像二進制搜索一樣:發明者認為它太簡單而沒有當作一項發明。它最早出現在IBM的系統R

    日志在數據庫里的用法是:當數據庫崩潰的時候用日志來同步各種數據結構和索引。為了保證操作的原子性和持久性,在對數據庫進行維護,也就是所有各種數據結構做出更改之前,數據庫會把即將修改的信息備份追加到日志里。日志記錄了已經發生了什么,每個表或者索引都是其歷史投影。由于日志是即刻持久化的,所以在當機時可以用來作為恢復的可信數據源。

    隨著時間推移,日志用途從實現ACID發展為數據庫之間復制數據的一種方法。發生在數據庫上的操作動作順序與遠端備份數據庫上的操作順序通過日志保持完全同步。Oracle,MySQL 和PostgreSQL都是使用復制日志同步實現主從同步。Oracle還把日志產品化為一個通用的數據訂閱機制,這樣非Oracle數據訂閱用戶也可以使用XStreamsGoldenGate訂閱數據了,MySQL和PostgreSQL有類似的實現則,日志已經成為許多數據結構的關鍵組件。

    正是由于這樣的起源,機器可識別的日志這個概念大部分時候還是都被局限在數據庫內部。日志用做數據訂閱的機制似乎是偶然出現,不過要把這種數據抽象用于支持所有類型的消息傳輸、數據流和實時數據處理也是可行的。

     

    分布式系統日志

    日志解決了兩個問題:操作動作的順序化和數據的分發,這兩個問題在分布式數據系統里顯得尤為重要。保持一致的操作動作的順序是分布式系統設計的核心問題之一。

    以日志為中心實現分布式系統是受到了一個簡單經驗常識的啟發,它稱為狀態機復制原理:如果兩個相同的確定的處理過程從同一狀態開始,以相同的順序輸入相同的(數據或事件),那么這兩個處理過程必然會產生相同的輸出(結果),并且在最后相同的狀態結束。

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

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

    處理狀態是處理過程保存在計算機上的任何數據(狀態),在處理過程結束后,這些狀態數據要么保存在內存里,要么保存在磁盤上。

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

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

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

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

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

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

    分布式系統通常可以寬泛劃分為兩種方法來進行數據處理和復制。"狀態機器模型"通常使用一個active-active模型,在這個模型中我們保存了請求和該請求的復制處理。

    我們可以對"狀態機器模型"進行細微的更改,稱之為"預備份primary-backup模型",也就是選出一個副本做為leader,并允許它按照請求到達的時間來進行處理請求,并將該請求導致狀態的改變輸出到日志。其他的副本按照leader狀態改變的順序而應用執行這些改變,這樣他們之間就能達到同步,并能夠在leader失敗的時候接替leader的工作。

    如圖"預備份模型"和"狀態機器模型"是有些區別的,假定有一個算術服務,它內部有一個使用數字屬性作為它的狀態(初始值為0),并對這個值進行加法和乘法運算。active-active模型(狀態機器模型)方式應該會輸出所進行的變換,比如"+1","*2"等動作。每一個副本都會應用這些變換,從而得到同樣的結果集。active-passive(預備份模型)方式將會有一個獨立的主處理過程執行這些變換并輸出結果日志,比如"1","3","6"等。這個例子也清楚的展示了為什么說順序是保證各副本間一致性的關鍵:一次加法和乘法的順序的改變將會導致不同的結果。

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

    可能是由于過去的幾十年中,分布式計算的理論遠超過了其實際應用。在現實中,一致性的問題是有點太簡單了。計算機系統很少需要決定某個單值,他們幾乎總是處理成序列的請求。所以日志作為這樣的記錄,而不是一個簡單的單值寄存器,自然是更加抽象。?

    此外,專注于算法會掩蓋了 底層系統需要的日志的抽象。我懷疑,我們最終會把日志為一個商品化的基石,不論其是否以同樣的方式 實施,日志將成為一種大眾化的接口,為大多數算法和其實現提升提供最好的保證和最佳的性能。?

     

    記錄變更101: 表與事件是一對

    讓我們還是回到數據庫。數據庫中存在著大量重復:操作日志和表是一對“情侶”。這些日志有點類似借貸清單和銀行的流程,數據庫表記錄的是當前的盈余表。如果你有大量的操作日志,你就可以使用這些操作從而創建可以捕獲當前狀態的表(類似領域事件/CQRS)。這張表將記錄每個關鍵點(日志中一個特別的時間點)的狀態信息。這就是為什么日志是非常基本的數據結構的意義所在:日志可用來創建基本表,也可以用來創建各類衍生表。同時意味著可以存儲非關系型的對象。

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

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

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

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

    接下來的內容

    在這篇文章的其余部分,我將試圖說明日志除了可用在分布式計算或者抽象分布式計算內部模型之外,還可用在哪些方面。其中包括:?

    1. 數據集成-讓組織的全部數據存儲和處理系統里的所有數據很容易地得到訪問。

    2. 實時數據處理-計算生成的數據流。

    3. 分布式系統設計-實踐中的的系統是如何通過使用集中式日志來簡化設計。

    所有這些用法都是通過把日志用做單獨服務來實現的。?

    在上面任何一種用法里,日志的用途開始都是使用了日志所能提供的某個簡單功能:生成永久的、可重現的歷史記錄。令人意外的是,問題的核心是可以讓多少臺機器以特定的方式,按照自身的速度重現歷史記錄的能力。

    下頁

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

    Apache Kafka簡單介紹

    分布式系統的Raft算法

    通過實體快照實現事件建模

    CQRS架構

    如何理解Stream processing, Event sourcing, Reactive, CEP?

     

     

    美女漫画大全