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

寫在前面

這是來自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數據訂閱用戶也可以使用XStreams和GoldenGate訂閱數據了,MySQL和PostgreSQL有類似的實現則,日誌已經成為許多數據結構的關鍵組件。

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

分佈式系統日誌

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

以日誌為中心實現分佈式系統是受到了一個簡單經驗常識的啟發,它稱為狀態機複製原理:

如果兩個相同的確定的處理過程從同一狀態開始,以相同的順序輸入相同的(數據或事件),那麼這兩個處理過程必然會產生相同的輸出(結果),並且在最後相同的狀態結束。

一千個人眼中有一千種日誌的用法。數據庫工作者通常區分物理日誌和邏輯日誌。物理日誌就是記錄每一行被改變的內容。邏輯日誌記錄的不是改變的行,而是那些引起行的內容被改變的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. 分佈式系統設計-實踐中的的系統是如何通過使用集中式日誌來簡化設計。

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

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

最後給大家送點免費的東西

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

現在開放資源免費領取,送給需要高清架構腦圖,架構視頻資料、架構電子書和Java面試文件,以及想要提升技術的朋友。

獲取資料的方式:轉發+私信【資料】領取!

都看到這裡了,別忘了點個關注喲。以後會持續分享更多幹貨!!


分享到:


相關文章: