Storm之trident序列化問題

在使用Stormtrident做流計算開發時,遇到一個詭異的問題:

我繼承IPartitionedTridentSpout或者IOpaquePartitionedTridentSpout接口做事務型實時計算的開發,類型T通常是用來每個批次序列化到ZK中的偏移量。我遇到的問題是:只要實時應用啓動後不終止,每個批次發送的消息的偏移量都是接着上一個批次消息的偏移量繼續向後移動的。但是隻要應用終止後重新啓動,發送的消息就會從消息隊列的起始位置重新開始,好像ZK中保存的偏移量根本沒起作用。

之前在沒有使用trident的時候,我繼承的是IPartitionedTransactionalSpout或者IOpaquePartitionedTransactionalSpout接口。這兩個接口在處理每個批次時,都會將下一批次消息的偏移量序列化到ZK中,當需要發送下一批次的消息時,是從ZK中去讀取下一批次消息的偏移量。按照這個處理邏輯,應該不會出現一直運行就正常,一重啓就重頭髮送消息這種問題。

研究了trident的源碼後發現,原來trident對這一塊邏輯做了改進,爲了減輕ZK的壓力,trident在內存中維護了一個TreeMap類型的對象,裏面保存了批次ID與偏移量的對應關係。Trident在處理每個批次消息的時候都會既向TreeMap中保存一份偏移量,又向ZK中序列化一份偏移量。在需要處理下一批次消息時,trident只是從內存的TreeMap中讀取偏移量,而不需要從ZK中讀取偏移量,只有當應用重啓時,trident才從ZK中讀取偏移量。

這就很好的解釋了爲什麼我的應用一直運行時沒有問題,一旦重啓,處理的消息就會從頭開始。同時,也可以推理出,其實trident序列化到ZK中的偏移量應該是有問題的,這才導致應用重啓時沒有讀出來。

ZK中去查了一下序列化進去的偏移量,發現果然序列化出現了問題。於是,繼續研究trident做序列化的代碼。發現原來trident修改了序列化對象的方式。從backtype.storm.transactional.state.TransactionalState裏面的setDatagetData方法可以看到,非tridentstorm使用的是Kryo序列化框架;而從storm.trident.topology.state.TransactionalState裏面的setDatagetData方法可以看到,trident使用的是JSON-Simple的序列化方式,再具體點是用
String org.json.simple.JSONValue.toJSONString(Object arg0) 
方法進行序列化。原生的JSONValue.toJSONString()方法是不能序列化自定義類的。而我之前使用的T類型

就是一個自定義類型,這也是導致偏移量沒有成功序列化到ZK中的原因。最後我將T類型修改爲JSONObject來保存偏移量,解決了序列化到ZK錯誤的問題。

我不大清楚trident修改序列化方式的目的是什麼。它導致之前使用非trident封裝Spout的代碼無法重用,希望對序列化有深入研究的同學能夠指教 

轉自:http://blog.sina.com.cn/s/blog_6ff05a2c0101lajp.html

發佈了96 篇原創文章 · 獲贊 6 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章