使用WebSphere構建J2EE應用程序
集群拓撲有兩種類型,垂直集群或水平集群。垂直集群在同一節(jié)點或物理計算機上具有多個集群成員。水平集群在計算單元中的很多計算機的多個節(jié)點上都具有集群成員。本文將討論如圖 1 所示的水平集群拓撲。

我們將討論在設計基于 Web 的應用程序時的三個注意事項:
實現(xiàn)應用程序文件同步
在企業(yè)應用程序的生命周期中,通??梢酝ㄟ^應用修復程序、添加新的 Web 內(nèi)容或更新應用程序行為來對已部署的應用程序進行更新。一般來說,應用程序提供了允許用戶上傳在服務器端更改或創(chuàng)建的文件的用戶界面。
將下面的場景作為一個示例:用戶希望更新 Web 站點徽標圖像文件,并且將原始文件作為 .war 文件應用程序的一部分進行存檔。該應用程序提供了相關的功能和用戶界面,以便用戶完成這項任務。然后,用戶選擇一個新的圖像作為 Web 站點的新徽標,并且上傳該文件。系統(tǒng)使用新的文件替換原始的文件,并且當用戶再次訪問他的 Web 站點時,可以看到相應的更改。在單節(jié)點環(huán)境的應用服務器中,所有這些工作都可以順利進行。然而,在集群環(huán)境中卻存在一些問題。
在集群環(huán)境中,如圖 2 所示,WebSphere Application Network Deployment 服務器中的 Deployment Manager 將接收到用戶的上傳請求,然后該請求被發(fā)送到 Node A。Node A 將執(zhí)行相應的業(yè)務邏輯并使用本地文件系統(tǒng)中的新圖像文件替換原始圖像文件。然而該集群中其他的成員并不清楚這項更改,其本地副本并沒有得到更新。因此,該集群中各個成員之間的這個圖像文件就出現(xiàn)了不一致的情況。如果 Node A 因為致命錯誤而停機,而 Node B 接收到了該請求,那么仍將使用原始的 Web 站點徽標??瓷先タ蛻羲坪鮼G失了他所做的更改。

這意味著,當應用程序運行于 WebSphere Application Server 時,需要在集群成員之間同步配置文件、二進制文件和資源文件。有一種機制可以處理上述問題。解決方案是使用共享的文件系統(tǒng)(例如,NFS)或共享的數(shù)據(jù)庫。在這個解決方案中,所有經(jīng)過更改或更新的文件都位于同一個共享文件系統(tǒng)或同一數(shù)據(jù)庫中。對于共享的文件系統(tǒng),所有應用程序都使用相同的位置,因此對于這些應用程序來說,任何文件更改都是可見的。對于共享的數(shù)據(jù)庫,應用程序可以從數(shù)據(jù)庫中獲得相應的更改。
上述解決方案的缺點包括:
- 共享的文件系統(tǒng)和數(shù)據(jù)庫導致一個新的單點故障。
- 它增加了編程和配置工作的復雜性。
- 它引入了一個新的性能瓶頸。
另一個解決方案是使用細粒度 WebSphere Application Server 應用程序管理 API,在集群的各個成員之間實現(xiàn)文件同步。WebSphere 6.0 中提供了這一特性。WebSphere 6.0 中包含許多改進,從而使得應用程序的部署更加容易并且更加高效。有關詳細信息,請參見 WebSphere Application Server 信息中心
WebSphere 6.0 還提供了靈活的應用程序文件管理。它允許應用程序通過以下方式進行更新:
- 替換整個應用程序(例如,整個 .ear 文件)。
- 替換、添加或刪除應用程序中的單個模塊(例如,.war、EJB.jar 或 .rar 文件)。
- 替換、添加或刪除單個文件。
- 替換、添加或刪除多個文件。
在對集群中的某個成員上的應用程序文件進行更新之后,將使用另一個新的特性 Rollout Update 對集群中各個成員的文件進行同步。它通過以下方式對應用程序進行更新:
- 保存更新的應用程序配置。
- 停止給定節(jié)點上所有的集群成員。
- 通過同步配置和重新啟動該節(jié)點上停止的集群成員來更新該節(jié)點上的應用程序。
讓我們回到前面關于 Web 站點徽標更新的示例。在這個場景中,徽標的更新和同步對于用戶來說應該是透明的,無需 WebSphere 管理員進行人工干預。這就意味著,應用程序必須控制應用程序的更新,如替換存檔于 ear 文件中的原始文件,并在集群的成員之間執(zhí)行文件同步。您可以通過調用 WebSphere 提供的 Java Management Extensions (JMX) 接口來完成這項任務。JMX 是一項 Java 應用程序資源管理標準。有關 JMX 的詳細信息,請參見 JMX Web 站點

