如何提高jms程序的健壯性

jms api 提供了一下的方式來創建一個健壯的 jms 應用程序

•控制消息的確認方式(acknowledgment)

•配置消息的持久性(確保當 jms 提供者失敗時,消息不會丟失)

•設置消息的優先級(影響消息傳遞的順序)

•允許消息過期(設置消息的過期時間,這樣消息過期後 jms provider 就會丟棄此消息)

•創建臨時目的地(臨時目的會在創建它的連接被關閉時被銷燬)
•創建持久訂閱
•使用本地事務
控制消息確認方式

如果一條消息沒有被確認,那麼 jms provider 會認爲此消息沒有成功地被消費。一條消息成功地被客戶端消費通常包含3個步驟:

1.客戶端接收到這條消息
2.客戶端成功處理這條消息
3.客戶端確認這條消息

消息的確認是由 jms provider 觸發還是由客戶端觸發,這取決於會話的確認模式。

在事務性會話中,事務提交的時候會自動確認消息,當事務被回滾,所有消費的消息都會被重傳。

在非事務性會話中,什麼時候以及如何確認消息取決於 createQueueSession 、 createTopicSession 和 createSession 方法的第二個參數的取值。有三種可選的取值:

•Session.AUTO_ACKNOWLEDGE 會話自動確認。當客戶端調用 receive 方法併成功返回以及調用 MessageListener 處理消息併成功返回後,會話會自動確認已成功接收到消息。在 AUTO_ACKNOWLEDGET 會話中,同步接收消息是一個例外(消費一條消息包含三個步驟),在這種情況下,消息接收和確認在同一個步驟中發生。
•Session.CLIENT_ACKNOWLEDGE 客戶端確認。客戶端通過調用消息的 acknowledge 方法手動確認成功接收一條消息。在這種模式下,消息確認發生在會話級別,確認一條消息會自動確認由此會話消費的所有消息。例如,一個消費者消費10條消息,並在消費第5條消息的時候調用了 acknowledge 方法,這會確認所有的10條消息。
•Session.DUPS_OK_ACKNOWLEDGE 這個選項會使會話延遲消息的確認。在消息傳遞過程中,如果 jms provider 失敗,這可能會導致傳遞一些重複的消息,因此只有在消費者允許重複的消息時才考慮使用此模式(如果重傳一條消息,jms provider 必須設置消息頭 JMSRedelivered 爲 true)。

當 QueueSession 被關閉,jms provider 會保持那些客戶端已經接受到但還沒有確認的消息,並在下一次客戶端連接到隊列的時候重傳這些消息。同樣,當 TopicSession 關閉,jms provider 也會保持那些持久 TopicSubcriber 沒有確認的消息。非持久 TopicSubscriber 沒有確認的消息,當會話關閉時會被丟棄。

如果使用隊列和持久訂閱,可以調用方法 Session.recover 使會話停止當前消息傳遞,並從第一個沒有確認的消息開始重新傳遞,這會使消息傳遞的順序與消息發送的順序不一致。對於非持久訂閱的 TopicSubscriber,當恢復會話時 jms provider 可能會丟棄沒有確認的消息。

設置消息的持久性

jms 提供了兩種消息傳遞模式,這兩種模式決定了當 jms provider 失敗時消息是否會丟失。DeliveryMode 接口提供了這兩種傳遞模式。

PERSISTENT 傳遞模式要求 jms provider 確保在消息傳輸過程中如果 jms provider 失敗消息不會丟失,這是默認的傳輸模式。使用這種模式發送的消息在發送的時候會被記錄到一個持久儲存中。

NON_PERSISTENT 傳遞模式不要求 jms provider 把消息保存到持久存儲中,同樣也不保證如果 jms provider 失敗,消息不會丟失。

有兩種方式設置消息傳遞模式:

1.調用 MessageProducer 的 setDelieryMode 方法設置傳遞模式,此 MessageProducer 發送的消息都使用這個方法設置的傳遞模式。
2.使用重載的 send 和 publish 方法設置特定消息的傳遞模式

如果不指定傳遞模式,默認使用 PERSISTENT 模式。使用 NON_PERSISTENT 可以提高性能以及降低存儲需求。

設置消息優先級

可以使用優先級使 jms provider 優先傳遞緊急的消息。有兩種方式設置消息優先級。

1.調用 MessageProducer 的 setPriority 方法設置此 MessageProducer 發送的消息的優先級
2.調用重載的 send 和 publish 方法爲特殊的消息設置優先級

消息的優先級從0(最低)到9(最高)有10種級別。如果沒有設置優先級,默認優先級爲4。jms provider 會確保優先級高的消息會在優先級低的消息之前被傳遞,但並不保證會嚴格按照優先級的順序來傳遞消息。

允許消息過期

默認情況下,消息永遠不會過期。但如果一條消息在一段時間之後就會被廢棄,那麼可以設置消息的過期時間。有兩種方式可以設置消息的過期時間。

