1.消息類型的選擇
Java的JMS消息類型有文本類型,對象類型,位元組類型,流類型,XML類型,在實際項目中,用的最多的是文本類型,對象類型和xml類型的消息.建議最好不用對象類型,因為如果用對象類型的話,調試的時候是很麻煩的,首先你必須要寫專門的測試代碼用來發送消息,第二,必須要管理對象所屬的類的不同版本,第三,不友善檢視queue或者topic中的消息内容.而如果使用文本類型或者xml類型的消息,那麼可以很容易的通過JMS中間件提供的一些管理工具來發送測試消息,檢視消息内容,并且更加容易管理不同版本之間的相容性.如果一定要用對象類型消息的話,建議使用xstream把對象轉化為xml .
2.是使用queue還是topic?
這兩者的定義是很清楚的,也很容易區分.但是在實際項目中,如何來取舍呢?我的建議是盡量用queue.如果你的項目用到了JMS,那麼你的系統也應該是到了需要部署在叢集環境的規模了.用topic在叢集環境下會帶來很多麻煩.舉個簡單的例子,如果你是用MDB來處理topic的消息,你有一個MDB名為SampleMDB,它以叢集的方式分别部署在A伺服器和B伺服器上.那麼有可能同一條topic消息被同一個MDB處理兩次.雖然一些JMS中間件提供商為解決這種問題提供了一些解決方案,例如把subsriber分組,但是它為開發和調試都帶來了很大的麻煩.topic消息的處理也要比queue的複雜,很難跟蹤topic消息的處理過程.
那麼,如果不用topic的話,怎麼來實作topic這種性質的消息處理呢?可以寫一個消息轉發器,把一個queue上的消息轉發給所有關注這個queue的其它queue中.例如,有一個queue,名為SampleQ1,一個消息發送者sender,一個消息轉發器router,有三個handler A,B,C需要處理這個queue中的消息.那麼,sender發送消息到SampleQ1,router接收SampleQ1的消息後分别發送到SampleQ1_A,SampleQ1_B,SampleQ1_C,handler A,B,C分别從隊列SampleQ1_A,SampleQ1_B,SampleQ1_C中接收消息.
3.用JMS來解決什麼問題?
一提起JMS可以做什麼,第一想到的就是異步處理.面試的時候問JMS可以做什麼?大多數的回答是:用JMS來異步發送郵件!其實,還可以用JMS來解決很多複雜的問題,例如分布,并發,系統解耦,負載均衡,熱部署,觸發器等等,這些複雜的問題因為引入了JMS而變的更加簡單.下面簡單介紹下解決分布,并發問題的場景.
3.1 用JMS來解決并發問題
queue的概念大家都很清楚了,那就是queue裡的一條消息隻會被一個消息接收者處理.基于這個概念,我們可以在系統中對并發要求很嚴格的子產品中引入JMS的使用.例如,系統的送積分,一般這個子產品是用一個定時器,例如quartz,每天定期查詢資料庫,如果發現有滿足條件的記錄,那麼就把積分送給會員.如果同時有多個quartz在運作,那麼必須嚴格控制防止并發的對同一條記錄送多次積分.解決這個問題有很多方法,可以通過業務的設計,系統的部署,資料庫的設計,事務的控制等方法來實作,在這裡提一個用JMS來解決問題的方法:在插入記錄的同時發送一個queue的消息.這樣即使有多個送積分的MDB執行個體在運作,也隻會被一個執行個體處理.
3.2用JMS來解決分布的問題
解決分布有兩種類型,第一種是指消息是集中的,但消息的處理是分布的.例如,系統可能會被分為前台與背景,這兩個系統是部署在不同的網段裡的.那麼怎麼把前台發生的業務通知背景系統呢?當然,可以通過一個類似定時器的玩意定期去資料庫查詢.但這種方式要麼就是浪費系統資源,可能在定期查詢中80%的時間都是在做無用功,要麼就是業務請求沒有被及時處理.,因為定期的時間總是有一個時間間隔的.用JMS來處理這個問題會怎麼樣呢?前台系統在處理完業務請求後的同時發送一個消息到queue中,背景系統的消息接收者接收到消息後立即處理.這裡消息的處理也可能有一定的延期,但這主要取決于消息伺服器的硬體能力,網絡帶寬,消息接收者的處理速度等.
第二中是指消息也是分布的.很多消息中間件都提供了消息路由的功能,即消息發送到一個消息伺服器後,這個消息伺服器根據定義的規則再把這條消息路由轉發到其它的消息伺服器.例如,可能在北京的一個資料中心部署了資料采集系統,采集到資料後以消息的方式發送到消息伺服器,然後消息伺服器再把這條消息路由到上海的資料中心,再由上海資料中心部署的資料處理系統來處理這條消息.
4.JMS與事務,一定要用JTA事務嗎
很多人接觸到JTA事務都是從用JMS開始的,畢竟同時要連多個資料庫的的系統并不是那麼的多!而要用JTA事務的話,就得要在笨重的應用伺服器中部署.(當然,你也可以用類似atomikos的輕量級JTA事務管理器),更重要的是,并不是事務本身的技術有多複雜,而是事務的界定,這種事務的界定有時都不是程式員能決定的事情,需要在設計的時候就要考慮清楚,甚至可能還需要業務人員的參與.(題外話:經常問面試的,用spring的aop做什麼?大多數答:用來管理事務!事務要真這麼簡單該多好啊!)
我也不是要反對用JTA事務,而是要說明一下,用JMS,并非一定要用JTA事務.這可以分為三種場景:
一,必須用JTA事務,這種情況下,一般消息的接收者隻從消息本身獲得資料并進行處理.是以必須要保證消息的發送與所依賴的業務保持一緻.
二.不需要用事務,這種情況下, 要麼是業務無關緊要,例如用JMS來記錄日志.要麼是發送的消息僅僅是一個作為後續業務處理的一個觸發器!消息接收者僅僅是從消息中獲得一個id,然後根據這個id去查詢所依賴的其它資料進行業務處理.即使消息丢失也沒關系,可以通過其它的機制來補償.
三.消息丢失可以通過補償事務來完成.這個依賴與具體實作,就不詳細說了.
5.處理消息永遠比發送消息慢!
要保證你的JMS應用穩定的運作,那麼你必須在開發,部署的時候時刻重視這個問題.
首先,需要把發送消息的連接配接池與接收消息的連接配接池分開.以避免接收消息的連接配接過過而導緻發送消息的應用拿不到連接配接.
在一個連接配接上并發的處理消息,而不是連接配接打開,處理一個消息,馬上關閉連接配接.
合理的設定消息的過期時間,否則消息日積月累,最終超出queue的size
對于非關鍵業務的消息處理,可以采用異步處理的方法:接收到消息後并不是立刻處理,而是放到一個任務池或者線程池中處理.如果消息處理失敗,則把消息重新發送回隊列中.