應用程序在接收到用戶上傳的文件之后,它將調用 File Updater 以構造增量 EAR 文件。這個增量 EAR 文件是一個存檔文件,它具有與完整的應用程序 ear 文件相同的結構。增量 EAR 文件和完整的應用程序 EAR 文件之間的區(qū)別在于,該增量 EAR 文件僅包含要進行更新的文件。File Updater 將構建這個增量 EAR。它可以是封裝了增量 EAR 生成邏輯的簡單 Java 類,或者是添加了驗證邏輯和生成文件的相關復雜組件。
序列化會話對象
使用集群方式的應用程序可以提高系統(tǒng)的可靠性和可用性。然而,這也引入了一些挑戰(zhàn),如會話管理。HTTP 會話是包括用戶特定信息的集合。從用戶開始訪問到用戶最后一次訪問結束的這段時間內(nèi),由容器對會話進行維護。會話由一系列的會話屬性組成。事實上,這些屬性都是由系統(tǒng)或開發(fā)人員創(chuàng)建的 Java 對象。
在集群環(huán)境中,開發(fā)人員必須清楚,HTTP 會話可能運行于多個 JVM 中。這些會話屬性應該在每個 JVM 中保持一致。否則,當應用程序運行于不同的節(jié)點時,相同的輸入可能產(chǎn)生不同的結果,這是因為與用戶相關的數(shù)據(jù)在這兩個節(jié)點中不一致。
WebSphere 為集群方式的應用程序提供了實時的、完全一致的數(shù)據(jù)共享。然而,前提是必須對所有共享的屬性進行序列化和反序列化。當您將 Java 對象放入到會話中并希望在所有的節(jié)點之間共享該對象時,需要將這個 Java 對象聲明為一個 serializable 接口。下面的代碼顯示了在將對象放入到會話屬性時進行的驗證工作。
- public class MySession{
- public static void addObjectToSession(HttpServletRequest req, String key, Object value) {
- HttpSession session = req.getSession(true);
- if(value instanceof Serializable)
- session.setAttribute(key, value);
- else
- throw new NonSerializationException ();
- }
- public MySession() {
- }
- }
在上面的示例中,您創(chuàng)建了一個名為 MySession 的新類,用來將對象添加到會話中。您可以通過調用 addObjectToSession() 方法來添加它。首先應該檢查該對象是否實現(xiàn)了 serializable 接口。如果已經(jīng)實現(xiàn),可以隨后將這個對象添加到當前的 Http 會話中。否則,將會出現(xiàn) NonSerializationException。有些時候,在運行于另一個 JVM 中時,會話屬性中包含的信息無關緊要,如文件的絕對目錄。在這種情況下,通過將其聲明為瞬態(tài)屬性可以使得這些字段不使用集群方式。
使用動態(tài)緩存
如上所述,將應用程序數(shù)據(jù)保存在中央數(shù)據(jù)庫中可以確保在集群環(huán)境中寫入和一致地讀取數(shù)據(jù)。這種解決方案的缺點是,數(shù)據(jù)庫服務器引入了新的單點故障 (SPOF),并且不適合那些需要高性能的應用程序。另一種解決方案是使用 WebSphere Dynamic Cache 和 Data Replication Service (DRS)。您可以在基于內(nèi)存的對象緩存的方式下,通過共享整個集群中某些服務器上的對象,來實現(xiàn)這個解決方案。圖 4 顯示了帶 Data Replication Service 的 WebSphere Dynamic Cache 的體系結構。

