The Log

在LinkedIn分布式化中過(guò)程中,我學(xué)到最有用的東西,是我們構(gòu)建的很多系統(tǒng),在背后都有一個(gè)非常簡(jiǎn)單的思想,日志。有時(shí)日志也叫做WAL(Write Ahead Logs)或者提交日志或者事務(wù)日志。日志其實(shí)已經(jīng)存在很久了,幾乎和計(jì)算機(jī)存在的時(shí)間一樣長(zhǎng),很多分布式數(shù)據(jù)系統(tǒng)和實(shí)時(shí)應(yīng)用架構(gòu)的核心就是日志。

如果你不了解日志,你就肯定不能徹底理解數(shù)據(jù)庫(kù),NoSQL存儲(chǔ),kv存儲(chǔ),復(fù)制,paxos協(xié)議,hadoop,版本控制,甚至其他任何軟件系統(tǒng)。即使這樣,現(xiàn)在中大多數(shù)軟件工程師對(duì)日志并不熟悉。我希望改變這種現(xiàn)狀,在這篇文章中,我會(huì)帶著你了解有關(guān)日志的一切,包括日志是什么,怎樣使用日志做數(shù)據(jù)集成,實(shí)時(shí)數(shù)據(jù)處理和系統(tǒng)架構(gòu)。

第一部分,日志是什么?

日志可能是最簡(jiǎn)單的存儲(chǔ)抽象。日志是一種只能在尾部添加,完全順序的,按照時(shí)間排序的一組記錄。日志長(zhǎng)得像這樣:

Log

記錄被添加到日志尾部,并從左到右讀取。日志中的每一條記錄都包含一個(gè)唯一的日志序列號(hào)。

日志記錄的順序定義了一個(gè)時(shí)間的概念,因?yàn)樵谖覀兊亩x中,右邊的記錄要比左邊的記錄“大”。這種情況下,日志序列號(hào)就可以被當(dāng)做每條記錄的時(shí)間戳。把順序定義為時(shí)間的概念一開(kāi)始看起來(lái)有點(diǎn)奇怪,但是這其實(shí)是一個(gè)很有用的屬性,因?yàn)檫@樣一來(lái)系統(tǒng)的時(shí)間就不依賴(lài)任何物理時(shí)鐘了。當(dāng)我們說(shuō)到分布式系統(tǒng)時(shí),這會(huì)是一個(gè)非常有用的屬性。

在我們現(xiàn)在的討論當(dāng)中,日志的內(nèi)容和格式并不重要,同時(shí),我們也不能一直追加日志,因?yàn)榇鎯?chǔ)空間遲早會(huì)耗盡。

所以,日志和文件或者數(shù)據(jù)庫(kù)表并沒(méi)有本質(zhì)的不同。文件是一個(gè)字節(jié)數(shù)組,數(shù)據(jù)庫(kù)表是一個(gè)記錄數(shù)組,日志其實(shí)就像一張數(shù)據(jù)庫(kù)表或者一個(gè)文件,只是日志里的記錄按照時(shí)間順序排序過(guò)。

說(shuō)到現(xiàn)在,你可能奇怪,為什么要說(shuō)這么簡(jiǎn)單的東西?一個(gè)只能在尾部追加的記錄序列到底和數(shù)據(jù)系統(tǒng)有什么關(guān)系?答案是,日志記錄了發(fā)生的事情以及發(fā)生的時(shí)間。在很大程度上來(lái)說(shuō),這其實(shí)就是分布式系統(tǒng)要處理的核心問(wèn)題。

在進(jìn)一步闡釋之前,我要先解釋清楚一個(gè)疑惑。每個(gè)程序員都對(duì)另一種日志特別熟悉 - 非結(jié)構(gòu)化的錯(cuò)誤日志或者應(yīng)用程序的trace信息。我把這些日志稱(chēng)為“應(yīng)用日志”。應(yīng)用日志其實(shí)我們這里討論的日志的一種降級(jí)形式。他們最大的區(qū)別是,應(yīng)用日志是用肉眼去讀并理解的,而數(shù)據(jù)日志是用程序來(lái)處理的。

數(shù)據(jù)庫(kù)中的日志

