一步一步理解Java企業級應用的可擴展性

老實說,「可擴展性」是個全面且詳盡的話題,並且每每得不到充分理解。人們一般認爲可擴展性等同於高可用性,筆者見過編程新手和架構師「老手」都建議將集羣做爲可擴展性和高可用性的解決方案。建議確實沒錯,但問題是,人們一般是經過互聯網搜索,而非實際理解應用自己的狀況來實現集羣。html

筆者並未自稱「專家」,只想經過這篇文章介紹一些有關 Java 企業級應用的通常擴展策略。java

問題

可擴展性並不是 Java 企業級平臺規範內的標準組件。相關技術一般因供應商(應用服務器)而異,而且每每須要使用不止一款產品(應用服務器自己除外)。正因如此,設計可擴展的 Java 企業級應用纔會有些棘手,要完成任務,每每不只沒有能夠參照的實例,並且要求咱們必須不折不扣地理解應用。web

擴展類型

筆者確信大家不是第一次看到這些內容。擴展通常分爲兩大類:縱向擴展,和橫向擴展。算法

擴展的第一個天然階段是縱向擴展。數據庫

  • 縱向擴展:包括給服務器增長更多資源,例如內存 (RAM)、磁盤空間、處理器等。這在某些方案中具有實用價值,但通過特定時間點後就會發現,這種擴展費用高昂,不如藉助橫向擴展。編程

  • 橫向擴展:在這個過程當中會增長更多機器或額外的服務器實例/節點,這也叫作集羣(Clustering),由於全部服務器是做爲一個集體或集羣一塊兒運行的。緩存

高可用性不等於可擴展性

系統高度可用(擁有多個服務器節點以方便故障轉移),並不表示系統可擴展。高可用性只是意味着,若是當前處理節點崩潰,請求會傳遞或轉移到集羣中的另外一個節點,以便從開始處繼續。可擴展性則是經過增長可用資源(內存、處理器等)而提高系統特定性能(例如用戶數量、吞吐量、響應時間)的能力,即便將失敗請求傳遞到另外一個節點,也沒法保證應用會在這種場景中正確運行(緣由咱們會在下面揭曉)。服務器

下面咱們來了解一些關於可擴展性的觀點和相關討論。session

讓橫向擴展的集羣達到負載均衡

假設您已經縱向擴展至最大容量,如今又用多個節點造成集羣,將系統進行了橫向擴展。接下來您要作的多是在集羣基礎架構前放置一臺負載均衡器,讓負載分散在集羣各部分之間(若是要詳細瞭解負載均衡,你們能夠參考其餘方面的資料,在這裏咱們重點仍是說擴展問題)。架構

輸入圖片說明

應用有狀態仍是無狀態?

如今你已經橫向擴展了,這就夠了嗎?若是你的應用無狀態,即應用邏輯在處理請求時不依靠現有服務器狀態,則橫向擴展已經足夠。

但若是應用具備 HTTP 會話對象、有狀態 EJB、會話域 bean (CDI、JSF) 等組件時,又會怎樣?這取決於具體用戶(具體來講,即調用線程),存儲特定狀態並依靠當前顯示的狀態來執行請求(例如,HTTP 會話對象可能會存儲用戶的身份驗證狀態、購物車信息等)。

在橫向擴展或集羣式應用中,節點的任何集羣均可能爲後續請求提供服務。若是首個請求的 JVM 實例處的狀態數據沒有被接收,其餘節點會如何處理請求?

輸入圖片說明

輸入圖片說明

會話保持

會話保持配置可在負載均衡器層面上完成,確保來自特定用戶/終端用戶的請求始終被轉發到同一個實例/應用服務器節點,即維持服務器親和力。這樣,咱們就緩解了所需狀態沒法顯示的問題。但這裏有個陷阱 – 若是節點崩潰怎麼辦?狀態會被破壞,用戶會被轉至服務器請求處理所依賴的、但不具有現有狀態的實例。

輸入圖片說明

輸入圖片說明

集羣複製

爲解決上述問題,您可對應用服務器集羣機制進行配置,以支持有狀態組件的複製,藉此可確保 HTTP 會話數據(和其餘有狀態對象)顯示在全部服務器實例上。如此一來,終端用戶請求即可轉至任何服務器節點,即便某個服務器實例崩潰或不可用,集羣中的其餘任何節點都可以處理請求。如今您的集羣就不是通常集羣了,而是複製集羣。

輸入圖片說明

集羣複製特定於 Java 企業級容器/應用服務器,最好查閱相關文檔,瞭解如何複製集羣。通常而言,大多數應用服務都支持 Java 企業級組件(若有狀態和無狀態的 EJB、HTTP 會話、JMS 隊列等)集羣。

然而這形成了另外一個問題 – 應用服務器中的每個節點都處理會話數據,致使 JVM 堆內存愈來愈多,所以垃圾回收也愈來愈頻繁,另外,複製集羣時還會消耗必定的處理能力。

有狀態組件的外部存儲

在另外一層存儲會話數據和有狀態的對象,這能夠藉助 RDBMS 實現,大多數應用服務器自己就支持這一功能。

輸入圖片說明

你可能已經注意到了,咱們已經將存儲從內存層轉移到持久層 - 一天工做結束時,你可能會遇到由數據庫致使的擴展問題。不是說這必定會發生,但數據庫確實可能由於應用而過載,然後逐漸延時(例如在故障轉移時)。設想一下,從數據庫中再現整個用戶會話狀態以便用在另外一個集羣實例中,不只耗費大量時間,還會影響峯值負載下的終端用戶體驗。

最後的邊界:分佈式內存中緩存

這是最後的邊界,至少在我看來如此,由於它把咱們帶回了內存方法。沒有比這更好的辦法了!Oracle Coherence、Hazelcast 這類產品或其餘任何分佈式緩存/內存網格產品可用於清理有狀態的狀態存儲和複製/分佈 - 這就是緩存層。好的一面是這些產品大多默認支持 HTTP 會話存儲。

輸入圖片說明

這種結構設置意味着,應用服務器的重啓不會影響現有用戶會話 - 給系統打補丁而不形成宕機和終端用戶斷電(雖然並不像聽上去那麼容易,但顯然是個辦法!),這始終是好事。總的來講,其理念是:應用層和 web 會話緩存層可獨立運行和擴展,彼此不受干擾。

分佈式不等於重複式

這兩個詞之間存在巨大差別,就緩存層而言,理解其中的差別是極爲關鍵的。二者各有長短:

  • 分佈式:緩存共享數據的各個部分,即數據集被分在各緩存集羣節點之間(利用與產品特定的算法)。

  • 重複式:全部緩存節點都擁有全部數據,即每一個緩存服務器都包含整個數據集的一份複本。

延伸閱讀(主要關於 Weblogic)

結束語

  • 高度可擴展性可能不是全部 Java 企業級應用的必要條件。但若是你打算構建互聯網/面向大衆的應用,將高可擴展性歸入設計因素顯然很是實用。

  • 對於但願充分利用自動靈活性(經濟可行!)和高可用性等雲平臺(主要是PaaS)特色的應用而言,可擴展的設計是必要的。

  • 不難發現,有狀態的應用一般更難以擴展。徹底「無狀態」或許沒法實現,但咱們應當朝這方面努力。

你用哪些技巧和方法來擴展 Java 企業級應用,快來和你們分享吧。

(編譯自:https://dzone.com/articles/the-basics-of-scaling-java-ee-applications)

相關文章
相關標籤/搜索