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