摘要:本文主要介紹如何了解 java 應用的擴充方式以及不同類型的擴充技術和具體技巧,介紹一些有關 java 企業級應用的一般擴充政策。
老實說,“可擴充性”是個全面且詳盡的話題,而且往往得不到充分了解。人們通常認為可擴充性等同于高可用性,筆者見過程式設計新手和架構師“老手”都建議将叢集作為可擴充性和高可用性的解決方案。建議确實沒錯,但問題是,人們通常是通過網際網路搜尋,而非實際了解應用本身的情況來實作叢集。
筆者并未自稱“專家”,隻想通過這篇文章介紹一些有關 java 企業級應用的一般擴充政策。
可擴充性并非 java 企業級平台規範内的标準元件。相關技術通常因供應商(應用伺服器)而異,并且往往需要使用不止一款産品(應用伺服器本身除外)。正因如此,設計可擴充的 java 企業級應用才會有些棘手,要完成任務,往往不僅沒有可以參照的執行個體,而且要求我們必須徹徹底底地了解應用。
筆者确信你們不是第一次看到這些内容。擴充一般分為兩大類:縱向擴充,和橫向擴充。
擴充的第一個自然階段是縱向擴充。
縱向擴充:包括給伺服器增加更多資源,例如記憶體 (ram)、磁盤空間、處理器等。這在某些方案中具備實用價值,但經過特定時間點後就會發現,這種擴充費用高昂,不如借助橫向擴充。
橫向擴充:在這個過程中會增加更多機器或額外的伺服器執行個體/節點,這也叫做叢集(clustering),因為所有伺服器是作為一個集體或叢集一起運作的。
系統高度可用(擁有多個伺服器節點以友善故障轉移),并不表示系統可擴充。高可用性隻是意味着,如果目前處理節點崩潰,請求會傳遞或轉移到叢集中的另一個節點,以便從開始處繼續。可擴充性則是通過增加可用資源(記憶體、處理器等)而提升系統特定性能(例如使用者數量、吞吐量、響應時間)的能力,即使将失敗請求傳遞到另一個節點,也無法保證應用會在這種場景中正确運作(原因我們會在下面揭曉)。
下面我們來了解一些關于可擴充性的觀點和相關讨論。
假設您已經縱向擴充至最大容量,現在又用多個節點形成叢集,将系統進行了橫向擴充。接下來您要做的可能是在叢集基礎架構前放置一台負載均衡器,讓負載分散在叢集各部分之間(如果要詳細了解負載均衡,大家可以參考其他方面的資料,在這裡我們重點還是說擴充問題)。

現在你已經橫向擴充了,這就夠了嗎?如果你的應用無狀态,即應用邏輯在處理請求時不依靠現有伺服器狀态,則橫向擴充已經足夠。
但如果應用具有 http 會話對象、有狀态 ejb、會話域 bean (cdi、jsf) 等元件時,又會怎樣?這取決于具體客戶(具體來說,即調用線程),存儲特定狀态并依靠目前顯示的狀态來執行請求(例如,http 會話對象可能會存儲使用者的身份驗證狀态、購物車資訊等)。
在橫向擴充或叢集式應用中,節點的任何叢集都可能為後續請求提供服務。如果首個請求的 jvm 執行個體處的狀态資料沒有被接收,其他節點會如何處理請求?
會話保持配置可在負載均衡器層面上完成,確定來自特定客戶/終端使用者的請求始終被轉發到同一個執行個體/應用伺服器節點,即維持伺服器親和力。這樣,我們就緩解了所需狀态無法顯示的問題。但這裡有個陷阱 – 如果節點崩潰怎麼辦?狀态會被破壞,使用者會被轉至伺服器請求處理所依賴的、但不具備現有狀态的執行個體。
為解決上述問題,您可對應用伺服器叢集機制進行配置,以支援有狀态元件的複制,借此可確定 http 會話資料(和其他有狀态對象)顯示在所有伺服器執行個體上。如此一來,終端使用者請求便可轉至任何伺服器節點,即使某個伺服器執行個體崩潰或不可用,叢集中的其他任何節點都能夠處理請求。現在您的叢集就不是一般叢集了,而是複制叢集。
叢集複制特定于 java 企業級容器/應用伺服器,最好查閱相關文檔,了解如何複制叢集。一般而言,大多數應用服務都支援 java 企業級元件(如有狀态和無狀态的 ejb、http 會話、jms 隊列等)叢集。
然而這造成了另一個問題 – 應用伺服器中的每一個節點都處理會話資料,導緻 jvm 堆記憶體越來越多,是以垃圾回收也越來越頻繁,另外,複制叢集時還會消耗一定的處理能力。
在另一層存儲會話資料和有狀态的對象,這可以借助 rdbms 實作,大多數應用伺服器本身就支援這一功能。
你可能已經注意到了,我們已經将存儲從記憶體層轉移到持久層 - 一天工作結束時,你可能會遇到由資料庫導緻的擴充問題。不是說這一定會發生,但資料庫确實可能因為應用而過載,而後逐漸延時(例如在故障轉移時)。設想一下,從資料庫中再現整個使用者會話狀态以便用在另一個叢集執行個體中,不僅耗費大量時間,還會影響峰值負載下的終端使用者體驗。
這是最後的邊界,至少在我看來如此,因為它把我們帶回了記憶體方法。沒有比這更好的辦法了!oracle coherence、hazelcast 這類産品或其他任何分布式緩存/記憶體網格産品可用于清理有狀态的狀态存儲和複制/分布 - 這就是緩存層。好的一面是這些産品大多預設支援 http 會話存儲。
這種結構設定意味着,應用伺服器的重新開機不會影響現有使用者會話 - 給系統打更新檔而不造成當機和終端使用者斷電(雖然并不像聽上去那麼容易,但顯然是個辦法!),這始終是好事。總的來說,其理念是:應用層和 web 會話緩存層可獨立運作和擴充,彼此不受幹擾。
這兩個詞之間存在巨大差異,就緩存層而言,了解其中的差異是極為關鍵的。兩者各有長短:
分布式:緩存共享資料的各個部分,即資料集被分在各緩存叢集節點之間(利用與産品特定的算法)。
重複式:所有緩存節點都擁有所有資料,即每個緩存伺服器都包含整個資料集的一份複本。
聚類配置
用于會話持久性的 rdbms 配置
分布式 web 會話複制 – oracle coherence, hazelcast
高可擴充性 – 非常好的資源!
高度可擴充性可能不是所有 java 企業級應用的必要條件。但如果你打算建構網際網路/面向大衆的應用,将高可擴充性納入設計因素顯然非常實用。
對于希望充分利用自動靈活性(經濟可行!)和高可用性等雲平台(主要是paas)特點的應用而言,可擴充的設計是必要的。
不難發現,有狀态的應用通常更難以擴充。完全「無狀态」或許無法實作,但我們應當朝這方面努力。
你用哪些技巧和方法來擴充 java 企業級應用,快來和大家分享吧。
(編譯自:https://dzone.com/articles/the-basics-of-scaling-java-ee-applications)
oneapm 為您提供端到端的 java 應用性能解決方案,我們支援所有常見的 java 架構及應用伺服器,助您快速發現系統瓶頸,定位異常根本原因。分鐘級部署,即刻體驗,java 監控從來沒有如此簡單。想閱讀更多技術文章,請通路 oneapm 官方技術部落格。
本文轉自 oneapm 官方部落格