實現(xiàn)高可用性設(shè)計的奧秘
2024-07-21 02:38:46
供稿:網(wǎng)友
高可用性要求一種合適的基礎(chǔ)結(jié)構(gòu),但是,假如沒有將該基礎(chǔ)結(jié)構(gòu)與J2EE應(yīng)用程序設(shè)計策略進(jìn)行協(xié)調(diào)平衡,性能很可能就會受損。
假如您在高可用性硬件和軟件基礎(chǔ)結(jié)構(gòu)方面投資了一筆數(shù)目可觀的資金,您就必須保證應(yīng)用程序具備高可用性-至少應(yīng)保證J2EE(java 2平臺企業(yè)版)中普遍存在的做法可保證應(yīng)用程序具備高可用性。別忘了,當(dāng)您將數(shù)據(jù)庫和應(yīng)用程序服務(wù)器的群集與群集軟件進(jìn)行組合時,您將會獲得一個相當(dāng)有效的組合。這里的群集軟件包括Oracle9i數(shù)據(jù)庫和Oracle9i應(yīng)用程序服務(wù)器(Oracle9iAS)中的軟件,這些群集軟件既可以將請求自動發(fā)送到可用的服務(wù)器,還可以提供透明的應(yīng)用程序失敗處理。當(dāng)您在J2EE體系結(jié)構(gòu)中增加這類數(shù)目眾多的混合狀態(tài)治理機(jī)制(具有狀態(tài)的Web會話和無狀態(tài)Web會話,具有狀態(tài)的商業(yè)組件和無狀態(tài)商業(yè)組件,自動復(fù)制或備份beans等等)時,您應(yīng)該同時保證具備高可用性。
不幸地是,這種普遍的做法并非完全正確。盡管服務(wù)器與相應(yīng)軟件的群集可以提供高可用性,但是它們卻無法保證高可用性。事實上,某些高可用性功能(如J2EE的狀態(tài)治理機(jī)制)的過度使用就可能會降低應(yīng)用程序的性能,進(jìn)而降低整體的可用性。
即便使用最好的體系結(jié)構(gòu),要真正實現(xiàn)高可用性,其中的要害一步就是從一開始就把高可用性考慮到應(yīng)用程序的設(shè)計中來。因此,您需要從以下幾個方面來非凡關(guān)注應(yīng)用程序的設(shè)計:
· 便捷的狀態(tài)治理
投入一定時間來識別并確定應(yīng)用程序的狀態(tài),然后將狀態(tài)精確映射到各種可用的狀態(tài)治理機(jī)制,避免過度使用某一類型的機(jī)制而導(dǎo)致性能降低。
· 仔細(xì)的層次設(shè)計
分析應(yīng)用程序是否真正需要很多層。層次會增加復(fù)雜性、導(dǎo)致性能劣化并且降低可用性。
· 失敗處理策略
確定并處理那些基礎(chǔ)結(jié)構(gòu)無法自動檢測和修復(fù)的失敗。
假如在應(yīng)用程序設(shè)計的各個步驟中額外多投入一些時間,同時應(yīng)用本文所描述的各種策略,那么應(yīng)用程序的可用性將會顯著增強(qiáng)。
便捷的狀態(tài)治理
要確保實現(xiàn)高可用性,您就需要具備有效的狀態(tài)恢復(fù)機(jī)制。假如一個組件失敗,系統(tǒng)在處理新的請求之前,必須先恢復(fù)該組件所保持的狀態(tài)。
J2EE提供多種便捷的狀態(tài)治理機(jī)制,但是這些機(jī)制經(jīng)常被過度使用,而過度使用這些機(jī)制經(jīng)常帶來一些不幸的結(jié)果。包括 JavaServer Pages (jsp)頁中的會話范圍的JavaBeans、HTTP會話對象servlets以及用于商業(yè)組件的有狀態(tài)會話bean等在內(nèi)的這些狀態(tài)治理機(jī)制,可以識別并確定失敗時必須保持的狀態(tài)。所有這些機(jī)制都使用存儲在內(nèi)存中的Java 對象來表示應(yīng)用程序的狀態(tài)。在HTTP會話過程中以Java形式來保存這些對象可以為編程人員提供必要的便捷,但是卻很輕易會忘記進(jìn)行相關(guān)備份所需的代價。
應(yīng)用程序服務(wù)器(如Oracle9iAS)通過在數(shù)據(jù)庫、文件或者備份服務(wù)器的有效內(nèi)存中對這些存儲在內(nèi)存中的Java 對象的副本進(jìn)行備份,就可以在必要時積極采取相應(yīng)的恢復(fù)措施。對Java 對象進(jìn)行備份時經(jīng)常要求使用代價昂貴的 Java 串行操作。假如將許多大型的Java 對象用于狀態(tài)治理(這是一種常見的應(yīng)用程序設(shè)計策略),就會使J2EE 狀態(tài)治理機(jī)制負(fù)載過重。因此,應(yīng)用程序的性能將會劣化到極低的級別,這會讓人無法接受。當(dāng)然,這也與高可用性的目標(biāo)背道而馳(我們認(rèn)為一個速度極慢的應(yīng)用程序不具有高可用性)。
作為這種 J2EE 標(biāo)準(zhǔn)方法的另一可選方法,您應(yīng)該關(guān)注多數(shù)大型 Web 站點(這些站點同時又具備高可用性)所使用的模型。在該模型中,應(yīng)用程序的狀態(tài)主要保存在持久穩(wěn)固的存儲器(如數(shù)據(jù)庫)中,同時在內(nèi)存中進(jìn)行了緩存處理以便改善響應(yīng)時間(這與J2EE模型不同,J2EE模型中一開始就將狀態(tài)存儲在內(nèi)存中,然后由應(yīng)用程序服務(wù)器進(jìn)行備份)。這里,最要害的不同之處就是:對于大型的Web站點模型,應(yīng)用程序的寫進(jìn)程已投入一定時間來識別并確定應(yīng)用程序狀態(tài)的要害片斷,同時還設(shè)計了一種有效機(jī)制(緩存),用于從應(yīng)用程序?qū)彺孢M(jìn)行訪問。因而,中間層組件的失敗并不需要恢復(fù)中間層的狀態(tài),而僅需重新啟動緩存,這是因為需要時可以從后端再次導(dǎo)入相關(guān)的狀態(tài)。
一些大型的 Web站點更進(jìn)一步,它們對應(yīng)用程序的狀態(tài)進(jìn)行分離,然后將其分別存儲在穩(wěn)固持久的后端存儲器和客戶端瀏覽器中。一些狀態(tài)以cookie的形式保存在瀏覽器中,這樣就隱藏了 Html 形式的元素或 URL 參數(shù)。
這種技術(shù)不僅提供了更高的可用性,而且還提高了應(yīng)用程序的整體品質(zhì)。假如瀏覽器處于未連接狀態(tài),這種技術(shù)答應(yīng)終端用戶很輕易地重新開始連接會話。
現(xiàn)在很清楚了:J2EE應(yīng)用程序開發(fā)人員需要預(yù)先投入一定時間來分析應(yīng)用程序狀態(tài),然后根據(jù)特定策略將其映射到適當(dāng)?shù)目苫謴?fù)存儲器中。
接下來的一個問題就是如何確定哪些狀態(tài)應(yīng)該映射到后端數(shù)據(jù)庫而哪些狀態(tài)應(yīng)該映射到瀏覽器。幸運地是,這個問題的答案通常是相當(dāng)簡單直接的,它取決于所要映射的狀態(tài)信息的類型。
應(yīng)用程序的狀態(tài)通常可分為下面三種類型:
· 頁狀態(tài):此種類型的狀態(tài)在一頁中是有效的,例如,搜索查詢返回的一系列結(jié)果的開始索引。
· 會話狀態(tài):此種類型的狀態(tài)通常在一次會話的整個過程中是有效的,例如,運行應(yīng)用程序的末端用戶的身份。
· 持久狀態(tài):此種類型的狀態(tài)的生命周期為端用戶會話,例如,購物報表或開支報告的內(nèi)容。在常見的典型應(yīng)用程序中,大多數(shù)應(yīng)用程序狀態(tài)都是這種持久狀態(tài)類型的。
一旦您將應(yīng)用程序的狀態(tài)劃分為上述三種類型,您就可以將狀態(tài)映射到適當(dāng)?shù)某钟衅髦小U埬谀X中牢記:您的目標(biāo)之一就是通過一種J2EE 機(jī)制使在中間層內(nèi)存器中保存的狀態(tài)盡可能少。
映射頁狀態(tài)。處理頁狀態(tài)的最佳方式就是將其存儲隱藏形式的元素或URL參數(shù)中,這些元素或參數(shù)嵌套在該頁中。因為此狀態(tài)需要在該頁面對瀏覽器可用的整個期間中始終保持,因而它并不會產(chǎn)生恢復(fù)問題。諸如 Oracle9iAS 的J2EE MVC 框架之類的模型查看控制器(Model View Controller)框架,使用隱藏形式的元素將頁面流信息保存在每一個Web頁面中。
映射會話狀態(tài)。您可以保存一些會話狀態(tài),如用戶身份和in cookies;身份驗證系統(tǒng)(如Oracle9iAS Single Sign-On)就使用此種方法。然而,您需要在中間層內(nèi)存中保存會話狀態(tài)的其他一些部分。假如cookie 的數(shù)目過多或者內(nèi)容過大,就無法進(jìn)行高效操作。在這些情況下,您就應(yīng)該使用之前已提及的一種 J2EE狀態(tài)治理機(jī)制。把使用這些機(jī)制的情形限制到這些場合有助于保持較高的可用性。
映射持久狀態(tài)。您應(yīng)該非常明確地將持久狀態(tài)保存在后端數(shù)據(jù)庫中。您可以在中間層內(nèi)存中對其進(jìn)行緩存以便提高效率(Oracle9iAS 中的非凡JSP 標(biāo)記庫可以在 Web 緩存和 J2EE 容器中對頁片斷進(jìn)行緩存)。然而,您可能希望數(shù)據(jù)庫成為真實數(shù)據(jù)的來源以便中間層失敗時避免出現(xiàn)恢復(fù)問題。請注重:強(qiáng)烈建議顯式標(biāo)識狀態(tài)并且通過正規(guī)的數(shù)據(jù)庫訪問機(jī)制(如實體 beans或 Java Database Connectivity (JDBC))將狀態(tài)顯式存儲在數(shù)據(jù)庫中.
通過此種方式來映射這三種類型的狀態(tài),就可以創(chuàng)建狀態(tài)安全的應(yīng)用程序。狀態(tài)安全的應(yīng)用程序可以避免無狀態(tài)應(yīng)用程序的局限性,而可用性并不差。
仔細(xì)的層次設(shè)計
層次設(shè)計是獲得可用性的另一領(lǐng)域。在J2EE中,通常有這樣一個共識:應(yīng)用程序應(yīng)該由多種層次組成。然而,假如您使用過多的層次,不僅不會增強(qiáng)可用性,反而還可能會阻礙了可用性。
使用多種層次的原因是相當(dāng)明顯的。首先,仔細(xì)的多層設(shè)計有助于隔離各種故障,例如,商業(yè)組件雖然失敗但并不會影響Web前端的可用性,這一點可持續(xù)至前端需要使用該組件為止。而且,在一些情況下,每一層中運行更少的邏輯可以使每一層變得更健壯。
但是,使層的數(shù)目盡可能保持最低具有非常顯著的優(yōu)勢。這使應(yīng)用程序可以更輕易地進(jìn)行治理和監(jiān)控,為那些負(fù)責(zé)實現(xiàn)高可用性的操作組提供巨大的幫助。而且,假如一個應(yīng)用程序具有層數(shù)不多,通常就更易于設(shè)計,因而整體上就更加健壯。最后,設(shè)計一個層數(shù)不多的應(yīng)用程序(例如,使用EnterPRise JavaBeans (EJB) 2.0 本地接口)可以獲得更優(yōu)的性能,這也同時會大大增強(qiáng)可用性。
假如您將目標(biāo)鎖定為高可用性,但又無法確定選用的層數(shù)應(yīng)該多一些還是少一些,請您相信,使用更少的層數(shù),出錯的可能性就會更低。
失敗處理策略
與狀態(tài)治理和層次設(shè)計一樣,我們在失敗處理方面過分依靠于常規(guī)的方法和高可用性基礎(chǔ)結(jié)構(gòu)的實際能力。因為現(xiàn)在的應(yīng)用程序服務(wù)器能夠自動檢測和修復(fù)許多組件失敗,我們就不必投入太多的精力,以便我們的應(yīng)用程序能夠處理那些不能自動修復(fù)的失敗。但是我們并沒有意識到:真正的高可用性則要求應(yīng)用程序和應(yīng)用程序服務(wù)器之間能夠相互協(xié)作。
雙重事務(wù)是一種常見的失敗類型,這種類型的失敗很難做到自動修復(fù)。終端用戶兩次單擊Bill Me 按鈕就是該類失敗的一個示例。由于雙重事務(wù)的產(chǎn)生因素在于不同層之間的通信失敗,所以修復(fù)就可能會涉及一些位于應(yīng)用程序服務(wù)器內(nèi)嵌的修復(fù)機(jī)制范圍之外的問題。請這樣一種簡單的情形,一個JSP 頁面通過JDBC 提交事務(wù),但是卻收到了網(wǎng)絡(luò)通信錯誤。那么應(yīng)用程序服務(wù)器如何才能確定在通信失敗之前該事務(wù)是否已經(jīng)提交?應(yīng)用程序服務(wù)器是否應(yīng)該自動再重復(fù)先前的操作?這類問題在層次緊密的體系結(jié)構(gòu)中更加難以解決,其中JSP頁調(diào)用在多個分布式容器中運行的EJB。通信錯誤表示bean 調(diào)用根本就沒有執(zhí)行完畢,在這種情況下再次進(jìn)行調(diào)用就非常合適。可是,相同的錯誤也可能是起因于這樣一種情況,調(diào)用本身已取得成功但是