我其實(shí)并不知道日志這個(gè)概念是誰(shuí)發(fā)明的,也有可能是這個(gè)概念像二分查找一樣,太簡(jiǎn)單,連發(fā)明者都沒(méi)有意識(shí)到他發(fā)明了一個(gè)東西。日志最早在IBM的System R中出現(xiàn)。在數(shù)據(jù)庫(kù)中,日志是作用是在崩潰情況下也能保持不同種類(lèi)的數(shù)據(jù)結(jié)構(gòu)及索引的同步。為了實(shí)現(xiàn)原子性和持久性,在把修改真正應(yīng)用到數(shù)據(jù)之前,數(shù)據(jù)庫(kù)使用日志來(lái)保存對(duì)數(shù)據(jù)的修改。日志是真正發(fā)生的事情的記錄,數(shù)據(jù)庫(kù)表和索引只是把發(fā)生過(guò)的事情映射到某種有用的數(shù)據(jù)結(jié)構(gòu)之中。由于日志是立即持久化的,在系統(tǒng)崩潰的時(shí)候會(huì)用日志來(lái)恢復(fù)其他的持久性數(shù)據(jù)結(jié)構(gòu)。

隨著時(shí)間推移,日志的使用已經(jīng)從最初的數(shù)據(jù)庫(kù)ACID性質(zhì)實(shí)現(xiàn),發(fā)展到數(shù)據(jù)庫(kù)之間復(fù)制數(shù)據(jù)的方法。事實(shí)證明,這一連串對(duì)數(shù)據(jù)修改的記錄,恰恰就是和遠(yuǎn)程數(shù)據(jù)庫(kù)保持同步的關(guān)鍵。Oracle,MySQL和PostgreSQL都包含日志傳輸協(xié)議,用來(lái)在從數(shù)據(jù)庫(kù)上復(fù)制數(shù)據(jù)。Oracle已經(jīng)把他們的Xstreams和GoldenGate產(chǎn)品化,MySQL和PostgreSQL也有相似的關(guān)鍵技術(shù)。

正因?yàn)槿绱?,機(jī)器可讀的日志概念,僅僅被限制在數(shù)據(jù)庫(kù)的范疇之內(nèi)。使用日志作為數(shù)據(jù)訂閱的機(jī)制好像只是因?yàn)橐馔舛a(chǎn)生的。但是這種抽象對(duì)于支持消息,數(shù)據(jù)流動(dòng)和實(shí)時(shí)數(shù)據(jù)處理來(lái)說(shuō)非常完美。

在分布式系統(tǒng)中的日志

日志解決的兩個(gè)問(wèn)題是,數(shù)據(jù)變化順序和數(shù)據(jù)分布,在分布式環(huán)境中顯得更加重要。在數(shù)據(jù)的更新上達(dá)成一致是分布式系統(tǒng)設(shè)計(jì)時(shí)需要考慮的核心問(wèn)題。

以日志為核心的分布式系統(tǒng),是從一個(gè)簡(jiǎn)單的觀察結(jié)果而來(lái),這里我們把它叫做狀態(tài)機(jī)復(fù)制原則:

如果兩個(gè)相同的確定性系統(tǒng),從一個(gè)相同的狀態(tài)開(kāi)始,且以相同的順序獲得相同的輸入,兩個(gè)系統(tǒng)會(huì)產(chǎn)生相同的輸出,并且以相同的狀態(tài)結(jié)束運(yùn)行。

這個(gè)描述可能聽(tīng)起來(lái)有點(diǎn)不清楚,我來(lái)解釋一下。

確定性系統(tǒng)的意思是,數(shù)據(jù)的處理并不依賴(lài)時(shí)間, 也不會(huì)因?yàn)槠渌粗斎胗绊戄敵觥Ee例來(lái)說(shuō),如果一個(gè)程序的輸出會(huì)被線程執(zhí)行的順序影響,或者被gettimeofday這個(gè)函數(shù)調(diào)用影響,或者被某些不可重復(fù)發(fā)生的事情影響,這個(gè)程序就不具有確定性。