1.調用 MessageProducer 的 setTimeToLive 設置 MessageProducer 發送的消息的默認過期時間
2.使用重載的 send 和 publish 方法設置特定消息的過期時間

如果設置 timeToLive 爲0,那麼消息永遠不會過期。

發送消息時,會使用當前時間與 timeToLive 的和設置消息的過期時間。任何在指定的過期時間之前沒有被傳遞的消息都會被銷燬。

創建臨時目的

jms 提供了方法 QueueSession.createTemporaryQueue 和 TopicSession.createTemporaryTopic 來創建臨時隊列 TemporaryQueue 和臨時主題 TemporaryTopic,臨時目的在創建它們的連接被關閉時會被銷燬。

僅有使用創建臨時目的的連接創建的消費者才能消費臨時目的上的消息,但任何一個消息生產者都可以向臨時目的上發送消息。如果關閉創建臨時目的地連接,那麼臨時目的也會被關閉,臨時目的上的消息會丟失。


創建持久訂閱

爲了確保發佈/訂閱應用程序能夠接收到所有已發佈的消息,在發佈端可以使用 PERSISTENT 傳遞模式傳輸消息以確保消息不回在傳輸過程中丟失,而在訂閱端則可以使用持久訂閱來保證能夠收到所有已發佈的消息。

TopicSession.createSubscriber 方法創建一個非持久訂閱者。非持久訂閱者只能接收到在它處於活動狀態時發佈的消息。

可以使用方法 TopicSession.createDurableSubscriber 創建一個持久訂閱者。持久訂閱在任何時候僅能有一個訂閱者。

一個持久訂閱者使用一個由 jms provider 維護的唯一的標識符註冊一個持久訂閱。隨後的訂閱者會恢復之前訂閱者在關閉之前的狀態。如果一個持久訂閱沒有處於活動狀態的訂閱者,jms provider 會保持訂閱的消息直到這些消息被訂閱者接收到或者消息過期。

使用如下設置能夠創建一個持久訂閱的唯一標識符:

•爲連接設置一個唯一的客戶 id( Connection.setClientID )
•訂閱的主題名以及訂閱的名稱

創建了一個連接並設置了其客戶 id 之後,可以使用連接創建 Session,並調用這個 Session 的 createDurableSubscriber 來創建一個持久訂閱者,這個方法接收兩個參數,第一個參數是一個主題名,第二個參數是創建的這個持久訂閱的名稱,例如:

String topicName = "myTopic";
String subName = "mySub";
TopicSubscriber sub = topicSession.createDurableSubscriber( topicName, subName );


調用 TopicConnection 的 start 方法後此訂閱者就處於活動狀態。這之後可以關閉此 TopicSubscriber:

topicSubscriber.close();

jms provider 會保存發佈到這個主題上的消息。如果任意一個應用程序使用具有相同客戶 id 的連接,並使用相同的主題和訂閱名調用 createDurableSubscriber 方法,那麼這個持久訂閱就會被激活,jms provider 就會把在此訂閱者處於不活動狀態發佈的消息傳遞給此訂閱者。

刪除一個持久訂閱,首先要關閉訂閱者,然後使用訂閱名調用 unsubscribe 方法註銷持久訂閱。

topicSubscriber.close();
topicSession.unsubscribe( "mySub" );

unsubscribe 方法會使 jms provder 刪除它維護的關於訂閱者的狀態信息。


使用本地事務

可以把一系列操作組成一個稱爲事務的原子工作單元。如果一個操作失敗,事務會被回滾,並可以嘗試重新執行這一組操作。如果這一組操作都成功,事務則會被提交。

jms 客戶端可以在事務中發送和接受一組消息。jms api 中的 Session 接口提供了 commit 和 rollback 方法來提交回滾事務。事務提交意味着生產的所有消息都會被髮送,消費的所有消息都會被確認。事務回滾意味着生產的消息都會被銷燬,消費的消息都會被重傳直到它們過期。

一個事務性會話始終包含在一個事務中。只要調用了 commit 方法或 rollback 方法,這意味着一個事務的結束,新的事務的開始。關閉事務性會話會回滾正在進行的事務。

當創建會話的時候可以指定會話是否爲事務性的。方法 createQueueSession 與 createTopicSession 的第一個參數是一個 boolean 類型的,如果設爲 true 則新建的會話爲事務性的,如果爲 false 新建的回話則不是事務性的。這兩個方法的第二個參數是設置確認模式的,這個值只有在非事務性回話中有效,事務性會話則會忽略確認模式,所以可以設置爲0,例如:

topicSession = topicConnection.createTopicSession( true, 0 );

由於本地事務的提交與回滾是與回話相關聯的,所以不能把對隊列的主題的操作綁定到同一個事務中。因爲 QueueReceiver、QueueSender 與 TopicSubscriber、TopicPublisher 分別是由 QueueSession 和 TopicSession 創建的。
發佈了34 篇原創文章 · 獲贊 0 · 訪問量 1533
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章