注意: 這一章還未完成編輯拐迁,你閱讀的內(nèi)容中還存在大量機器翻譯的結(jié)果
第4章 使用日志構(gòu)建數(shù)據(jù)系統(tǒng)
我要討論的最后一個主題是日志在聯(lián)機數(shù)據(jù)系統(tǒng)內(nèi)部的作用德召。
日志在分布式數(shù)據(jù)庫內(nèi)部用于數(shù)據(jù)流的作用與它在大型組織中用于數(shù)據(jù)集成的作用之間存在類比。在這兩種情況下毁涉,它都負責(zé)數(shù)據(jù)流,一致性和恢復(fù)。畢竟歹茶,一個組織如果不是一個非常復(fù)雜的分布式數(shù)據(jù)系統(tǒng),那又是什么呢?
也許斜視一下惊豺,你可以將整個組織的系統(tǒng)和數(shù)據(jù)流視為一個非常復(fù)雜的分布式數(shù)據(jù)庫燎孟。你可以將所有單個面向查詢的系統(tǒng)(Redis,SOLR尸昧,Hive表等)查看為數(shù)據(jù)上的特定索引揩页。你可以將諸如Storm或Samza之類的流處理系統(tǒng)視為一種非常完善的觸發(fā)和視圖實現(xiàn)機制。我已經(jīng)注意到烹俗,古典數(shù)據(jù)庫人員非常喜歡這種觀點爆侣,因為它最終向他們解釋了人們在使用所有這些不同數(shù)據(jù)系統(tǒng)的工作-它們只是不同的索引類型!
不可否認衷蜓,現(xiàn)在數(shù)據(jù)類型的爆炸式增長累提,但是實際上,這種復(fù)雜性一直存在磁浇。即使在關(guān)系數(shù)據(jù)庫的鼎盛時期斋陪,組織也有許多關(guān)系數(shù)據(jù)庫!因此置吓,自從大型機真正將所有數(shù)據(jù)都放在一個地方以來无虚,可能就沒有真正的集成。將數(shù)據(jù)分為多個系統(tǒng)的動機很多:規(guī)模衍锚,地理位置友题,安全性和性能隔離是最常見的。好的系統(tǒng)可以解決這些問題戴质。例如度宦,一個組織可能有一個包含所有數(shù)據(jù)并服務(wù)于眾多不同群體的Hadoop集群。
因此告匠,在遷移到分布式系統(tǒng)中時戈抄,數(shù)據(jù)處理已經(jīng)存在一種可能的簡化:將每個系統(tǒng)的許多小實例合并為幾個大集群。許多系統(tǒng)尚不足以允許這樣做后专,因為它們沒有安全性划鸽,不能保證性能隔離或只是擴展性不夠好。但是戚哎,這些問題都是可以解決的裸诽。你可以運行一個由整個組織的所有應(yīng)用程序共享的大型多租戶系統(tǒng),而不必運行一個系統(tǒng)的許多小型單服務(wù)器實例型凳。這樣可以極大地提高管理和利用效率丈冬。
拆分?
我認為不同系統(tǒng)的爆炸式增長是由于構(gòu)建分布式數(shù)據(jù)系統(tǒng)的困難而引起的甘畅。通過減少到單個查詢類型或用例殷蛇,每個系統(tǒng)都可以將其范圍縮小到可以構(gòu)建的一組事物中实夹。運行所有這些系統(tǒng)會產(chǎn)生太多的復(fù)雜性。
我看到將來可能會遵循三個可能的方向粒梦。
第一種可能性是現(xiàn)狀的延續(xù):系統(tǒng)的分離或多或少會保持更長的時間。之所以會發(fā)生這種情況荸实,可能是因為分發(fā)的困難難以克服匀们,或者是因為這種專業(yè)化使每個系統(tǒng)的便利性和功能性達到了新的水平。只要這是正確的准给,數(shù)據(jù)集成問題將仍然是成功使用數(shù)據(jù)的最重要的重要問題之一泄朴。在這種情況下,集成數(shù)據(jù)的外部日志將非常重要露氮。
第二種可能性是可能進行重新整合祖灰,其中具有足夠普遍性的單個系統(tǒng)開始將所有不同功能合并回單個ubersystem。這個超級系統(tǒng)從表面上看就像關(guān)系數(shù)據(jù)庫一樣畔规,但是在組織中的使用卻大不相同局扶,因為你只需要一個大型系統(tǒng),而不需要多個小型系統(tǒng)叁扫。在這個世界上三妈,除了系統(tǒng)內(nèi)部要解決的問題之外,沒有真正的數(shù)據(jù)集成問題莫绣。我認為建立這樣一個系統(tǒng)的實際困難使這不太可能畴蒲。
還有另一種可能的結(jié)果,也是很吸引作為工程師的我的一種对室。新一代數(shù)據(jù)系統(tǒng)的一個有趣方面是模燥,它們幾乎都是開源的。開源提供了另一種可能性:數(shù)據(jù)基礎(chǔ)架構(gòu)可以捆綁為服務(wù)和面向應(yīng)用程序的系統(tǒng)API的集合掩宜。你已經(jīng)在Java堆棧中看到了這種情況:
- Zookeeper可以處理大部分系統(tǒng)協(xié)調(diào)工作(也許會得到來自更高級的抽象蔫骂,例如Helix或Curator)。
- Mesos和YARN處理虛擬化和資源管理锭亏。
- 諸如Lucene纠吴,RocksDB和LMDB之類的嵌入式庫都可以建立索引。
- Netty慧瘤,Jetty和Finagle和rest.li等更高級別的包裝程序可以遠程處理通訊戴已。
- Avro,協(xié)議緩沖區(qū)锅减,Thrift和不計其數(shù)的其他庫處理序列化糖儡。
- Kafka和BookKeeper提供了備份日志。
如果將這些東西堆放并斜視一下怔匣,它將開始看起來像是LEGO版本的分布式數(shù)據(jù)系統(tǒng)工程握联。你可以將這些成分拼湊在一起桦沉,以創(chuàng)建大量可能的系統(tǒng)。對于最終用戶而言金闽,這顯然不是一個故事纯露,他們可能更關(guān)心API而不是其實現(xiàn)方式,但這可能是在不斷發(fā)展的更加多樣化和模塊化的世界中實現(xiàn)單個系統(tǒng)的簡單性的一條途徑代芜。如果分布式系統(tǒng)的實施時間從數(shù)年到數(shù)周不等埠褪,因為出現(xiàn)了可靠,靈活的構(gòu)建基塊挤庇,那么合并為單個整體系統(tǒng)的壓力就消失了钞速。
日志在系統(tǒng)架構(gòu)中的位置
假定存在外部日志的系統(tǒng)允許各個系統(tǒng)放棄自己的大部分復(fù)雜性,并依靠共享日志嫡秕。日志可以執(zhí)行以下操作:
- 通過對并發(fā)進行排序來處理數(shù)據(jù)一致性(無論是最終的還是即時的)更新節(jié)點
- 提供節(jié)點之間的數(shù)據(jù)復(fù)制
- 向作者提供“提交”語義(例如僅在你的寫保證不會丟失)
- 提供系統(tǒng)的外部數(shù)據(jù)訂閱源
- 提供恢復(fù)丟失數(shù)據(jù)或引導(dǎo)新的失敗副本的功能復(fù)制品
- 處理節(jié)點之間的數(shù)據(jù)重新平衡
這實際上是分布式數(shù)據(jù)系統(tǒng)所做工作的重要部分蝌借。實際上叭爱,剩下的大部分與最終面向客戶的查詢API和索引策略有關(guān)间驮。這正是系統(tǒng)之間應(yīng)有所不同的部分尘奏;例如,全文搜索查詢可能需要查詢所有分區(qū)潮改,而按主鍵查詢可能只需要查詢負責(zé)該鍵數(shù)據(jù)的單個節(jié)點狭郑。
這是這樣的。該系統(tǒng)分為兩個邏輯部分:日志和服務(wù)層汇在。日志按順序捕獲狀態(tài)更改翰萨。服務(wù)節(jié)點存儲服務(wù)查詢所需的任何索引(例如,鍵值存儲可能具有btree或sstable之類的內(nèi)容糕殉,而搜索系統(tǒng)則具有反向索引的內(nèi)容)亩鬼。寫入可以直接進入日志,盡管它們可能被服務(wù)層代理阿蝶。寫入日志會產(chǎn)生邏輯時間戳記(例如日志中的索引)雳锋。如果系統(tǒng)已分區(qū)(我假設(shè)已分區(qū)),那么日志和服務(wù)節(jié)點將具有相同數(shù)量的分區(qū)羡洁,即使它們的計算機數(shù)量可能非常不同玷过。
服務(wù)節(jié)點訂閱日志,并按照日志存儲它們的順序筑煮,盡快將寫入操作應(yīng)用于其本地索引(請參見圖4-1)辛蚊。
通過提供寫入的時間戳作為其查詢的一部分真仲,客戶端可以從任何節(jié)點獲取“讀取時寫入”的語義袋马。接收到此類查詢的服務(wù)節(jié)點會將所需的時間戳記與其自身的索引點進行比較,并在必要時將請求延遲秸应,直到它已被索引到至少那個時間為止虑凛,以避免服務(wù)過時的數(shù)據(jù)碑宴。
服務(wù)節(jié)點可能需要也可能不需要掌握所有權(quán)或領(lǐng)導(dǎo)者選舉的概念。對于許多簡單的用例桑谍,由于日志是事實的來源延柠,因此服務(wù)節(jié)點可以完全沒有領(lǐng)導(dǎo)者。
分布式系統(tǒng)必須做的棘手的事情之一是處理恢復(fù)故障節(jié)點或?qū)⒎謪^(qū)從一個節(jié)點移到另一個節(jié)點锣披。一種典型的方法是使日志僅保留一個固定的數(shù)據(jù)窗口捕仔,并將其與分區(qū)中存儲的數(shù)據(jù)快照結(jié)合起來。日志也可以保留完整的數(shù)據(jù)副本并壓縮日志本身盈罐。這將大量的復(fù)雜性從服務(wù)層(這是系統(tǒng)特定的)移出并移到了日志(這可以是通用的)中。
通過使用此日志系統(tǒng)闪唆,你可以獲得針對ETL饋入其他系統(tǒng)的數(shù)據(jù)存儲內(nèi)容的完整開發(fā)的訂閱API盅粪。實際上,許多系統(tǒng)可以在提供不同索引的同時共享同一日志悄蕾,如圖4-2所示:
請注意,這種以日志為中心的系統(tǒng)本身如何立即成為數(shù)據(jù)流的提供者帆调,以便在其他系統(tǒng)中進行處理和加載奠骄。同樣,流處理器可以消耗多個輸入流番刊,然后通過另一個對輸出進行索引的系統(tǒng)為它們提供服務(wù)含鳞。
我發(fā)現(xiàn)作為日志和查詢API的因素,這種系統(tǒng)視圖非常有啟發(fā)性芹务,因為它使你可以將查詢特征與系統(tǒng)的可用性和一致性方面分開蝉绷。我實際上認為,這甚至是一種有用的方法枣抱,可以從心理上考慮并非以這種方式構(gòu)建的系統(tǒng)以更好地理解它熔吗。
值得注意的是,盡管Kafka和BookKeeper是一致的日志佳晶,但這不是必需的桅狠。你可以輕松地將類似Dynamo的數(shù)據(jù)庫納入最終一致的AP日志和鍵值服務(wù)層。這樣的日志有點棘手轿秧,因為它會重新傳遞舊消息中跌,并取決于訂閱者來處理(就像Dynamo本身一樣)。
在日志中擁有單獨的數(shù)據(jù)副本(尤其是完整副本)的想法使許多人感到浪費淤刃。實際上晒他,有一些因素使這不再是一個問題。首先逸贾,日志可以是一種特別有效的存儲機制陨仅。在實時數(shù)據(jù)中心中津滞,我們在Kafka中擁有PB級日志存儲的絕大部分。同時灼伤,許多服務(wù)系統(tǒng)需要更多的內(nèi)存才能有效地提供數(shù)據(jù)(例如触徐,文本搜索通常全部位于內(nèi)存中)。服務(wù)系統(tǒng)也可能使用優(yōu)化的硬件狐赡。例如撞鹉,我們大多數(shù)實時數(shù)據(jù)系統(tǒng)要么內(nèi)存不足,要么使用SSD颖侄。相比之下鸟雏,日志系統(tǒng)僅執(zhí)行線性讀取和寫入,因此使用大型多TB硬盤驅(qū)動器非常滿意览祖。最后孝鹊,如圖4-2所示,在數(shù)據(jù)由多個系統(tǒng)提供服務(wù)的情況下展蒂,日志成本將在多個索引上攤銷又活。這種組合使外部日志的開銷相當(dāng)小。
這正是LinkedIn用來構(gòu)建其自己的許多實時查詢系統(tǒng)的模式锰悼。這些系統(tǒng)將數(shù)據(jù)庫更新直接生成的日志或其他實時處理派生的日志作為輸入柳骄,并在該數(shù)據(jù)流之上提供特定的分區(qū),索引和查詢功能箕般。這就是我們實現(xiàn)搜索耐薯,社交圖譜,新聞源和OLAP查詢系統(tǒng)的方式隘世。實際上可柿,將單個數(shù)據(jù)源(無論是實時源還是從Hadoop派生的源)復(fù)制到多個服務(wù)系統(tǒng)中進行實時服務(wù)是很普遍的。事實證明丙者,這種面向日志的數(shù)據(jù)流是一個巨大的簡化假設(shè)复斥。這些系統(tǒng)完全不需要外部可訪問的寫API。Kafka和數(shù)據(jù)庫用作記錄系統(tǒng)械媒,并通過該日志將流更改為適當(dāng)?shù)牟樵兿到y(tǒng)目锭。寫入由托管特定分區(qū)的節(jié)點在本地處理。這些節(jié)點將日志提供的提要盲目地轉(zhuǎn)錄到其自己的存儲中纷捞×『纾可以通過重播上游日志來恢復(fù)發(fā)生故障的節(jié)點。
這些系統(tǒng)對日志的依賴程度有所不同主儡。完全依賴的系統(tǒng)可以利用日志進行數(shù)據(jù)分區(qū)奖唯,節(jié)點還原,重新平衡以及一致性和數(shù)據(jù)傳播的所有方面糜值。在此設(shè)置中丰捷,實際的服務(wù)層不過是一種緩存坯墨,該緩存的結(jié)構(gòu)旨在實現(xiàn)特定類型的處理,而寫入直接進入日志病往。
結(jié)論
日志為我們提供了一種原理化的方法捣染,可以對通過分布式系統(tǒng)級聯(lián)的不斷變化的數(shù)據(jù)進行建模。這對于在大型企業(yè)中為數(shù)據(jù)流建模以及在分布式數(shù)據(jù)庫中為數(shù)據(jù)流內(nèi)部建模一樣有效停巷。有了這種基本的抽象耍攘,就可以為我們提供將各種數(shù)據(jù)系統(tǒng)粘合在一起,處理實時更改的方法畔勤,以及本身就是一個有趣的系統(tǒng)和應(yīng)用程序體系結(jié)構(gòu)的方法蕾各。從某種意義上說,我們所有的系統(tǒng)現(xiàn)在都是分布式系統(tǒng)庆揪,因此曾經(jīng)有點分散的分布式數(shù)據(jù)庫實現(xiàn)細節(jié)現(xiàn)在變成了與現(xiàn)代軟件工程師非常相關(guān)的概念示损。
章節(jié)列表: