雖然不少人都曾預言 Java 將一蹶不振,可是不能否認的是,不少重要項目中,尤爲是銀行和政府一些大型項目,Java 仍在其中扮演着極其重要的角色。筆者屢次參與銀行、運營商等大型企業的性能優化工做,總結了企業級 Java 應用最應重視的4個性能指標,主要包括:商業事務,外部服務,垃圾回收以及應用佈局。下文將逐一展開闡述:html
商業事務是真實用戶體驗的直觀反映:它們抓取了用戶與應用交互時,用戶體驗到的實時性能數據。測量商業事務的性能,須要抓取一件商業事務總體的響應時間及其各個組件的響應時間。這些響應時間再與知足業務需求的基準進行比較,從而決定應用是否正常。程序員
若是你只打算測量應用的一個方面,本文會推薦你測量商業事務的表現。儘管容量指標(container metrics)能幫助你決定什麼時候調節集羣規模,可是商業事務才決定了應用自己的性能。你無需詢問應用服務器線程池(thread pool)的使用狀況,而是關心用戶可否迅速完成他們的商業事務,以及這些事務的表現是否正常。數據庫
介紹一點背景知識:商業事務經過其入口進行辨別,即用戶與你的業務進行互動的入口。這類互動包括:一個網頁請求,一個網頁服務調用,或消息隊列中的一條消息。固然,你也能夠基於一個 URL 參數爲一樣的網頁請求定義多個入口,或基於一個服務調用的內容定義多個入口點。關鍵在於:商業交易必須與對你的業務流程相關聯,好比說中國移動的空中繳費業務對應到系統中是多個原子服務,咱們就應該將這幾個原子服務經過相應的關聯聚合成一個空中繳費業務來進行監控。性能優化
辨別某個商業交易後,它的性能就會在整個應用生態系統中進行測量。每一個商業交易的性能會與其基準進行比較,斷定其是否正常。譬如,若是某個商業事務的響應時間大於您設定的閾值,咱們便斷定其運行異常。服務器
總而言之,商業事務最能反映用戶體驗,所以它們也是最重要的抓取維度。佈局
外部服務的形式多種多樣:從屬的網頁服務、遺留系統或數據庫等。外部服務是與應用交互的系統。運行在外部服務系統中的代碼經常沒法控制,可是咱們能夠控制這些系統的配置,所以瞭解他們是否運行正常以及什麼時候出錯也很重要。而且,咱們必須有能力區分問題是出自自身應用,仍是源於這些外部服務系統。性能
從商業事務的角度來講,咱們能夠辨別並測量這些處於自身應用的外部服務。有時,咱們須要配置監控方法從而辨別那些包裹了外部服務調用的方法。可是對於常見的協議,諸如 HTTP 和 JDBC,外部服務能夠自動檢測。測試
商業事務讓你對應用的性能有了全局的掌控,幫助你對性能問題進行分類。可是外部服務總能以意想不到的方式極大地影響應用的運行,因此你必須監控它們。優化
從 Java 發佈最先版本開始,一直都保留的核心特性就是垃圾回收,它真是讓人又愛又恨。垃圾回收使咱們再也不須要手動管理內存:當使用完一個對象後,咱們只需刪除它的引用,而後垃圾回收就會自動釋放它。若是你使用過須要手動管理內存的語言,諸如C或C++,你會滿懷感激。垃圾回收爲程序員們減小了分配、釋放內存空間的繁瑣步驟。spa
此外,由於垃圾回收器會自動釋放沒有引用的內存空間,它減小了傳統的內容泄露狀況,即內存被分配後,該內存的引用在內存釋放前就被刪除了。聽起來就像靈丹妙藥,不是麼?
儘管垃圾回收達成了無需手動管理內存的目標,也防止了傳統的內存泄露,可是做爲代價,垃圾回收過程有時至關笨拙。根據不一樣的 JVM,垃圾回收策略也會不一樣。深刻探討這些策略超出了本文的主旨。可是,讀者應該明白,瞭解垃圾回收期的工做原理,以及最佳的配置方案相當重要。
垃圾回收最大的敵人就是傳說中的主要 (major) 或 (full) 垃圾回收。除了 Azul JVM,全部的 JVM 都有這個問題。一般,垃圾回收大體分爲兩類:
爲了釋放存活時間較短的對象,次級垃圾回收發生得相對頻繁。他們在運行時不會封鎖線程,產生的影響較小。
然而,主要垃圾回收,有時也稱爲「暫停世界(Stop The World, STW)」垃圾回收,由於他們在運行時會封鎖 JVM 中的全部線程。
當垃圾回收運行時,它會運行一項可達性測試 (reachability test),如圖四所示。它會建立一個由對象組成的根集合 (root set),該集合包含每一個運行線程中的直接可見對象。接着,它會探尋根集合中的對象涉及的其餘對象,而後探尋這些對象涉及的對象,直到全部對象都被涉及。在這個過程當中,它會記錄 (mark) 下現時活動對象的內存地址,而後把不被使用的全部地址都掃除 (sweep)。說得更恰當些,它會把沒有根集合對象引用的內存都釋放。最終,它會壓縮、整理這些內存,這樣新的對象才能得到內存分配。
根據不一樣的 JVM ,次級、主要回收的方式都會不一樣。圖五圖六展現了在Sun JVM內次級、主要回收的操做方式。
在次級回收中,內存主要分配到 Eden 空間直到將其填滿。接着,拷貝收集器(copy collector)會將 Eden 中的活動對象拷貝到兩個倖存者空間(survivor spaces, to space和from space)。遺留在 Eden 中的對象就會被移除。若是倖存者空間被填滿,但還有多餘的活動對象,這些對象會被移到 tenured 空間。只有主要回收才能釋放tenured空間的內存。
最終,tenured 空間會被填滿,主要回收將會執行。它不會將倖存者空間放不下的活動對象拷貝到 tenured 空間中。此時,JVM 會封鎖全部線程,運行可達性測試,清除年輕的數據(Eden和兩個倖存者空間),並壓縮 tenured 空間。咱們將之稱爲主要回收。
你或許會想,堆越大,主要回收運行得越不頻繁。可是當它執行時,所需時間就會比小堆要長。所以,調整好堆的大小和垃圾回收策略對於應用的性能也很重要。
最後要探討的性能指標是應用佈局。由於雲的出現,如今的應用變得更加靈活:應用環境能夠根據用戶需求調節大小。所以,對應用的佈局進行檢測從而決定實例的多少是否合適是很是重要的。若是你的實例太多,你的雲主機成本就會增長。但若是你沒有足夠的實例,商業事務就會受到影響。
在評測過程當中,下面兩個指標尤爲重要:
商業事務的吞吐量
容器性能
商業事務應該基準化,你應該知道在給定的時間裏爲了知足基準所需的實例數量。若是你的商業事務的吞吐量增加忽然,你就要增長實例以知足用戶。
另外一個須要監測的是容器性能。具體來講,你想肯定是否有應用中的實例負載過大,若是有,你或許想在那個應用中添加實例。從應用的角度查看實例狀態很重要,由於單個實例可能因爲垃圾回收之類的因素負載過大,但若是應用中大多數實例都負載過大,則該應用可能已經沒法支持它接受的訪問量。
由於應用中的實例能夠單個地調節規模,因此分析各個實例的性能進而調整應用佈局就相當重要。