標籤:
1、storm事務性topology的提出
對於容錯機制,Storm通過一個系統層級的組件acker,結合xor校正機制判斷一個msg是否發送成功,進而spout可以重發該msg,保證一個msg在出錯的情況下至少被重發一次。但是在一些事務性要求比較高的情境中,需要保障一次只有一次的語義,比如需要精確統計tuple的數量等等。Storm 0.7.0引入了Transactional Topology, 它可以保證每個tuple”被且僅被處理一次”, 這樣你就可以實現一種非常準確,非常可擴充,並且高度容錯方式來實現計數類應用。
2、API介紹
IBatchBolt有三個方法
execute(Tuple tuple)
finishBatch()
prepare (java.util.Map conf, TopologyContext context, BatchOutputCollector collector,T id)
ITransactionalSpout有以下幾個主要方法:
ITransactionalSpout.Coordinator<T> getCoordinator(java.util.Map conf,
TopologyContext context)
ITransactionalSpout.Emitter<T> getEmitter(java.util.Map conf,
TopologyContext context)
3、事務機制原理分析
1) 對於一次只有一次的語義,從原理上來講,需要在發送tuple的時候帶上xid,在需要交易處理的時候,根據該xid是否以前已經處理成功來決定是否進行處理,當然需要把xid和處理結果一起做儲存。並且需要保障順序性,在當前請求xid提交前,所有比自己低xid請求都已經提交。
在交易處理時單個處理tuple效率比較低,因此storm中引入batch處理,一批tuple賦予一個xid,為了提高batch之間處理的並行度,storm採用了pipeline 處理的模型。參見pipeline模型,多個事務可以並存執行,但是commit的是嚴格按照順序的。
對應到storm中的具體實現中,把一個batch的計算分成了兩個階段processing和commit階段:
Processing階段:多個batch可以並行計算,上面例子中bolt2是普通的batchbolt(實現BaseBatchBolt),那麼多個batch在bolt2的task之間可以並存執行,比如對batch3和batch4並存執行execute或finishbatch(什麼時候調用該操作,後面會介紹)方法。
Commiting階段:batch之間強制按照順序進行提交,中Bolt3實現BaseBatchBolt並且標記需要交易處理的(實現了ICommitter介面或者通過TransactionalTopologyBuilder的setCommitterBolt方法把BatchBolt添加到topology裡面),那麼在Storm認為可以提交(至於什麼時候可以提交,後面會介紹)batch的時候調用finishbatch,在finishBatch做xid的比較以及狀態儲存工作。例子中batch2必須等待batch1提交後,才可以進行提交。
Storm事務性的拓撲看起來比較複雜,需要對batch的commit進行管理,錯誤的發現,batch的發射以及處理等等,其內部實現完全基於storm的相關底層操作進行抽象。
當使用Transactional Topologies的時候, storm為你做下面這些事情:
- 管理狀態: Storm把所有實現Transactional Topologies所必須的狀態儲存在zookeeper裡面。 這包括當前transaction id以及定義每個batch的一些中繼資料。
- 協調事務: Storm幫你管理所有事情, 以幫你決定在任何一個時間點是該proccessing還是該committing。
- 錯誤偵測: Storm利用acking架構來高效地檢測什麼時候一個batch被成功處理了,被成功提交了,或者失敗了。Storm然後會相應地replay對應的batch。你不需要自己手動做任何acking或者anchoring — storm幫你搞定所有事情。
- 內建的批處理API: Storm在普通bolt之上封裝了一層API來提供對tuple的批處理支援。Storm管理所有的協調工作,包括決定什麼時候一個bolt接收到一個特定transaction的所有tuple。Storm同時也會自動清理每個transaction所產生的中間資料。
- 最後,需要注意的一點是Transactional Topologies需要一個可以完全重發(replay)一個特定batch的訊息的隊列系統(Message Queue)。storm-contrib裡面的storm-kafka實現了這個。
事務性topology從實現上來講,包括事務性的spout,以及事務性的bolt。
2) 事務性的spout需要實現ITransactionalSpout,這個介面包含兩個內部類Coordinator和Emitter。在topology啟動並執行時候,事務性的spout內部包含一個子的topology,類似下面這個結構:
其中coordinator是spout,emitter是bolt。
這裡面有兩種類型的tuple,一種是事務性的tuple,一種是真實batch中的tuple;
coordinator為事務性batch發射tuple,Emitter負責為每個batch實際發射tuple。
具體如下:
- coordinator只有一個,emitter根據並行度可以有多個執行個體
- emitter以all grouping(廣播)的方式訂閱coordinator的”batch emit”流
- coordinator (其實是是一個內部的spout)開啟一個事務準備發射一個batch時候,進入一個事務的processing階段,會發射一個事務性tuple(transactionAttempt & metadata)到”batch emit”流
*****說明******
TransactionalTopology裡發送的tuple都必須以TransactionAttempt作為第一個field,storm根據這個field來判斷tuple屬於哪一個batch。
TransactionAttempt包含兩個值:一個transaction id,一個attempt id。transaction id的作用就是我們上面介紹的對於每個batch中的tuple是唯一的
,而且不管這個batch replay多少次都是一樣的。attempt id是對於每個batch唯一的一個id, 但是對於同一個batch,它replay之後的attempt id跟replay之前就不一樣了,
我們可以把attempt id理解成replay-times, storm利用這個id來區別一個batch發射的tuple的不同版本
metadata(中繼資料)中包含當前事務可以從哪個point進行重放資料,存放在zookeeper中的,spout可以通過Kryo從zookeeper中序列化和還原序列化該中繼資料。
**************
- Emiter接收到這個tuble後,會進行batch tuple的發送
- Storm通過anchoring/acking機制來檢測事務是否已經完成了processing 階段;
- Processing階段完成後,並且之前的transactions都已經提交了,coordinator發射一個tuble到” commit”流,進入commit階段。
- commiting bolts通過all grouping方式訂閱該”commit”流,事務提交後,coordinator同樣通過anchoring/acking機制確認已經完成了commit階段,接收到ack後,在zookeeper上把該transaction標記為完成。
3) 事務性的Bolt繼承BaseTransactionalBolt,處理batch在一起的tuples,對於每一個tuple調用調用execute方法,而在整個batch處理(processing)完成的時候調用finishBatch方法。如果BatchBolt被標記成Committer,則只能在commit階段調用finishBolt方法。一個batch的commit階 段由storm保證只在前一個batch成功提交之後才會執行。並且它會重試直到topology裡面的所有bolt在commit完成提交。那麼如何知道batch的processing完成了,也就是bolt是否接收處理了batch裡面所有的tuple;在bolt內部,有一個CoordinatedBolt的模型。
CoordinateBolt具體原理如下:
CoordinateBolt具體原理如下:
- 真正執行計算的bolt外面封裝了一個CoordinateBolt。真正執行任務的bolt我們稱為real bolt。
- 每個CoordinateBolt記錄兩個值:有哪些task給我發送了tuple(根據topology的grouping資訊);我要給哪些tuple發送資訊(同樣根據groping資訊)
- Real bolt發出一個tuple後,其外層的CoordinateBolt會記錄下這個tuple發送給哪個task了。
- 等所有的tuple都發送完了之後,CoordinateBolt通過另外一個特殊的stream以emitDirect的方式告訴所有它發送過 tuple的task,它發送了多少tuple給這個task。下遊task會將這個數字和自己已經接收到的tuple數量做對比,如果相等,則說明處理 完了所有的tuple。
- 下遊CoordinateBolt會重複上面的步驟,通知其下遊。
事務性的拓撲在storm中的一個應用是Trident,它是在storm的原語和事務性的基礎上做更高層次的抽象,做到一致性和恰好一次的語義。
Storm在批處理和事務方面的機制分析