2006 年底,Sun 公司發(fā)布了 Java Standard Edition 6(Java SE 6)的最終正式版,代號 Mustang(野馬)。跟 Tiger(Java SE 5)相比,Mustang 在性能方面有了不錯的提升。與 Tiger 在 API 庫方面的大幅度加強(qiáng)相比,雖然 Mustang 在 API 庫方面的新特性顯得不太多,但是也提供了許多實用和方便的功能:在腳本,WebService,XML,編譯器 API,數(shù)據(jù)庫,JMX,網(wǎng)絡(luò)和 Instrumentation 方面都有不錯的新特性和功能加強(qiáng)。 本系列 文章主要介紹 Java SE 6 在 API 庫方面的部分新特性,通過一些例子和講解,幫助開發(fā)者在編程實踐當(dāng)中更好的運(yùn)用 Java SE 6,提高開發(fā)效率。
本文是其中的第三篇,介紹了 Java 管理擴(kuò)展(Java Management Extension,JMX) 架構(gòu)及其框架,以及在 Java SE 5 中新引入的 JMX API -- java.lang.management 包, 最后作者講述了此 API 在 Java SE 6 中的相關(guān)改進(jìn)和對未來版本的展望
前言
在 Java 程序的運(yùn)行過程中,對 JVM 和系統(tǒng)的監(jiān)測一直是 Java 開發(fā)人員在開發(fā)過程所需要的。一直以來,Java 開發(fā)人員必須通過一些底層的 JVM API,比如 JVMPI 和 JVMTI 等,才能監(jiān)測 Java 程序運(yùn)行過程中的 JVM 和系統(tǒng)的一系列情況,這種方式一直以來被人所詬病,因為這需要大量的 C 程序和 JNI 調(diào)用,開發(fā)效率十分低下。于是出現(xiàn)了各種不同的專門做資源管理的程序包。為了解決這個問題,Sun 公司也在其 Java SE 5 版本中,正式提出了 Java 管理擴(kuò)展(Java Management Extensions,JMX)用來管理檢測 Java 程序(同時 JMX 也在 J2EE 1.4 中被發(fā)布)。
JMX 的提出,讓 JDK 中開發(fā)自檢測程序成為可能,也提供了大量輕量級的檢測 JVM 和運(yùn)行中對象/線程的方式,從而提高了 Java 語言自己的管理監(jiān)測能力
JMX 和系統(tǒng)管理
管理系統(tǒng)(Management System)
要了解 JMX,我們就必須對當(dāng)前的 IT 管理系統(tǒng)有一個初步的了解。隨著企業(yè) IT 規(guī)模的不斷增長,IT 資源(IT resource)數(shù)量不斷增加,IT 資源的分布也越來越分散。可以想象,甚至對于一家只有幾百臺 PC 公司的 IT 管理人員來說,分發(fā)一個安全補(bǔ)丁并且保證其在每臺 PC 上的安裝,如果只依賴人工來完成那簡直就是一場噩夢。這樣,IT 管理系統(tǒng)就應(yīng)運(yùn)而生。
然而,CPU、網(wǎng)卡、存儲陣列是 IT 資源;OS、MS Office、Oracle database、IBM Websphere 也是 IT 資源。IT 管理系統(tǒng)若要對這些 IT 資源進(jìn)行管理,就必須對這些管理對象有所了解:形形色色的 IT 資源就像是說著不同語言的人:Oralce 數(shù)據(jù)庫表達(dá)內(nèi)存緊張的方式和 Window XP 是絕然不同的, 而 IT 管理系統(tǒng)就像建造通天塔的經(jīng)理,必須精通所有的語言, 這幾乎是一個不可能完成的任務(wù)。難道 IT 管理系統(tǒng)是另外一個通天塔嗎?當(dāng)然不是!其實我們只要給每個 IT 資源配個翻譯就可以了。
管理系統(tǒng)的構(gòu)架
上圖分析了管理系統(tǒng)的基本構(gòu)架模式。其中 Agent / SubAgent 起到的就是翻譯的作用:把 IT 資源報告的消息以管理系統(tǒng)能理解的方式傳送出去。
也許讀者有會問,為什么需要 Agent 和 SubAgent 兩層體系呢?這里有兩個現(xiàn)實的原因:
管理系統(tǒng)一般是一個中央控制的控制軟件,而 SubAgent 直接監(jiān)控一些資源,往往和這些資源分布在同一物理位置。當(dāng)這些 SubAgent 把狀態(tài)信息傳輸?shù)焦芾硐到y(tǒng)或者傳達(dá)管理系統(tǒng)的控制指令的時候,需要提供一些網(wǎng)絡(luò)傳輸?shù)墓δ堋?
管理系統(tǒng)的消息是有一定規(guī)范的,消息的翻譯本身是件復(fù)雜而枯燥的事情。
一般來說,管理系統(tǒng)會將同一物理分布或者功能類似的 SubAgent 分組成一組,由一個共用的 Agent 加以管理。在這個 Agent 里封裝了 1 和 2 的功能。
JMX 和管理系統(tǒng)
JMX 既是 Java 管理系統(tǒng)的一個標(biāo)準(zhǔn),一個規(guī)范,也是一個接口,一個框架。圖 2 展示了 JMX 的基本架構(gòu)。
和其它的資源系統(tǒng)一樣,JMX 是管理系統(tǒng)和資源之間的一個接口,它定義了管理系統(tǒng)和資源之間交互的標(biāo)準(zhǔn)。javax.management.MBeanServer 實現(xiàn)了 Agent 的功能,以標(biāo)準(zhǔn)的方式給出了管理系統(tǒng)訪問 JMX 框架的接口。而 javax.management.MBeans 實現(xiàn)了 SubAgent 的功能,以標(biāo)準(zhǔn)的方式給出了 JMX 框架訪問資源的接口。而從類庫的層次上看,JMX 包括了核心類庫 java.lang.management 和 javax.management 包。java.lang.management 包提供了基本的 VM 監(jiān)控功能,而 javax.management 包則向用戶提供了擴(kuò)展功能。
JMX 的基本框架
JMX 使用了 Java Bean 模式來傳遞信息。一般說來,JMX 使用有名的 MBean,其內(nèi)部包含了數(shù)據(jù)信息,這些信息可能是:應(yīng)用程序配置信息、模塊信息、系統(tǒng)信息、統(tǒng)計信息等。另外,MBean 也可以設(shè)立可讀寫的屬性、直接操作某些函數(shù)甚至啟動 MBean 可發(fā)送的 notification 等。MBean 包括 Standard,MXBean,Dynamic,Model,Open 等幾種分類,其中最簡單是標(biāo)準(zhǔn) MBean 和 MXBean,而我們使用得最多的也是這兩種。MXBean 主要是 java.lang.management 使用較多,將在下一節(jié)中介紹。我們先了解其他一些重要的 MBean 的種類。
標(biāo)準(zhǔn) MBean
標(biāo)準(zhǔn) MBean 是最簡單的一類 MBean,與動態(tài) Bean 不同,它并不實現(xiàn) javax.management 包中的特殊的接口。說它是標(biāo)準(zhǔn) MBean, 是因為其向外部公開其接口的方法和普通的 Java Bean 相同,是通過 lexical,或者說 coding convention 進(jìn)行的。下面我們就用一個例子來展現(xiàn),如何實現(xiàn)一個標(biāo)準(zhǔn) MBean 來監(jiān)控某個服務(wù)器 ServerImpl 狀態(tài)的。ServerImpl 代表了用來演示的某個 Server 的實現(xiàn)
在管理過程中,管理系統(tǒng)并不與資源或者 SubAgent 直接打交道,也就是說,這里不會直接引用到 MBean。而是通過 MBeanServer 的 getAttribute 方法取得對應(yīng) MBean 的屬性的。
動態(tài) MBean
但是對于很多已有的 SubAgent 實現(xiàn),其 Coding Convention 并不符合標(biāo)準(zhǔn) MBean 的要求。重構(gòu)所有這些 SubAgent 以符合標(biāo)準(zhǔn) MBean 標(biāo)準(zhǔn)既費力也不實際。JMX 中給出了動態(tài)(Dynamic) MBean 的概念,MBServer 不再依據(jù) Coding Convention 而是直接查詢動態(tài) MBean 給出的元數(shù)據(jù)(meta data)以獲得 MBean 的對外接口。
它動態(tài) MBean
另外還有兩類 MBean:Open MBean 和 Model MBean。實際上它們也都是動態(tài) MBean。
Open MBean 與其它動態(tài) MBean 的唯一區(qū)別在于,前者對其公開接口的參數(shù)和返回值有所限制 —— 只能是基本類型或者 javax.management.openmbean 包內(nèi)的 ArrayType、CompositeType、TarbularType 等類型。這主要是考慮到管理系統(tǒng)的分布,很可能遠(yuǎn)端管理系統(tǒng)甚至 MBServer 層都不具有 MBean 接口中特殊的類。
Model Bean
然而,普通的動態(tài) Bean 通常缺乏一些管理系統(tǒng)所需要的支持:比如持久化 MBean 的狀態(tài)、日志記錄、緩存等等。如果讓用戶去一一實現(xiàn)這些功能確實是件枯燥無聊的工作。為了減輕用戶的負(fù)擔(dān),JMX 提供商都會提供不同的 ModelBean 實現(xiàn)。其中有一個接口是 Java 規(guī)范中規(guī)定所有廠商必須實現(xiàn)的:javax.management.modelmbean.RequiredModelBean。通過配置 Descriptor 信息,我們可以定制這個 Model Bean, 指定哪些 MBean 狀態(tài)需要記入日志、如何記錄以及是否緩存某些屬性、緩存多久等等。
虛擬機(jī)檢測
JMX 與虛擬機(jī)檢測
JMX 的提出,為 Java 虛擬機(jī)提供了 Java 層上的檢測機(jī)制。J2SE 中,新提出的 java.lang.management 包即是 JMX 在 JDK 的一個應(yīng)用,它提供了大量的有用的接口,通過 MBean 方式,提供了對 Java 虛擬機(jī)和運(yùn)行時遠(yuǎn)端的監(jiān)控和檢測方式,來幫助用戶來檢測本地或者遠(yuǎn)端的虛擬機(jī)的運(yùn)行情況。有了 JMX 之后,我們可以設(shè)計一個客戶端,來檢測遠(yuǎn)端一個正在運(yùn)行的虛擬機(jī)中的線程數(shù)、線程當(dāng)前的 Stack、內(nèi)存管理、GC 所占用的時間、虛擬機(jī)中的對象和當(dāng)前虛擬機(jī)參數(shù)等重要的參數(shù)和運(yùn)行時信息。JMX 另外的一個重要功能是對配置信息的檢測和再配置。比如,我們可以在遠(yuǎn)端查看和修改當(dāng)前 JVM 的 verbose 參數(shù),以達(dá)到動態(tài)管理的目的。甚至,我們可以在遠(yuǎn)端指揮 JVM 做一次 GC,這在下文中有詳細(xì)介紹。
JMX 提供的虛擬機(jī)檢測 API
檢測虛擬機(jī)當(dāng)前的狀態(tài)總是 Java 開放人員所關(guān)心的,也正是因為如此,出現(xiàn)了大量的 profiler 工具來檢測當(dāng)前的虛擬機(jī)狀態(tài)。從 Java SE 5 之后,在 JDK 中,我們有了一些 Java 的虛擬機(jī)檢測 API,即 java.lang.management 包。Management 包里面包括了許多 MXBean 的接口類和 LockInfo、MemoryUsage、MonitorInfo 和 ThreadInfo 等類。從名字可以看出,該包提供了虛擬機(jī)內(nèi)存分配、垃圾收集(GC)情況、操作系統(tǒng)層、線程調(diào)度和共享鎖,甚至編譯情況的檢測機(jī)制。這樣一來,Java 的開發(fā)人員就可以很簡單地為自己做一些輕量級的系統(tǒng)檢測,來確定當(dāng)前程序的各種狀態(tài),以便隨時調(diào)整。
要獲得這些信息,我們首先通過 java.lang.management.ManagementFactory 這個工廠類來獲得一系列的 MXBean。包括:
ClassLoadingMXBean
ClassLoadMXBean 包括一些類的裝載信息,比如有多少類已經(jīng)裝載/卸載(unloaded),虛擬機(jī)類裝載的 verbose 選項(即命令行中的 Java –verbose:class 選項)是否打開,還可以幫助用戶打開/關(guān)閉該選項。
CompilationMXBean
CompilationMXBean 幫助用戶了解當(dāng)前的編譯器和編譯情況,該 mxbean 提供的信息不多。
GarbageCollectorMXBean
相對于開放人員對 GC 的關(guān)注程度來說,該 mxbean 提供的信息十分有限,僅僅提供了 GC 的次數(shù)和 GC 花費總時間的近似值。但是這個包中還提供了三個的內(nèi)存管理檢測類:MemoryManagerMXBean,MemoryMXBean 和 MemoryPoolMXBean。
MemoryManagerMXBean
這個類相對簡單,提供了內(nèi)存管理類和內(nèi)存池(memory pool)的名字信息。
MemoryMXBean
這個類提供了整個虛擬機(jī)中內(nèi)存的使用情況,包括 Java 堆(heap)和非 Java 堆所占用的內(nèi)存,提供當(dāng)前等待 finalize 的對象數(shù)量,它甚至可以做 gc(實際上是調(diào)用 System.gc)。
MemoryPoolMXBean
該信息提供了大量的信息。在 JVM 中,可能有幾個內(nèi)存池,因此有對應(yīng)的內(nèi)存池信息,因此,在工廠類中,getMemoryPoolMXBean() 得到是一個 MemoryPoolMXBean 的 list。每一個 MemoryPoolMXBean 都包含了該內(nèi)存池的詳細(xì)信息,如是否可用、當(dāng)前已使用內(nèi)存/最大使用內(nèi)存值、以及設(shè)置最大內(nèi)存值等等。
OperatingSystemMXBean
該類提供的是操作系統(tǒng)的簡單信息,如構(gòu)架名稱、當(dāng)前 CPU 數(shù)、最近系統(tǒng)負(fù)載等。
RuntimeMXBean
運(yùn)行時信息包括當(dāng)前虛擬機(jī)的名稱、提供商、版本號,以及 classpath、bootclasspath 和系統(tǒng)參數(shù)等等。
ThreadMXBean
在 Java 這個多線程的系統(tǒng)中,對線程的監(jiān)控是相當(dāng)重要的。ThreadMXBean 就是起到這個作用。ThreadMXBean 可以提供的信息包括各個線程的各種狀態(tài),CPU 占用情況,以及整個系統(tǒng)中的線程狀況。從 ThreadMXBean 可以得到某一個線程的 ThreadInfo 對象。這個對象中則包含了這個線程的所有信息。
java.lang.management 和虛擬機(jī)的關(guān)系
我們知道,management 和底層虛擬機(jī)的關(guān)系是非常緊密的。其實,有一些的是直接依靠虛擬機(jī)提供的公開 API 實現(xiàn)的,比如 JVMTI;而另外一些則不然,很大一塊都是由虛擬機(jī)底層提供某些不公開的 API / Native Code 提供的。這樣的設(shè)計方式,保證了 management 包可以提供足夠的信息,并且使這些信息的提供又有足夠的效率;也使 management 包和底層的聯(lián)系非常緊密。
回頁首
Java 6 中的 API 改進(jìn)
Management 在 Java SE 5 被提出之后,受到了歡迎。在 Java 6 當(dāng)中,這個包提供更多的 API 來更好地提供信息。
OperatingSystemMXBean. getSystemLoadAverage()
Java 程序通常關(guān)注是虛擬機(jī)內(nèi)部的負(fù)載、內(nèi)存等狀況,而不考慮整個系統(tǒng)的狀況。但是很多情況下,Java 程序在運(yùn)行過程中,整個計算機(jī)系統(tǒng)的系統(tǒng)負(fù)荷情況也會對虛擬機(jī)造成一定的影響。隨著 Java 的發(fā)展,Java 程序已經(jīng)覆蓋了各個行業(yè),這一點也必須得到關(guān)注。在以前,利用 Native 代碼來檢測系統(tǒng)負(fù)載往往是唯一的選擇,但是在 Java 6 當(dāng)中,JDK 自己提供了一個輕量級的系統(tǒng)負(fù)載檢測 API,即 OperatingSystemMXBean.getSystemLoadAverage()。
當(dāng)然這個 API 事實上僅僅返回一個對前一分鐘系統(tǒng)負(fù)載的簡單的估測。它設(shè)計的主要目標(biāo)是簡單快速地估測當(dāng)前系統(tǒng)負(fù)荷,因此它首先保證了這個 API 的效率是非常高的;也因為如此,這個 API 事實上并不適用于所有的系統(tǒng)。
鎖檢測
我們知道,同步是 Java 語言很重要的一個特性。在 Java SE 中,最主要的同步機(jī)制是依靠 synchronize 關(guān)鍵字對某一個對象加鎖實現(xiàn)的;在 Java SE 5 之后的版本中,concurrent 包的加入,大大強(qiáng)化了 Java 語言的同步能力,concurrent 提供了很多不同類型的鎖機(jī)制可供擴(kuò)展。因此,要更好地觀測當(dāng)前的虛擬機(jī)狀況和不同線程的運(yùn)行態(tài),去觀察虛擬機(jī)中的各種鎖,以及線程與鎖的關(guān)系是非常必要的。很可惜的是,在過去的 JDK 中,我們并沒有非常方便的 API 以供使用。一個比較直接的檢測方式是查看線程的 stack trace,更為強(qiáng)大全面(但是也更復(fù)雜并且效率低下)的方案是得到一個 VM 所有對象的快照并查找之,這些策略的代價都比較大,而且往往需要編寫復(fù)雜的 Native 代碼。
JDK 6 里提供了一些相當(dāng)簡單的 API 來提供這個服務(wù)。首先了解兩個新類,LockInfo 和 MonitorInfo 這兩個類承載了鎖的信息。LockInfo 可以是任何的 Java 鎖,包括簡單 Java 鎖和 java.util.concurrent 包中所使用的鎖(包括 AbstractOwnableSynchronizer 和 Condition 的實現(xiàn)類/子類),而 MonitorInfo 是簡單的 Java 對象所代表的鎖。要檢測一個線程所擁有的鎖和等待的鎖,首先,要得到一個線程的 ThreadInfo,然后可以簡單地調(diào)用:
getLockedMonitors()
返回一個所有當(dāng)前線程已經(jīng)掌握的鎖對象的列表。
getLockedSynchronizers()
對于使用 concurrent 包的線程,返回一個該線程所掌握的“ownable synchronizer”(即 AbstractOwnableSynchronizer 及其子類)所組成的列表。
getLockInfo()
當(dāng)前線程正在等待的那個鎖對象的信息就可以知道線程所有的鎖信息。通過這些鎖信息,我們很方便的可以知道當(dāng)前虛擬機(jī)的所有線程的鎖信息。由此,我們還可以推導(dǎo)出更多的信息。
死鎖檢測
死鎖檢測一直以來是軟件工程師所重視的,顯然一個死鎖的系統(tǒng)永遠(yuǎn)是工程師最大的夢魘。Java 程序的死鎖檢測也一直以來是 Java 程序員所頭痛的。為了解決線程間死鎖問題,一般都有預(yù)防(代碼實現(xiàn)階段)和死鎖后恢復(fù)(運(yùn)行時)兩種方式。以前 Java 程序員都重視前者,因為在運(yùn)行態(tài)再來檢測和恢復(fù)系統(tǒng)是相當(dāng)麻煩的,缺少許多必要的信息;但是,對于一些比較復(fù)雜的系統(tǒng),采取后者或者運(yùn)行時調(diào)試死鎖信息也是非常重要的。由上面所說,現(xiàn)在我們已經(jīng)可以知道每一個線程所擁有和等待的鎖,因此要計算出當(dāng)前系統(tǒng)中是否有死鎖的線程也是可行的了。當(dāng)然,Java 6 里面也提供了一個 API 來完成這個功能,即:
ThreadMXBean.findDeadlockedThreads()
這個函數(shù)的功能就是檢測出當(dāng)前系統(tǒng)中已經(jīng)死鎖的線程。當(dāng)然,這個功能復(fù)雜,因此比較費時。基本上僅僅將之用于調(diào)試,以便對復(fù)雜系統(tǒng)線程調(diào)用的改進(jìn)。
回頁首
未來的發(fā)展
JMX 在 Java SE 5/6 中的功能已經(jīng)相當(dāng)強(qiáng)大,但是距離 Java 程序開發(fā)人員的要求還是有一段距離,因此 Sun 公司已經(jīng)向 JCP 提出了 JSR 255 (JMX API 2.0 版本)來擴(kuò)充和進(jìn)一步發(fā)展 JMX,并希望這個 JSR 將在 Java SE 7 中實現(xiàn)。在這個文檔中,新的 JMX 2.0 將著重于:
對 management 模型的優(yōu)化,并提供更好的支持;加入了比如 annotation 等等的新特性;
對 JMX 定義的優(yōu)化,在進(jìn)一步強(qiáng)化 MBean 擴(kuò)充性好的優(yōu)點的同時,盡量改變(用戶普遍認(rèn)為的)MBean 很難實現(xiàn)的缺點;
對非 Java 平臺客戶端的支持。這將是一個令人振奮的新特性;
具體的擴(kuò)展可能包括:
層次性的命名域(Hierarchical namespace);
新的事件服務(wù)功能;
對 locales 的新支持;
為 MBean 啟用 annotation 服務(wù);
也可以使用用戶類型的 mapping 了;
可以看到,JMX 的進(jìn)一步發(fā)展主要關(guān)注的是可擴(kuò)展性、動態(tài)性和易用性等 Java 用戶非常關(guān)注的方面。
回頁首
總結(jié)
在 Java SE 5 出現(xiàn)的 JMX 在 Java SE 6 中有了更多的功能和擴(kuò)展能力,這很好地適應(yīng)了 Java 語言的發(fā)展和用戶的要求,讓 Java 的監(jiān)測、管理的的功能更加強(qiáng)大。
參考資料
閱讀 Java SE 6 新特性系列 文章的完整列表,了解 Java SE 6 其它重要的增強(qiáng)。
Java 理論與實踐: 用 JMX 檢測應(yīng)用程序 (developerWorks,Brian Goetz,2006 年 10 月):這篇實踐性的文章介紹了如何使用 Java SE 5 中 JMX API 來檢測 Web 服務(wù)器和應(yīng)用程序。
從黑箱到企業(yè) 系列(developerWorks,Sing Li,2002 年):這是一個分為三部分的系列文章,介紹 Java 管理擴(kuò)展(Java Management Extension ,JMX)。
擴(kuò)展 Spring 的 JMX 支持 (developerWorks,Claude Duguay,2005 年 11 月):本文介紹了 Spring 1.2 中包括高級的 JMX 集成支持。
Java SE 6 文檔:Java SE 6 的規(guī)范文檔,可以找到絕大部分新特性的官方說明。
NTLM 身份驗證 微軟 TechNet 相關(guān)介紹 NTLM 的文章
RFC 2109、RFC 2965:關(guān)于 Cookie 的兩個 RFC
作者簡介
呂晶,目前就職于 IBM 中國開發(fā)中心 Harmony 開發(fā)團(tuán)隊,負(fù)責(zé)類庫開發(fā)工作。 對開源軟件,文史哲和新鮮事物均抱有濃厚的興趣。您可以通過 lvjing@cn.ibm.com 聯(lián)系到他。
李夷磊,Apache Harmony Project Committer,目前就職于 IBM 中國開發(fā)中心 Harmony 開發(fā)團(tuán)隊,主要負(fù)責(zé)類庫開發(fā)的技術(shù)工作,對 Java,OS 以及 system programming 有濃厚的興趣。
jwebee
我的個人網(wǎng)站
posted on 2007-07-25 12:25
周行 閱讀(1043)
評論(0) 編輯 收藏 所屬分類:
IT技術(shù)