- 論壇徽章:
- 0
|
大型Java分布式應(yīng)用縱橫談
每個大型應(yīng)用都在追求高可擴(kuò)展性和高可用性驅(qū)動的,而且云計算的發(fā)展必將使分布式平臺將來會更加流行。但對于Java分布式應(yīng)用的性能問題,你又怎么看呢?
在當(dāng)今應(yīng)用架構(gòu)里,分布式和應(yīng)用與服務(wù)之間的通信都是核心思想。想要從分布式中獲益,你必須牢牢記住幾條基本的原則,否則你可能會很容易遇到性能和擴(kuò)展性問題。在開發(fā)階段這些問題不會經(jīng)常出現(xiàn),但當(dāng)你進(jìn)行負(fù)載測試或產(chǎn)品化的時候,你可能會意識到你選擇的軟件架構(gòu)不能滿足性能和擴(kuò)展性需求。在這篇文章中,我們重點(diǎn)關(guān)注構(gòu)建分布式應(yīng)用需要記住的一些關(guān)鍵點(diǎn)。
分布式需要應(yīng)用之間進(jìn)行交互。范圍包括從大規(guī)模集群架構(gòu)上簡單的點(diǎn)到點(diǎn)的交互,到動態(tài)的面向服務(wù)或基于服務(wù)的架構(gòu)。跨系統(tǒng)邊界的通信也是提高軟件系統(tǒng)擴(kuò)展性和可用性的關(guān)鍵。如今軟件架構(gòu)已把分布式作為一個核心的必要的概念。Java平臺成為了核心的角色,因為它的分布式、有很好的API和產(chǎn)品支持這些特點(diǎn)。應(yīng)用場景從像SAP這樣在標(biāo)準(zhǔn)軟件上的系統(tǒng)集成,到內(nèi)部或外部的服務(wù)集成。SOA提供這樣的方法,使服務(wù)和應(yīng)用變的靈活和可重用,可以對新的市場需求很快的做響應(yīng)。另外,像使用網(wǎng)格計算,虛擬機(jī)和多核刀片機(jī)的趨勢,導(dǎo)致越來越多的集群應(yīng)用的出現(xiàn)。這主要是由于追求高可擴(kuò)展性和高可用性驅(qū)動的。而且云計算的發(fā)展趨勢表明,分布式平臺將來會更加流行。另外,系統(tǒng)正變得希望能更動態(tài)的增加其靈活性。例如,在運(yùn)行時添加應(yīng)用節(jié)點(diǎn)。這些趨勢也導(dǎo)致了系統(tǒng)結(jié)構(gòu)變得越來越復(fù)雜。對于開發(fā)人員來說,則更難理解產(chǎn)品中服務(wù)調(diào)用是如何實現(xiàn)的了。這種復(fù)雜性和缺乏對相應(yīng)知識的了解,很容易導(dǎo)致資源消耗的增加(CPU,內(nèi)存,網(wǎng)絡(luò))和性能的降低。
面具后的惡魔
如今,遠(yuǎn)程技術(shù)使分布式應(yīng)用的實現(xiàn)更加簡單。底層通信的細(xì)節(jié)和服務(wù)端和客戶端的基礎(chǔ)結(jié)構(gòu)對開發(fā)人員是透明的,F(xiàn)在,如果要把一個Java類暴露為一個服務(wù),有時只需要簡單的加一個注解到這個類上。服務(wù)也可以被工具生成的代理很容易的訪問。如下圖所示,但是,這僅僅是冰山的一角。
1.jpg (34.02 KB, 下載次數(shù): 43)
下載附件
2010-12-02 09:50 上傳
圖1.遠(yuǎn)程協(xié)議的上層架構(gòu)
遠(yuǎn)程堆棧的核心塊是對象的序列化和傳輸?shù)母袷交。通常,?yīng)用的開發(fā)者不需要知道這些。但是,這也是很多性能問題產(chǎn)生的原因。效率不高的序列化意味著,通過網(wǎng)絡(luò)傳輸了很多不需要的數(shù)據(jù)。復(fù)雜對象的顯示和大量的數(shù)據(jù),在序列化和反序列化期間,導(dǎo)致CPU和內(nèi)存的使用會很高。底層的基礎(chǔ)架構(gòu)和它的配置對應(yīng)用的性能有很大的影響。在客戶端,主要是連接的管理和底層線程模型。在分布式應(yīng)用中使用連接的指導(dǎo)方針和數(shù)據(jù)庫的連接很像。建立一個連接需要一定的時間。但這同樣要看是什么協(xié)議。例如,建立一個HTTPS的連接的開銷要大于一個簡單的TCP/IP連接。同時,連接又是系統(tǒng)很重要的資源。所以,使用連接池很重要。正確的配置在這里也很關(guān)鍵,因為錯誤的配置文件給我們帶來的壞處要多于好處。線程的模型涉及到請求如何被處理。重要的是請求是被同步還是異步處理。同步通信阻塞一個進(jìn)程直到收到相應(yīng)。在異步通信中,當(dāng)收到響應(yīng)時會調(diào)用一個回調(diào)。這就允許這個線程被其他事務(wù)使用。在服務(wù)端,可用的工作線程數(shù)量就是定義的并行處理的最大服務(wù)請求數(shù)。網(wǎng)絡(luò)本身也是分布式應(yīng)用的一個重要組件。網(wǎng)絡(luò)是比影響性能更加限制其可擴(kuò)展性的重要的瓶頸資源。這塊通常在開發(fā)時會被忽視,因為沒有調(diào)用實際的網(wǎng)絡(luò)。
遠(yuǎn)程調(diào)用之美在于...
這有很多可以選擇,Java提供了非常多的可能性和技術(shù)來實現(xiàn)分布式應(yīng)用。遠(yuǎn)程技術(shù)的選擇對應(yīng)用的架構(gòu)、性能和擴(kuò)展性有十分重要的影響。最“老的”的但是幾乎是用的最廣的遠(yuǎn)程協(xié)議是RMI(如下圖)。
2.jpg (49.14 KB, 下載次數(shù): 35)
下載附件
2010-12-02 09:50 上傳
圖2.RMI架構(gòu)
RMI是J2EE應(yīng)用的一個標(biāo)準(zhǔn)協(xié)議。像它的名稱暗示的一樣,設(shè)計時就是為了調(diào)用遠(yuǎn)程Java虛擬主機(jī)上的對象提供的方法。對象在服務(wù)端被暴露出來,這時客戶端就可以通過代理調(diào)用這個對象。同樣的服務(wù)端對象被多個線程使用。線程池被RMI基礎(chǔ)設(shè)施管理。通信通過TCP/IP被處理,并且使用JRMP或針對RMI的基于IIOP GIOP(CORBA協(xié)議)的協(xié)議。應(yīng)用服務(wù)端也提供自己的屬性協(xié)議來優(yōu)化其性能。如服務(wù)端的引用需要管理一樣,RMI基礎(chǔ)設(shè)施也提供了垃圾回收器來管理引用。這個分布式垃圾回收器(DGC)本身也使用RMI協(xié)議來管理服務(wù)器端的對象生命周期。除了客戶端和服務(wù)端很強(qiáng)大,RMI還有一些其他的實現(xiàn)。關(guān)于RMI的詳細(xì)介紹及應(yīng)用請參考51CTO之前的文章《用RMI實現(xiàn)基于Java的分布式計算》。
RMI只支持同步通信,缺點(diǎn)上面已經(jīng)討論過了。另外,不能為數(shù)據(jù)驅(qū)動的服務(wù)提供低級緩存,因為它是基于2進(jìn)制協(xié)議的。開發(fā)人員和系統(tǒng)架構(gòu)能夠改變基礎(chǔ)設(shè)施的配置參數(shù)來優(yōu)化性能。JMS是J2EE平臺上使用的第二多的協(xié)議。如下圖:
3.jpg (53.59 KB, 下載次數(shù): 45)
下載附件
2010-12-02 09:50 上傳
圖3.JMS架構(gòu)圖
有別于RMI, JMS是一個異步的協(xié)議。通信是基于隊列的,以便監(jiān)聽器可以對消息作出反應(yīng)。JMS不是一種標(biāo)準(zhǔn)的遠(yuǎn)程調(diào)用協(xié)議,但是它仍然能夠滿足服務(wù)與服務(wù)之間的交互。在SOA中非常重要的很多ESB的實現(xiàn),就采用基于JMS的中間件來進(jìn)行服務(wù)之間的信息傳遞。由于JMS是異步的,一些典型的同步問題就可以避免。在很多系統(tǒng)中,高可擴(kuò)展性的關(guān)鍵在于能夠很快的釋放資源(像線程)。在很多情況下,異步處理是唯一合適的方法。JMS提供很多不同的傳輸格式。XML是最通用的消息格式,但二進(jìn)制格式也是可能的。消息結(jié)構(gòu)的設(shè)計是應(yīng)用架構(gòu)的一個重要部分,因為它可以直接影響到應(yīng)用的性能和可擴(kuò)展性。
基于SOAP的WEB Service(如下圖)和其他相關(guān)的WS-*也在Java 企業(yè)應(yīng)用領(lǐng)域中變得越來越重要。
4.jpg (47.96 KB, 下載次數(shù): 38)
下載附件
2010-12-02 09:50 上傳
圖4.同步和異步SOAP架構(gòu)
設(shè)計SOAP是為了替換CORBA,而且一開始就得到了業(yè)界的強(qiáng)烈支持。因為WS-I之間的共同努力,不同平臺差不多能夠很容易的連接起來。SOAP是一種基于XML的RPC協(xié)議,所以很容易和浪費(fèi)帶寬聯(lián)系到一起。
越來越多的基于REST的服務(wù)開始取代SOAP。Java中的REST服務(wù)在JSR 311中有說明,是基于HTTP所支持的基本操作而設(shè)計的。但是,REST不是作為RCP協(xié)議,而是面向資源的,為了訪問和操作(web)資源而設(shè)計的。這兩個協(xié)議都支持同步通信。這也是底層HTTP協(xié)議所要求的。WS-地址對SOAP協(xié)議進(jìn)行擴(kuò)展,所以它也允許異步服務(wù)的實現(xiàn)。REST最大的優(yōu)點(diǎn)是,能夠很容易的通過HTTP代理實現(xiàn)緩存。REST依靠使用HTTP底層協(xié)議,無論如何都和用的機(jī)制。
可能犯的錯
分布式應(yīng)用的很多地方都可能出現(xiàn)潛在的問題,如圖所示:
5.jpg (20.21 KB, 下載次數(shù): 46)
下載附件
2010-12-02 09:50 上傳
圖5 分布式應(yīng)用的問題起因
在客戶端,主要的問題在于糟糕的交互設(shè)計-太多的服務(wù)調(diào)用,或者選擇了錯誤的通信模式。同步事務(wù)運(yùn)行時間過長很容易導(dǎo)致性能問題。在通信層,大量的數(shù)據(jù)和過多的服務(wù)調(diào)用所產(chǎn)生的高的網(wǎng)絡(luò)負(fù)載是主要問題。在服務(wù)端,不適當(dāng)?shù)姆⻊?wù)接口設(shè)計和不合適的序列化策略的使用導(dǎo)致性能和擴(kuò)展性問題。我們下面仔細(xì)看下這些問題。
分布式應(yīng)用的問題起因
通信協(xié)議的正確選擇主要取決于系統(tǒng)的整體架構(gòu)和底層的需求。如果你工作在有mainframe、Java和.NET組件相互交互的特異環(huán)境中,用SOAP是行不通的。在純Java環(huán)境中,在JRMP上使用RMI仍是性能最優(yōu),可擴(kuò)展性最好的解決方案,你能夠獲得開箱即用的編程支持。在很多SOA實現(xiàn)中,SOA和基于Web Service的實現(xiàn)同義而語。所以有越來越多的使用SOAP作為RPC協(xié)議的純Java應(yīng)用案例出現(xiàn),盡管采用這樣的方法一點(diǎn)有點(diǎn)都沒有。調(diào)查顯示,和RMI-JRMP相比,經(jīng)常使用SOAP還是有意義的。除了描述過的標(biāo)準(zhǔn)協(xié)議,一些其他的基于XML的和二進(jìn)制協(xié)議也在一些應(yīng)用中使用。Hessian的性能就不錯。另外,還有一些其他編程語言的實現(xiàn)。例如使用Spring把POJOs暴露給遠(yuǎn)程調(diào)用使不改變實現(xiàn)就在不同的協(xié)議間切換變得相對容易。Spring 支持RMI, HTTP, Hessian, Burlap, JAX-RPC, JAX-WS 和 JMS。
反模式:饒舌的應(yīng)用
在搭建分布式應(yīng)用時,一個核心的原則就是盡量減少遠(yuǎn)程調(diào)用。這些意味著數(shù)據(jù)序列化的開銷,建立連接的開銷和附件的網(wǎng)絡(luò)負(fù)載。另外,CPU,內(nèi)存和網(wǎng)絡(luò)資源的消耗限制了可擴(kuò)展性。所以,為遠(yuǎn)程應(yīng)用的接口設(shè)計一種方法,來確保必要的服務(wù)交互數(shù)最小是十分重要的。尤其是那些起初是在本地搭建的,然后為了可擴(kuò)展性原因遭遇了大量服務(wù)交互的應(yīng)用。這些問題大多會在負(fù)載測試或產(chǎn)品化時出現(xiàn),但當(dāng)本地開發(fā)測試時一點(diǎn)問題都沒有。可以采用適當(dāng)?shù)男阅芄芾矸椒,在開發(fā)過程中分析遠(yuǎn)程行為就可以避免這些問題。下圖顯示的是一個通過dynaTrace分析一個應(yīng)用的遠(yuǎn)程行為的例子 。
6.jpg (32.89 KB, 下載次數(shù): 39)
下載附件
2010-12-02 09:50 上傳
基于這個分析,接口能夠重新創(chuàng)建,應(yīng)用邏輯能夠重新設(shè)計來減少遠(yuǎn)程調(diào)用的次數(shù)?赡艿姆椒ㄊ,合并幾個方法的邏輯為一個,或在幾個調(diào)用請求周邊的對象處,使用數(shù)據(jù)容器。特定數(shù)據(jù)的位置也可以幫助減少遠(yuǎn)程調(diào)用,因為在需要的地方數(shù)據(jù)是可用的。尤其當(dāng)讀數(shù)據(jù)時,使用cache可以很大程度上提高性能和可擴(kuò)展性。在軟件設(shè)計的早期,服務(wù)的分發(fā)和可能的通信在成為需求或?qū)⒊蔀樾枨髸r已經(jīng)考慮到是很重要的。
反模式:大格式消息
當(dāng)調(diào)用遠(yuǎn)程的服務(wù)時,這通常意味著數(shù)據(jù)會在不同的協(xié)議上傳輸。像XML在SOAP協(xié)議上傳輸或二進(jìn)制數(shù)據(jù)在RMI協(xié)議上傳輸。大多數(shù)技術(shù)傳輸對象的數(shù)據(jù)或?qū)ο蟊旧。大多?shù)情況下,序列化的發(fā)生是在遠(yuǎn)程實現(xiàn)的底層。序列化的開銷和所傳輸對象的大小相對應(yīng)。在實際情況下,我們進(jìn)行序列化的開銷要占到98%。怎么會這樣?一個鑒權(quán)服務(wù)接口需要一個用戶對象來授權(quán)。這個用戶對象不僅有用戶名和密碼,還有很多屬性,關(guān)聯(lián)到其他用例的數(shù)據(jù)引用。標(biāo)準(zhǔn)的SOAP序列化要創(chuàng)建幾千字節(jié)的數(shù)據(jù)消息。這些數(shù)據(jù)要被服務(wù)解析并映射到用戶對象結(jié)構(gòu)上,導(dǎo)致大量CPU和內(nèi)存的消耗。解決方案再明顯不過了。接口要重構(gòu),只需要用戶ID和密碼。所以,除了選擇正確的遠(yuǎn)程技術(shù),消息內(nèi)容的設(shè)計對構(gòu)建好的性能和可擴(kuò)展性的應(yīng)用很重要。通常正好符合設(shè)計的很好一般對象會帶來高性能的回報。
反模式:分布部署
分布式的Java企業(yè)級應(yīng)用會導(dǎo)致一個應(yīng)用分割成多個服務(wù)和一些部署單元部署到一些應(yīng)用服務(wù)上。分布式的有一個組件新的部署包不需要重新部署到其他組件上。另一個可能性是,大量使用的服務(wù)能夠部署到獨(dú)立的硬件或被部署多次。有大量部署單元的復(fù)雜應(yīng)用,服務(wù)的交互變得越來越難理解。這會導(dǎo)致2個交互頻繁的服務(wù)被部署到不同的硬件上從而產(chǎn)生很多的遠(yuǎn)程調(diào)用情況出現(xiàn)。在大規(guī)模應(yīng)用中,分析交互的頻率和數(shù)據(jù)大小與部署結(jié)構(gòu)一致是很重要的。很多時候,從分布式部署到本地可以使性能得到很大的提升而不需要損失靈活性和可擴(kuò)展性。尤其對那些無狀態(tài)的服務(wù),把它們部署到不同的節(jié)點(diǎn)來提升其本地性。
結(jié)論
從這些反模式中可以看出,在應(yīng)用的設(shè)計初期階段就考慮可擴(kuò)展性是很重要的。它是應(yīng)用架構(gòu)的一個關(guān)鍵驅(qū)動。在后期提高性能和可擴(kuò)張性在多數(shù)或大多數(shù)情況下工作會越困難。對應(yīng)用產(chǎn)品的詳細(xì)分析來識別遠(yuǎn)程調(diào)用的頻率或大體積數(shù)據(jù),優(yōu)化系統(tǒng)的一致性是不可或缺的。如果你遇到了相似的或不同的問題,請讓我知道,我好擴(kuò)充我的反模式記錄。 |
|