Java分佈式

在當今應用架構裏,分佈式和應用與服務之間的通訊都是核心思想。想要從分佈式中獲益,你必須緊緊記住幾條基本的原則,不然你可能會很容易遇到性能和擴展性問題。在開發階段這些問題不會常常出現,但當你進行負載測試或產品化的時候,你可能會意識到你選擇的軟件架構不能知足性能和擴展性需求。在這篇文章中,咱們重點關注構建分佈式應用須要記住的一些關鍵點。web

分佈式須要應用之間進行交互。範圍包括從大規模集羣架構上簡單的點到點的交互,到動態的面向服務或基於服務的架構。跨系統邊界的通訊也是提升軟件系統擴展性和可用性的關鍵。現在軟件架構已把分佈式做爲一個核心的必要的概念。Java平臺成爲了核心的角色,由於它的分佈式、有很好的API和產品支持這些特色。應用場景從像SAP這樣在標準軟件上的系統集成,到內部或外部的服務集成。SOA提供這樣的方法,使服務和應用變的靈活和可重用,能夠對新的市場需求很快的作響應。另外,像使用網格計算,虛擬機和多核刀片機的趨勢,致使愈來愈多的集羣應用的出現。這主要是因爲追求高可擴展性和高可用性驅動的。並且雲計算的發展趨勢代表,分佈式平臺未來會更加流行。另外,系統正變得但願能更動態的增長其靈活性。例如,在運行時添加應用節點。這些趨勢也致使了系統結構變得愈來愈複雜。對於開發人員來講,則更難理解產品中服務調用是如何實現的了。這種複雜性和缺少對相應知識的瞭解,很容易致使資源消耗的增長(CPU,內存,網絡)和性能的下降。數據庫

面具後的惡魔編程

現在,遠程技術使分佈式應用的實現更加簡單。底層通訊的細節和服務端和客戶端的基礎結構對開發人員是透明的。如今,若是要把一個Java類暴露爲一個服務,有時只須要簡單的加一個註解到這個類上。服務也能夠被工具生成的代理很容易的訪問。以下圖所示,可是,這僅僅是冰山的一角。緩存

遠程協議的上層架構 圖1.遠程協議的上層架構服務器

遠程堆棧的核心塊是對象的序列化和傳輸的格式化。一般,應用的開發者不須要知道這些。可是,這也是不少性能問題產生的緣由。效率不高的序列化意味着,經過網絡傳輸了不少不須要的數據。複雜對象的顯示和大量的數據,在序列化和反序列化期間,致使CPU和內存的使用會很高。底層的基礎架構和它的配置對應用的性能有很大的影響。在客戶端,主要是鏈接的管理和底層線程模型。在分佈式應用中使用鏈接的指導方針和數據庫的鏈接很像。創建一個鏈接須要必定的時間。但這一樣要看是什麼協議。例如,創建一個HTTPS的鏈接的開銷要大於一個簡單的TCP/IP鏈接。同時,鏈接又是系統很重要的資源。因此,使用鏈接池很重要。正確的配置在這裏也很關鍵,由於錯誤的配置文件給咱們帶來的壞處要多於好處。線程的模型涉及到請求如何被處理。重要的是請求是被同步仍是異步處理。同步通訊阻塞一個進程直到收到相應。在異步通訊中,當收到響應時會調用一個回調。這就容許這個線程被其餘事務使用。在服務端,可用的工做線程數量就是定義的並行處理的最大服務請求數。網絡自己也是分佈式應用的一個重要組件。網絡是比影響性能更加限制其可擴展性的重要的瓶頸資源。這塊一般在開發時會被忽視,由於沒有調用實際的網絡。網絡

遠程調用之美在於... 架構

這有不少能夠選擇,Java提供了很是多的可能性和技術來實現分佈式應用。遠程技術的選擇對應用的架構、性能和擴展性有十分重要的影響。最「老的」的可是幾乎是用的最廣的遠程協議是RMI(以下圖)。異步

RMI架構 圖2.RMI架構編程語言

