http://samza.incubator.apache.org/learn/documentation/0.7.0/comparisons/introduction.html
這裡有一些使得Samza和其它流處理專案不同的高層設計決策。
The Stream Model 流模型
流是Samza job的輸入和輸出。Samza有非常強的流模械型——不僅是一個簡單的訊息交換系統。Samza中的stream是一個分割槽的、每個分割槽有序的、可重放的、多訂閱者的,無損的訊息序列。(A stream in Samza is partitioned,ordered-per-partition, replayable, multi-subscriber, lossless sequence of messages)。stream不僅是系統的輸入輸出,而且將處理步驟進行快取,使得它們互相隔離。
這個更強的模型需要持久化、容錯、以及流的實現提供快取功能。一個Samza job可以停止消費幾分鐘,甚至幾小時(可能因為一個不好的配置或者長時間執行的運算)而不會對上游的job有任何影響。這使得Samza適於大規模佈署,例如處理一個大型公司的所有資料流:job之間的獨立使得它們可以被使用不同程式碼庫、有不同SLA的不同小組來寫程式碼實現、擁有、執行。
這樣的設計受到我們使用Hadoop構建類似的離線處理流水線之經驗的啟發。在Hadoop中,processing stages是MapReduce jobs, processing stage的輸出是HDFS裡一個目錄裡的檔案。下一個processing stage就的輸入就是前一個processsing stage的輸出。我們發現stage之間的獨立使得我們可以有數百個鬆耦合的job,這些job由不同的小組維護,組成了一個離線處理生態系統。我們的目標是把這樣豐富的生態系統複製到近時實的環境裡。
這個強“流模型”的第二個好處就是所有的stage都是多訂閱者multi-subscriber的。在實際上,這意味著如果一個人新增加了一些生成輸資料流的處理流程,那麼其它人可以看到這些輸出,消費它們,構建於它們之上,而不會和另一個人的job有程式碼有任何耦合。一個討人喜的副作用是這使用除錯變得方便,因為你可以手動的檢視任何一個stage的輸出。
最後,這個強“流模型”strong stream model極大簡化了Samza框架特性的實現。每個job只需要自己的輸入輸出,在出故障的時候,每個job都可以獨自被恢復和重啟。不必要對整個資料流圖做中央控制。
為這個strong stream model而做的妥協是訊息被寫在磁碟上。我們樂於做出這個妥協因為MapReduce和HDFS展示了持久化儲存也可以提供很高的讀寫吞吐量,並且幾乎無限的磁碟空間。這個觀察是kafka的基礎,Kafka提供了數百MB/秒的有備份的吞吐,以及每個節點數TB的磁碟空間。所以按我們的使用方式,磁碟吞吐不是瓶頸。
MapReduce經常被指責進行不必要的磁碟寫。但是,這個指責對於流處理不怎麼適用:像MapReduce一樣的批處理經常被用於處理在短時間內處理很大的歷史資料集(比如,在10分鐘內查詢一分鐘的資料),而流處理大都需要跟進穩定的資料流(在10分鐘內處理10分鐘的資料)。這意味著流處理的原始吞吐量需求大都比批處理低幾個數量級。
State 狀態
只有非常簡單的流處理問題才是無狀態的(例如:一次處理一條訊息,和其它訊息都沒有關係)。很多流處理程式需要它的任務能維護一些狀態,例如:
- 如果需要知道對於一個user ID 已經有多少條訊息,就需要為每個user 維持一個計數器。
- 如果想要知道每天有多少不同的使用者訪問了你的網站,你需要保持一個use ID的集合,這個集合裡的user ID今天至少出現了一次。
- 如果你需要對兩個流做join(比如,如果你需要知道廣告的點進比click-through rate,你需要把展示廣告的訊息流和點選廣告的訊息流做join)你需要儲存一個流中的訊息直到你從另一個流中收到了相關的訊息。
- 如果你需要把從資料庫獲得的一些資訊新增進訊息(比如,把頁面訪問訊息用訪問頁面的使用者的資訊進行擴充套件),這個job就需要訪問資料庫的當前狀態。
一些狀態,例如計數器,可以被儲存在任務的記憶體中的計數器裡,但是如果這個任務重啟了,這些狀態可能就丟失了。或者,你可以把這些狀態存在遠端的資料庫裡,但是如果你每處理一條訊息就進行一次資料庫查詢,那麼效能就可能差到不可接受。Kafka可以輕鬆地在每個節點上處理100k~500k訊息/秒(和訊息大小有關),但是查詢一個遠端的鍵值儲存的吞吐量可能只有1~5k請求/秒——慢了兩個量級。
在Samza中,我們付出了專門的努力使得它具有高效能以及可靠的狀態。關鍵在於對每個節點保持狀態在本地(這樣就不需要通過網路進行查詢),並且通過複製狀態變化到其它流來使得它能應對機器故障(譯註:這裡的複製應該是說把當前任務的輸出發到其它的Stream裡,這就利用了其它Stream進行持久化)。
這種做法和資料庫的“變化捕獲”聯絡在一起就變得很有趣。拿之前的例子來說:你有一個包括了user ID的頁面點選流,你想把這些訊息用user的資訊進行擴充。乍一看來,你唯一的選擇就是對每一個user ID去查用資料庫。但是有了Samza,就可以做得更好。
“變化捕獲”意味著每次資料庫裡的資料發生變化,你獲得一個訊息來告訴你變化是什麼。如果你有一個這樣的訊息流,通過從資料庫建立起回放整個流,你可以獲得資料庫的所有內容。這個changelog流同樣可以做為Samza job的輸入流。
現在你可以寫一個Samza job,它使用頁面點選事件和changelog做為輸入。你確保它們使用同樣的key(例如 user ID)做分割槽。每次一個changelog事件進來,你就把更新後的使用者資訊寫在task的本地儲存上。每次一個頁面點選事件進來,你從本地儲存中獲取最新的使用者資訊。這樣的話,你就可以把所有的狀態保持在task的本地,而不用去查詢遠端的資料庫。
事實上,現在你有了主資料庫的一個副本,這個副本被分割槽,這些分割槽和Samza task在一臺機器上。資料庫寫仍然需要通過主資料庫,但是當你在處理訊息時需要讀資料庫,那你就只需要查詢本地的狀態。
這種做法不僅比查詢遠端的資料庫要快得多,而且它也更容易操作。如果你使用Samza處理一個很大容量的流,並且對每個訊息都做一次遠端查詢,那麼你很容易就使得資料庫過載了,這樣就會影響其它使用那個資料庫的服務。但是,當一個task使用本地狀態,它就和其它東西是獨立的,就不會影響其它服務。
分割槽的本地狀態不總是好的,也不總是必須的——Samza不會阻止你查詢外部的資料庫。如果你不能從你的資料庫獲取其變化資訊,或者你需要其它遠端服務的邏輯,那麼當然從你的Samza job來請求一個遠端的服務也是很方便的。但是如果你需要使用在本地的狀態,那麼 Samza本身提供了這功能。
Execution Framework 執行框架
我們所做的最後一個決定是不去為Samza構建一個自己的分散式執行系統。取而代之後是,執行環境是可插拔的,目前是由YARN來提供。這樣有兩點好處:
第一個好處是很實際的:有另一群聰明人在搞execution framework。YARN正在以很快的步驟開發,並且己經支援了很多跟資源限定和安全有關的功能。它允許你控制叢集的哪一部分由哪些使用者和使用者組來使用,並且可以通過cgroups控制每個節點的資源使用(CPU,記憶體等)。YARN可以大規模執行以支援Hadoop,並且有希望成為無所不在的一層。因為Samza整個通過YARN執行,因此在YARN叢集之外沒有另外的守護程式或者master。也就是說,如果你已經有了Kafka和YARN,你就不用安裝其它東西來執行Samza job。
第二點,Samza和YARN的組合完全是元件化的。和YARN的組合在另外一個包裡,並且Samza的主框架在編譯時並不依賴它。它意味著YARN可以被另一個虛擬化框架取代——我們對增加Samza和AWS的組合很感興趣。很多公司使用AWS,AWS本身就是一個虛擬化框架,它和YARN對於Samza是一樣的:它允許你來建立和銷燬虛擬"container“機器以及保證這些container使用確定的資源fixed resources。因為流處理任務是長時間執行的,在AWS之內執行一個YARN叢集,然後對單獨的job進行排程,這種做法有點傻。反之,一個更合適的方法是為你的job直接分派一些EC2例項。
我們認為在像Mesos和YARN這樣的開源的虛擬化框架,以及像Amazon提供的商業化的雲服務裡有很多創新,所有裝Samza和它們進行組合是合理的。
下一節:MUPD8 (先不翻譯了)