WebSphere Dynamic Cache 是面向 J2EE 體系結構和緩存對象的解決方案。表示層中 Web 服務、Servlet 和 JSP 的輸出、WebSphere 命令類以及 Java 對象都可以使用應用程序編程接口 (API) 進行緩存,或者聲明一些緩存策略并將其添加到應用程序中。
Data Replication Service (DRS) 是用于復制數(shù)據(jù)的 WebSphere Application Server 內(nèi)部組件。DRS 使得集群中的各個服務器都可以使用會話管理、動態(tài)緩存和無狀態(tài)會話 Bean 的數(shù)據(jù)。動態(tài)緩存可以利用應用服務器中的 DRS 在集群的各個服務器中復制緩存的數(shù)據(jù)。在集群范圍內(nèi)傳輸數(shù)據(jù)失效通知,以保持數(shù)據(jù)的一致性和有效性。圖 5 顯示了如何使用動態(tài)緩存和 DRS 在集群中共享應用程序數(shù)據(jù)。

首先,應用程序運行于 Server One,并通過調用 DistributedMap API 將 Object A 放入其本地緩存中。通過合適的配置,DRS 可以在整個集群范圍內(nèi)復制緩存的對象并保持緩存數(shù)據(jù)的一致性。因此,將 Object A 復制到 Server Two 的本地緩存。當應用程序運行于 Server Two(假如 Server One 遇到問題或根據(jù)負載平衡策略將事務提交到 Server Two)時,應用程序可以從 Server Two 的本地緩存中獲得 Server One 的 Object A。
WebSphere Application Server 通過使用緩存實例存儲和管理緩存的 Java 對象。緩存實例還可以用于對相關的對象進行邏輯分組。特定實例的緩存中存儲的對象不會受到其他緩存實例的影響。如上所述,DistributedMap 公共接口使得應用程序可以直接訪問緩存實例。
應用程序可以存儲和檢索任何實現(xiàn)了 java.util.Map 接口的對象。您所緩存的任何其他 Java 對象都必須實現(xiàn) java.io.Externalizable 或 java.io.Serializable 接口。集群中的服務器可以通過使用其 JNDI 名稱來訪問緩存實例。這些服務器必須位于同一個復制域。下面的代碼示例顯示了應用程序如何通過其 JNDI 名稱查找緩存實例,將對象放入緩存實例中,并稍后對其進行檢索。
- Import javax.naming.InitialContext;
- Import com.ibm.websphere.cache.DistributedMap; ... InitialContext context=new InitialContext();
- DistributedMap map=(DistributedMap)context.lookup("cache/example_cache_instance");
- map.put("cache_id", yourJavaObject);
- YourJavaObject obj=(YouJavaObject)map.get("cache_id");
結束語
本文討論了設計運行于 WebSphere 集群環(huán)境的應用程序時需要考慮的三個方面。存儲于文件系統(tǒng)的應用程序數(shù)據(jù)應當在每個集群服務器中保存一致。針對這個需求的解決方案是使用共享的文件系統(tǒng)或共享的數(shù)據(jù)庫。使用細粒度文件更新特性,您可以在集群范圍內(nèi)擁有更靈活的應用程序文件,并避免引入新的單點故障。會話管理是 Web 應用程序的一個重要的考慮事項。您應該考慮進行對象序列化和反序列化,以便在集群范圍內(nèi)進行共享。您可以使用自已定義的類將對象封裝到會話中,然后同時執(zhí)行驗證。您還可以通過使用 WebSphere Dynamic Cache 和 Data Replication Service 實現(xiàn)集群范圍內(nèi)應用程序數(shù)據(jù)的共享,這將顯著地提高應用程序的性能。
【編輯推薦】