RMI是J2EE應用的一個標準協議。像它的名稱暗示的同樣,設計時就是爲了調用遠程Java虛擬主機上的對象提供的方法。對象在服務端被暴露出來,這時客戶端就能夠經過代理調用這個對象。一樣的服務端對象被多個線程使用。線程池被RMI基礎設施管理。通訊經過TCP/IP被處理,而且使用JRMP或針對RMI的基於IIOP GIOP(CORBA協議)的協議。應用服務端也提供本身的屬性協議來優化其性能。如服務端的引用須要管理同樣,RMI基礎設施也提供了垃圾回收器來管理引用。這個分佈式垃圾回收器(DGC)自己也使用RMI協議來管理服務器端的對象生命週期。除了客戶端和服務端很強大,RMI還有一些其餘的實現。關於RMI的詳細介紹及應用請參考51CTO以前的文章《用RMI實現基於Java的分佈式計算》。分佈式

RMI只支持同步通訊,缺點上面已經討論過了。另外,不能爲數據驅動的服務提供低級緩存,由於它是基於2進制協議的。開發人員和系統架構可以改變基礎設施的配置參數來優化性能。JMS是J2EE平臺上使用的第二多的協議。以下圖:

JMS架構圖 圖3.JMS架構圖

有別於RMI, JMS是一個異步的協議。通訊是基於隊列的,以便監聽器能夠對消息做出反應。JMS不是一種標準的遠程調用協議,可是它仍然可以知足服務與服務之間的交互。在SOA中很是重要的不少ESB的實現,就採用基於JMS的中間件來進行服務之間的信息傳遞。因爲JMS是異步的,一些典型的同步問題就能夠避免。在不少系統中,高可擴展性的關鍵在於可以很快的釋放資源(像線程)。在不少狀況下,異步處理是惟一合適的方法。JMS提供不少不一樣的傳輸格式。XML是最通用的消息格式,但二進制格式也是可能的。消息結構的設計是應用架構的一個重要部分,由於它能夠直接影響到應用的性能和可擴展性。

基於SOAP的WEB Service(以下圖)和其餘相關的WS-*也在Java 企業應用領域中變得愈來愈重要。

同步和異步SOAP架構 圖4.同步和異步SOAP架構

設計SOAP是爲了替換CORBA,並且一開始就獲得了業界的強烈支持。由於WS-I之間的共同努力,不一樣平臺差很少可以很容易的鏈接起來。SOAP是一種基於XML的RPC協議,因此很容易和浪費帶寬聯繫到一塊兒。

愈來愈多的基於REST的服務開始取代SOAP。Java中的REST服務在JSR 311中有說明,是基於HTTP所支持的基本操做而設計的。可是,REST不是做爲RCP協議,而是面向資源的,爲了訪問和操做(web)資源而設計的。這兩個協議都支持同步通訊。這也是底層HTTP協議所要求的。WS-地址對SOAP協議進行擴展,因此它也容許異步服務的實現。REST最大的優勢是,可以很容易的經過HTTP代理實現緩存。REST依靠使用HTTP底層協議,不管如何都和用的機制。

可能犯的錯

分佈式應用的不少地方均可能出現潛在的問題,如圖所示:

分佈式應用的問題原由 圖5 分佈式應用的問題原由

在客戶端,主要的問題在於糟糕的交互設計-太多的服務調用,或者選擇了錯誤的通訊模式。同步事務運行時間過長很容易致使性能問題。在通訊層,大量的數據和過多的服務調用所產生的高的網絡負載是主要問題。在服務端,不適當的服務接口設計和不合適的序列化策略的使用致使性能和擴展性問題。咱們下面仔細看下這些問題。

分佈式應用的問題原由