程序的狀態(tài)就是程序運(yùn)行結(jié)束后機(jī)器上存儲(chǔ)的數(shù)據(jù),不管是在內(nèi)存里還是在磁盤(pán)上。

程序以相同順序獲得相同輸入這點(diǎn)可能會(huì)給我們一個(gè)暗示,這里和日志有關(guān)。這其實(shí)是一個(gè)非常直覺(jué)可以理解的概念,如果給兩個(gè)確定性程序相同的輸入日志,這兩個(gè)程序會(huì)產(chǎn)生相同的輸出。

把日志的概念應(yīng)用到分布式系統(tǒng)上的方式就很明顯了。在分布式環(huán)境下的所有機(jī)器做同一件事的問(wèn)題,可以簡(jiǎn)化為,實(shí)現(xiàn)一個(gè)分布式一致性日志系統(tǒng),把日志作為這些程序的輸入就好了。日志在這里的作用是,排除一切非確定性的輸入,確保所有副本同步處理輸入。

這個(gè)方式的美妙之處在于,以前作為索引的日志時(shí)間戳,現(xiàn)在也可作為副本的狀態(tài)時(shí)鐘。你可以用最大處理日志序列號(hào)這個(gè)數(shù)字來(lái)描述一個(gè)副本。這個(gè)時(shí)間戳和日志結(jié)合起來(lái),描述了副本的整個(gè)狀態(tài)。

有非常多的方式可以把這個(gè)原理應(yīng)用到依賴(lài)日志輸入的系統(tǒng)。理論上,我們甚至可以用日志記錄每一條副本需要執(zhí)行的指令或者副本需要執(zhí)行的方法名和參數(shù)。只要兩個(gè)程序用相同的方式處理這些輸入,這兩個(gè)程序的數(shù)據(jù)會(huì)始終保持一致。

不領(lǐng)域的人會(huì)用不同方式來(lái)描述日志。比如數(shù)據(jù)庫(kù)工作者會(huì)區(qū)分物理日志和邏輯日志。物理日志是記錄了每一行記錄改變的內(nèi)容。邏輯日志記錄了改變數(shù)據(jù)的SQL,比如insert/update/delete。

書(shū)本上通常會(huì)描述兩種數(shù)據(jù)處理和復(fù)制的方式。狀態(tài)機(jī)模型,通常指的是為每一個(gè)請(qǐng)求記錄日志,并且每一個(gè)副本逐一處理每一條請(qǐng)求。另一個(gè)模型主-備模型稍微有點(diǎn)不同,在這個(gè)模型下,系統(tǒng)會(huì)選舉一個(gè)副本作為leader,leader會(huì)執(zhí)行請(qǐng)求并記錄數(shù)據(jù)修改內(nèi)容,其他備份會(huì)把數(shù)據(jù)修改通過(guò)日志同步到本地。

Two Models

為了理解這兩種方法的區(qū)別,我們來(lái)看一個(gè)玩具問(wèn)題。假設(shè)有一個(gè)“算法服務(wù)”,它維護(hù)了一個(gè)數(shù)字作為它的狀態(tài),并且初始化為零,后續(xù)這個(gè)服務(wù)對(duì)這個(gè)數(shù)字進(jìn)行加法和乘法計(jì)算。主-主的模型可能會(huì)記錄數(shù)字的變化,比如“+1”或者“+2”。每個(gè)副本會(huì)經(jīng)歷相同順序的數(shù)字變化。主-備模型會(huì)有一個(gè)主服務(wù)來(lái)執(zhí)行計(jì)算,并且日志記錄結(jié)果,比如“1”,“3”,“6”。這個(gè)簡(jiǎn)單的例子也說(shuō)明為什么順序?qū)τ跀?shù)據(jù)的一致性至關(guān)重要,因?yàn)閷?duì)加法和乘法的重排序會(huì)產(chǎn)生不同的計(jì)算結(jié)果。


Paxos

分布式日志也可以被當(dāng)做一致性協(xié)議的數(shù)據(jù)模型。畢竟,日志就是為數(shù)據(jù)下一個(gè)變化的值做的決定。你可以看一個(gè)paxos算法中的日志是什么樣子的,及時(shí)paxos算法也被用來(lái)創(chuàng)建日志。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容