2017-09-25 51 views
0

當消費者失敗時,我需要確保重新傳遞JMS消息,但這裏類似問題上接受的策略可能不適用於我的情況。如何在客戶端崩潰時確保JMS消息重新傳遞

考慮一個JMS客戶端 - spring + activeMq--接收不會丟失或重複的消息。由於消息的處理非常昂貴,客戶端會批量處理它們。場景播放如下:

  • T1 - 客戶端接收消息A,B,C和d
  • T2 - 線程在客戶端上被喚醒並決定處理消息A,B和C
  • T3 - 客戶端收到消息E和F
  • T4 - 線程返回已處理A,B和C的數據。如果另一個線程尚未完成,它可以接收下一批。

生產者建立現在的方式 - 消息,儘快爲他們交付刪除,是否已經由一個線程拿起與否 -和Session.AUTO_ACKNOWLEDGEDefaultJmsListenerContainerFactory。如果客戶在T4之前停機,則消息A到F將丟失。

我正打算使用Session.CLIENT_ACKNOWLEDGE在生產者和獲得每個線程T4之後調用msg.acknowledge(),但根據documentation,這也將確認E和F,這將是如果客戶在T4之後失敗,則丟失。

我不確定交易會話是否會對此有所幫助,因爲它將涵蓋消息A到F,而線程完成只保證已處理該消息的子集。

我的目標是保證在發生客戶端故障時(例如,虛擬機停機,所有尚未被線程成功處理的消息都保留在主題/隊列中。當客戶回來時,他們可以被客戶接收。

關於如何實現這一點的任何想法?

小號

回答

0

我想提的第一件事情是,你不應該使用CLIENT_ACKNOWLEDGE原因你會更差,提高輸率。客戶端確認,因爲你所說的還會承認相關本地jms會話中的所有消息,否則將確認來自一個批次的所有提取的消息。

消息,儘快爲他們交付拆除,它們是否 被一個線程拿起或不

通常承認是送回來時,onMessage方法調用已完成。你的意思是什麼線索?如果您的處理是在同一個線程中完成的,那麼它似乎只會在調用成功後纔會發送確認。

你是如何實現批量消費的?如果你的意思是活躍的mq消費者(http://activemq.apache.org/performance-tuning.html),並且你正在使用Spring(WS或Integration)和AMQ代碼庫提供的功能,那麼你應該只將自己的努力放在適當的配置上,而不是做一些複雜的自定義實現來達到99.999999%的成功率。每個jms經紀人都會丟失消息或者有重複的消息,並且你永遠不會得到0的丟失率。而對於大多數企業系統來說,這是一個正常的情況,例如,萬分之一的消息丟失或重複。

爲了得到某種可靠的交付,你應該使用持久交付模式和jms交易。對我而言,重複的消息要比完全丟失更好(實際上,所有系統架構都應該被構建爲處理這種事情的冪等)。正如你所說,AMQ文檔批次也是可靠性與性能之間的折衷。從根本上說,沒有機會同時實現兩個屬性。至少通過AMQ和jms。所以這是在你決定什麼對你來說更重要的可靠性或表現。對於您來說,最理想的選擇是定義這種權衡,並確定哪些批量的重複郵件在丟失或重複郵件的情況下是可以接受的。

+0

是的,auto_ack在onMessage()完成後完成。目前,此方法僅將消息添加到集合(以簡化)並返回。當滿足某些條件(時間,集合的大小...)時,線程決定是時候處理集合中的部分消息。這意味着在auto_ack中,msg ack和實際處理之間會有一段時間。也許我所追求的是不可行的,正如你所說的,我只需要配置集合的大小以至多保留我可以承受的最小丟失數量。 –

+0

在這種情況下,實際上您可以使用像mapdb或smth這樣的持久數據結構。從發送郵件到某個內部渠道的那一刻起,實際上您有責任在此郵件的進一步訪問後留心。試圖通過經紀人完成這項工作將導致複雜的邏輯沒有任何需要。但對我來說,即使mapdb看起來像一個開銷,我懷疑你的情況是一個好的架構。從我的角度來看,最好的選擇就是建議您可以丟失或獲取一些較低信息量的重複項並設置合適的窗口大小 –