通訊協議的正確選擇主要取決於系統的總體架構和底層的需求。若是你工做在有mainframe、Java和.NET組件相互交互的特異環境中,用SOAP是行不通的。在純Java環境中,在JRMP上使用RMI還是性能最優,可擴展性最好的解決方案,你可以得到開箱即用的編程支持。在不少SOA實現中,SOA和基於Web Service的實現同義而語。因此有愈來愈多的使用SOAP做爲RPC協議的純Java應用案例出現,儘管採用這樣的方法一點有點都沒有。調查顯示,和RMI-JRMP相比,常用SOAP仍是有意義的。除了描述過的標準協議,一些其餘的基於XML的和二進制協議也在一些應用中使用。Hessian的性能就不錯。另外,還有一些其餘編程語言的實現。例如使用Spring把POJOs暴露給遠程調用使不改變實現就在不一樣的協議間切換變得相對容易。Spring 支持RMI, HTTP, Hessian, Burlap, JAX-RPC, JAX-WS 和 JMS。

反模式:饒舌的應用

在搭建分佈式應用時,一個核心的原則就是儘可能減小遠程調用。這些意味着數據序列化的開銷,創建鏈接的開銷和附件的網絡負載。另外,CPU,內存和網絡資源的消耗限制了可擴展性。因此,爲遠程應用的接口設計一種方法,來確保必要的服務交互數最小是十分重要的。尤爲是那些起初是在本地搭建的,而後爲了可擴展性緣由遭遇了大量服務交互的應用。這些問題大多會在負載測試或產品化時出現,但當本地開發測試時一點問題都沒有。能夠採用適當的性能管理方法,在開發過程當中分析遠程行爲就能夠避免這些問題。下圖顯示的是一個經過dynaTrace分析一個應用的遠程行爲的例子 。

基於這個分析,接口可以從新建立,應用邏輯可以從新設計來減小遠程調用的次數。可能的方法是,合併幾個方法的邏輯爲一個,或在幾個調用請求周邊的對象處,使用數據容器。特定數據的位置也能夠幫助減小遠程調用,由於在須要的地方數據是可用的。尤爲當讀數據時,使用cache能夠很大程度上提升性能和可擴展性。在軟件設計的早期,服務的分發和可能的通訊在成爲需求或將成爲需求時已經考慮到是很重要的。

反模式:大格式消息

當調用遠程的服務時,這一般意味着數據會在不一樣的協議上傳輸。像XML在SOAP協議上傳輸或二進制數據在RMI協議上傳輸。大多數技術傳輸對象的數據或對象自己。大多數狀況下,序列化的發生是在遠程實現的底層。序列化的開銷和所傳輸對象的大小相對應。在實際狀況下,咱們進行序列化的開銷要佔到98%。怎麼會這樣?一個鑑權服務接口須要一個用戶對象來受權。這個用戶對象不只有用戶名和密碼,還有不少屬性,關聯到其餘用例的數據引用。標準的SOAP序列化要建立幾千字節的數據消息。這些數據要被服務解析並映射到用戶對象結構上,致使大量CPU和內存的消耗。解決方案再明顯不過了。接口要重構,只須要用戶ID和密碼。因此,除了選擇正確的遠程技術,消息內容的設計對構建好的性能和可擴展性的應用很重要。一般正好符合設計的很好通常對象會帶來高性能的回報。

反模式:分佈部署

分佈式的Java企業級應用會致使一個應用分割成多個服務和一些部署單元部署到一些應用服務上。分佈式的有一個組件新的部署包不須要從新部署到其餘組件上。另外一個可能性是,大量使用的服務可以部署到獨立的硬件或被部署屢次。有大量部署單元的複雜應用,服務的交互變得愈來愈難理解。這會致使2個交互頻繁的服務被部署到不一樣的硬件上從而產生不少的遠程調用狀況出現。在大規模應用中,分析交互的頻率和數據大小與部署結構一致是很重要的。不少時候,從分佈式部署到本地可使性能獲得很大的提高而不須要損失靈活性和可擴展性。尤爲對那些無狀態的服務,把它們部署到不一樣的節點來提高其本地性。

結論

從這些反模式中能夠看出,在應用的設計初期階段就考慮可擴展性是很重要的。它是應用架構的一個關鍵驅動。在後期提升性能和可擴張性在多數或大多數狀況下工做會越困難。對應用產品的詳細分析來識別遠程調用的頻率或大致積數據,優化系統的一致性是不可或缺的。若是你遇到了類似的或不一樣的問題,請讓我知道,我好擴充個人反模式記錄

相關文章
相關標籤/搜索