以下是我們認(rèn)為 Samza 與其他流處理項(xiàng)目略有不同的高級(jí)設(shè)計(jì)決策。
流是 Samza 工作的輸入和輸出。Samza 有一個(gè)非常強(qiáng)大的流模型 - 它不僅僅是一個(gè)簡(jiǎn)單的消息交換機(jī)制。Samza 中的一個(gè)流是一個(gè)分區(qū)的,有序的每分區(qū)的,可重播的,多用戶的,無(wú)損的消息序列。流不僅僅是系統(tǒng)的輸入和輸出,還包括將處理階段彼此隔離的緩沖區(qū)。
這種更強(qiáng)大的模型需要在流實(shí)現(xiàn)中的持久性,容錯(cuò)性和緩沖性,但它具有幾個(gè)好處。
首先,下游處理階段的延遲不能阻止上游階段。Samza 的工作可能會(huì)停止使用幾分鐘甚至幾個(gè)小時(shí)(可能是因?yàn)椴渴鸩患鸦蜷L(zhǎng)時(shí)間運(yùn)行的計(jì)算),而不會(huì)對(duì)上游作業(yè)產(chǎn)生任何影響。這使Samza 適合大型部署,例如處理一家大型公司的所有數(shù)據(jù)流:在由不同 SLA 組成的不同代碼庫(kù)中的不同團(tuán)隊(duì)進(jìn)行編寫(xiě),擁有和運(yùn)行時(shí),工作之間的隔離至關(guān)重要。
這是我們?cè)?Hadoop 中構(gòu)建類似的離線處理流水線的經(jīng)驗(yàn)的動(dòng)力。在 Hadoop 中,處理階段是 MapReduce 作業(yè),處理階段的輸出是 HDFS 上的文件目錄。到下一個(gè)處理階段的輸入僅僅是由較早階段產(chǎn)生的文件。我們發(fā)現(xiàn),階段之間的這種強(qiáng)大的隔離使得有可能有??數(shù)百個(gè)松散耦合的工作,由不同的團(tuán)隊(duì)維護(hù),構(gòu)成一個(gè)離線處理生態(tài)系統(tǒng)。我們的目標(biāo)是在近乎實(shí)時(shí)的環(huán)境中復(fù)制這種豐富的生態(tài)系統(tǒng)。
這個(gè)更強(qiáng)大的模式的第二個(gè)好處是所有階段都是多用戶。實(shí)際上,這意味著如果一個(gè)人添加一組創(chuàng)建輸出數(shù)據(jù)流的處理流,其他人可以看到輸出,消耗它,并在其上構(gòu)建,而不會(huì)在作業(yè)之間引入代碼的任何耦合。作為一個(gè)愉快的副作用,這使得調(diào)試流程變得容易,因?yàn)槟梢允謩?dòng)檢查任何階段的輸出。
最后,這種強(qiáng)大的流模型大大簡(jiǎn)化了 Samza 框架中功能的實(shí)現(xiàn)。每個(gè)工作只需要關(guān)心自己的輸入和輸出,而在出現(xiàn)故障的情況下,每個(gè)作業(yè)都可以獨(dú)立恢復(fù)和重新啟動(dòng)。不需要對(duì)整個(gè)數(shù)據(jù)流圖進(jìn)行中央控制。
我們需要為這個(gè)更強(qiáng)大的流模型做出的權(quán)衡是將消息寫(xiě)入磁盤(pán)。我們?cè)敢庾龀鲞@個(gè)權(quán)衡,因?yàn)?MapReduce 和 HDFS 已經(jīng)表明,持久存儲(chǔ)可以提供非常高的讀寫(xiě)吞吐量和幾乎無(wú)限的磁盤(pán)空間。這個(gè)觀察是 Kafka 的基礎(chǔ),它允許每百個(gè) MB /秒的復(fù)制吞吐量,每個(gè)節(jié)點(diǎn)有很多 TB 的磁盤(pán)空間。當(dāng)以這種方式使用時(shí),磁盤(pán)吞吐量通常不是瓶頸。
MapReduce 有時(shí)被批評(píng)為寫(xiě)入磁盤(pán)而不是必要的。然而,這種批評(píng)對(duì)于流處理的用處較少:像 MapReduce 這樣的批量處理常常用于在短時(shí)間內(nèi)處理大量的歷史數(shù)據(jù)集(例如,在十分鐘內(nèi)查詢一個(gè)月的數(shù)據(jù)),而流處理主要需要跟上數(shù)據(jù)的穩(wěn)態(tài)流動(dòng)(在10分鐘內(nèi)處理10分鐘的數(shù)據(jù))。這意味著流處理的原始吞吐量要求通常比批量處理要低一個(gè)數(shù)量級(jí)。
只有非常簡(jiǎn)單的流處理問(wèn)題才是無(wú)狀態(tài)的(即可以一次處理一個(gè)消息,而與所有其他消息無(wú)關(guān))。許多流處理應(yīng)用程序需要一個(gè)工作才能保持一些狀態(tài)。例如:
某些狀態(tài)(如計(jì)數(shù)器)可以在任務(wù)中保存在內(nèi)存中,但是如果重新啟動(dòng)作業(yè),那么該狀態(tài)將丟失?;蛘撸梢詫顟B(tài)保留在遠(yuǎn)程數(shù)據(jù)庫(kù)中,但如果需要對(duì)每個(gè)處理的消息執(zhí)行數(shù)據(jù)庫(kù)查詢,則性能可能會(huì)變得不可接受。Kafka 可以輕松處理每個(gè)節(jié)點(diǎn) 100k-500k 的消息/秒(取決于消息大?。?,但是針對(duì)遠(yuǎn)程鍵值存儲(chǔ)的查詢的吞吐量往往比每秒更接近1-5k個(gè)請(qǐng)求 - 兩個(gè)數(shù)量級(jí)。
在薩姆薩,我們特別努力地支持高性能,可靠的狀態(tài)。關(guān)鍵是保持每個(gè)節(jié)點(diǎn)的本地狀態(tài)(以便查詢不需要遍歷網(wǎng)絡(luò)),并通過(guò)將狀態(tài)更改復(fù)制到另一個(gè)流來(lái)使其對(duì)于機(jī)器故障的穩(wěn)健性。
當(dāng)與數(shù)據(jù)庫(kù)更改捕獲相結(jié)合時(shí),這種方法特別有趣。以上面的示例,您有一個(gè)頁(yè)面視圖事件流,包括查看該頁(yè)面的用戶的 ID,并且您希望使用該用戶的更多信息來(lái)擴(kuò)充事件。乍一看,它看起來(lái)好像只能查詢用戶數(shù)據(jù)庫(kù)來(lái)查找您看到的每個(gè)用戶標(biāo)識(shí)(可能有一些緩存)。有了 Samza,我們可以做得更好。
更改捕獲意味著每次數(shù)據(jù)庫(kù)中的某些數(shù)據(jù)發(fā)生變化時(shí),您會(huì)收到一個(gè)事件,告訴您哪些更改。如果您有更改事件流,一直返回創(chuàng)建數(shù)據(jù)庫(kù)時(shí),可以通過(guò)重播流來(lái)重建數(shù)據(jù)庫(kù)的整個(gè)內(nèi)容。該更改日志流也可以用作 Samza 作業(yè)的輸入。
現(xiàn)在,您可以編寫(xiě)一個(gè)同時(shí)將 page-view 事件和 changelog 作為輸入的 Samza 作業(yè)。您確保它們?cè)谙嗤拿荑€上分區(qū)(例如用戶 ID )。每當(dāng) changelog 事件進(jìn)入時(shí),您將更新的用戶信息寫(xiě)入任務(wù)的本地存儲(chǔ)。每次頁(yè)面瀏覽事件進(jìn)入時(shí),都會(huì)從本地存儲(chǔ)中讀取有關(guān)該用戶的當(dāng)前信息。這樣,您可以將本地的所有狀態(tài)保留在任務(wù)中,而不需要查詢遠(yuǎn)程數(shù)據(jù)庫(kù)。
實(shí)際上,您現(xiàn)在擁有主數(shù)據(jù)庫(kù)的副本,分為與 Samza 任務(wù)位于同一計(jì)算機(jī)上的小分區(qū)。數(shù)據(jù)庫(kù)寫(xiě)入仍然需要轉(zhuǎn)到主數(shù)據(jù)庫(kù),但是當(dāng)您需要從數(shù)據(jù)庫(kù)中讀取以便從輸入流處理消息時(shí),可以查看任務(wù)的本地狀態(tài)。
這種方法不僅要比查詢遠(yuǎn)程數(shù)據(jù)庫(kù)要快得多,而且對(duì)于操作來(lái)說(shuō)也更好。如果您正在使用 Samza 處理大量流,并對(duì)每個(gè)消息進(jìn)行遠(yuǎn)程查詢,則可以輕松地使用請(qǐng)求壓倒數(shù)據(jù)庫(kù),并使用相同的數(shù)據(jù)庫(kù)影響其他服務(wù)。相比之下,當(dāng)一個(gè)任務(wù)使用本地狀態(tài)時(shí),它與其他任何東西是隔絕的,所以它不會(huì)意外地將其他服務(wù)丟棄。
分區(qū)的本地狀態(tài)并不總是適當(dāng)?shù)?,不是必需?- Samza 中沒(méi)有任何內(nèi)容可以防止對(duì)外部數(shù)據(jù)庫(kù)的調(diào)用。如果您不能從數(shù)據(jù)庫(kù)中產(chǎn)生更改的提要,或者您需要依賴只存在于遠(yuǎn)程服務(wù)中的邏輯,那么從 Samza 作業(yè)調(diào)用遠(yuǎn)程服務(wù)可能會(huì)更為方便。但是,如果要使用本地狀態(tài),它將開(kāi)箱即用。
我們做出的一個(gè)最終決定是不要在 Samza 建立一個(gè)定制的分布式執(zhí)行系統(tǒng)。相反,執(zhí)行是可插拔的,目前由 YARN 完全處理。這有兩個(gè)好處。
第一個(gè)好處是實(shí)用的:還有另一個(gè)智能人員團(tuán)隊(duì)在執(zhí)行框架上工作。YARN 正在快速發(fā)展,并且已經(jīng)支持圍繞資源配額和安全性的豐富功能。這允許您控制分配給哪些用戶和組的哪些部分,并通過(guò) cgroup 控制各個(gè)節(jié)點(diǎn)(CPU,內(nèi)存等)的資源利用率。YARN 大規(guī)模運(yùn)行以支持 Hadoop,并可能成為無(wú)處不在的層。由于 Samza 完全通過(guò) YARN 運(yùn)行,所以沒(méi)有獨(dú)立的守護(hù)程序或主人可以超越 YARN 群集本身。換句話說(shuō),如果你已經(jīng)有了 Kafka 和 YARN,你不需要安裝任何東西才能運(yùn)行 Samza 的工作。
其次,我們與 YARN 的整合是完全組合的。它存在于一個(gè)單獨(dú)的包中,而主要的 Samza 框架在構(gòu)建時(shí)不依賴于它。這意味著 YARN 可以被其他虛擬化框架所替代 - 特別是我們有興趣添加直接的 AWS 集成。許多公司在 AWS 上運(yùn)行,這本身就是一個(gè)虛擬化框架,Samza 的目的相當(dāng)于 YARN:它允許您創(chuàng)建和銷毀虛擬“容器”機(jī)器,并保證這些容器的固定資源。由于流處理作業(yè)長(zhǎng)時(shí)間運(yùn)行,因此在 AWS 內(nèi)部運(yùn)行 YARN 群集,然后在此群集中安排各個(gè)作業(yè)是有點(diǎn)愚蠢的。相反,更明智的做法是直接為您的工作分配一組 EC2 實(shí)例。
我們認(rèn)為,像 Mesos 和 YARN 這樣的開(kāi)放源碼虛擬化框架以及像亞馬遜這樣的商業(yè)云提供商將會(huì)有很多創(chuàng)新,所以與它們整合是有意義的。
更多建議: