速讀原著-Java 20 年:JVM 虛擬化技術的發展

  • 2020 年 2 月 14 日
  • 筆記

Java 20 年:JVM 虛擬化技術的發展

虛擬化技術已經有了幾十年的發展歷史,並且在硬件、操作系統層面都已經得到了廣泛的應用。虛擬化不但可以顯著節省成本,而且還可以提升管理性。同樣,虛擬化技術也可以應用在 JVM 中,以提高資源利用率,降低單應用的部署成本。早在 2004 年,Sun 公司就提出過 Java 應用虛擬化的設想,並且還制定過兩個JSR 規範。那現在JVM 虛擬化技術發展到了哪一步?基於JVM 的虛擬化技術在實現過程中有哪些難點?為了回答這些問題,InfoQ 採訪了 JVM 專家李三紅。

定義以及歷史

InfoQ:能介紹下什麼是 JVM 的虛擬化嗎?JVM 的虛擬化價值在哪裡?

李三紅:傳統的 Java 應用部署模式,一般遵循「硬件->操作系統->JVM->Java 應用」這種自底向上的部署結構,其中 Java EE 應用可以細化為「硬件->操作系統->JVM->JavaEE 容 器->JavaEE 應用」的部署結構。這種部署結構往往比較重,操作系統、JVM 和 JavaEE 容器造成的 overhead 很高,而很多時候一個 Java 應用並不需要跑滿整個硬件的資源,導致這種模式的資源利用率是比較低的。 而另一方面,硬件虛擬化技術逐漸成熟:VMware Hypervisor、Xen、KVM、Power LPAR 等技術能夠幫助我們在同一個硬件上部署多個操作系統實例(每個操作系統實例可以理解為宿主機的租戶),而時下流行的 OS Container 技術如 LXC、Docker 等,則是把操作系統虛擬化為多個實例,實現更輕量級的虛擬化。無論哪個層面的虛擬化,其目的都是對資源利用率更加高效的追求。 同樣的思路,我們也可以在 JVM 層面,或者容器框架層面做虛擬化,類似於 Hypervisor 或者OS Container,讓虛擬化的JVM/容器框架可以支持多租戶的運行模式,這是比 OS 虛擬化更高一層的做法:

如上圖,從左到右來看,隨着虛擬化層次的提高,從 Hardware 到 OS,到 JVM,再到容器, 單個租戶應用的部署成本也在下降, 最右邊的「 多租戶」 的 JavaEE Container (Multitenant-Container)是在容器框架層面的虛擬化,可以支持更高密度的應用部署,而不是傳統的APP : Container = 1:1 的部署方式。 什麼是單個租戶應用部署成本?舉一個簡單的例子,在沒有虛擬化之前,傳統的部署模式,一個 JavaEE 應用需要獨佔所有的硬件資源(CPU、MEM、網絡等)。Hypervisor 的出現,使得一個共享的硬件資源上可以同時跑多個 OS,這種資源使用上的節約本質上是通過 Over-Commit(即允許租戶超量使用物理資源)來達到的,即我們假設跑在同一個虛擬化環境的不同租戶不會在同一個時間消費同樣的資源。同樣的道理可以來理解 JVM/容器框架的虛擬化。 多個JavaEE 應用可以部署在同一個JVM/容器內,但邏輯上它們各自會認為是運行在一個獨立的JVM/容器內,從而可以更大程度的提高資源利用率,降低單應用的部署成本。

InfoQ:多租戶 JVM 的概念是什麼時候出現的?能聊聊它的發展歷史嗎?

李三紅:早在 2004 年,Sun 公司就提出過 JVM 虛擬化這方面的想法,當時 Grzegorz Czajkowski 領導了一個叫做巴塞羅那的研究項目,該項目基於 Java HotSpot 虛擬 1.5 版本開發了 Multi-Tasking Virtual Machine(MVM)。MVM 旨在提高 Java 程序的啟動速度, 節省內存開銷。不過自從 Sun 被甲骨文收購後,我們沒有聽到關於該項目的任何新的進展。儘管沒有看到 MVM 成功產品化,不過它卻留下兩個重要的 JSR(Java Specification Request)規範:JSR121 和 JSR284。JSR284 目前在 java.net 上有一個實現它的孵化項目jsr284-ri-tck(ri: Reference Implementation, tck: Test Compatible Kit)。 從 2009 年開始,IBM Java 團隊也開始着手研究 JVM 的虛擬化技術,並於 2013 年發佈第一個基於 IBM J9 虛擬機的 Bata 版本。IBM Multi-tenant JVM 是JVM 層面的虛擬化,其思路是把多個標準的Java 應用運行在同一個JVM上,讓這些應用共享底層的GC、JIT、Java 運行時庫等基礎組件。 Waratek 也在 2012 年的 Red Hat 技術峰會上發佈了 CloudVM Beta 版本,支持多租戶。與IBM Multi-tenant JVM 類似,Waratek 允許多個應用運行在同一個 CloudVM 上,每一個應用運行在一個叫Java Virtual Container(JVC)的容器里。

應用場景以及發展前景

InfoQ:JVM 虛擬化最適合應用在什麼場景中?

李三紅:虛擬化的本質就是把本來獨佔的資源共享出來,即在A 不需要的時候,B 可以拿 來用,從而提高資源的利用率。 如果我們能把獨佔資源的應用,通過 JVM 的虛擬化的能力,同時部署在同一個「多租戶」JVM 里,或者是同一個「多租戶」容器里, CPU、Heap 這些資源就可以極大程度地共享了,部署的密度也就可以成倍的提高,其結果就是單應用的部署成本成倍的下降。打個簡單的比喻,如果按照 1:1 的部署密度,機器的成本是 1000 台,如果我們能把部署的密度提高到 1:10,機器的成本就是 1000/10=100 台。 多租戶的 JVM 或者容器,其最大的應用場景就是高密度的應用部署場景。也許有人有疑問,OS 虛擬化也可以提高部署密度, 為什麼要選擇JVM 虛擬化? 我們就拿 Docker 作為一個例子來比較一下。比如利用 Docker 可以把運行在同一個實際操作系統上的單個 JVM 進程互相隔離,每個 JVM 進程可以看作是實際操作系統的一個租戶,下面是一個簡化的例子(先不考慮複雜的 OS 內存交換場景):

左圖表示在 OS 之上,使用 Docker 虛擬出來兩個租戶,即兩個獨立的 JVM 進程分別運行在兩個隔離的Docker 容器里。右圖則表示JVM/容器的虛擬化方案。在Docker 的方案里, 由於兩個 App1 和 App2 是跨 JVM 進程的,所以 Heap 資源對於它們來說不是共享的,很難在Heap 內存在App1 不使用的時候,可以拿來給App2 使用,這個就是一個限制Docker 這種方案部署密度的因素,比如你有 8G 內存,你可能會選擇部署兩個Docker 容器,每個4G。而這個因素對於 JVM 虛擬化方案,則不存在這樣的限制,因為所有的 App 都是在一個進程里的,Heap 對大家來說都是共享的,完全可以通過合理的安排選擇部署更多的App。

InfoQ:你認為多租戶 JVM 的前景如何?為什麼現在做多租戶 JVM 的廠商這麼少?

李三紅:在 IBM 的時候,其實我們內部有過很多次的討論。如果我們從虛擬化的這個角 度來看,從硬件, 到OS, 再到JVM, 以及容器, JVM 的虛擬化(多租戶JVM)以及容器的虛擬化(多租戶容器)是一個技術的發展趨勢。但是,現實的情況是,根據我們這些年在這個領域的經驗與積累,基於傳統的 JVM 實現 JVM 虛擬化,技術上碰到的很多的挑戰,其中一些的確難於在短期內找到一個好的解決方案。(關於裏面的一些實現細節,讀者可以參考我之前的文章,高密度 Java 應用部署的一些實踐) 。簡單列舉一個例子,在多租戶JVM 中,每一個租戶都有自己獨立的 Region, 但是如果租戶與租戶之間出現交叉引用的情況,就會導致 object leakage,這個是我們內部使用的一個技術術語。其結果是,在某些條件下,某個租戶退出 Region 不能合理釋放。這個問題頭痛的地方在於, 每次 Java class library 的代碼改動,都有可能造成新的 object leakage。類似這樣的問題, 需要 Java Class Library 開發者和多租戶 JVM 之間有一種約定,或者範式來共同約束解決這類問題。 我們再來談第二個問題。 就像你說的,目前做多租戶 JVM 的廠商的確很少,事實上本來做商業JVM 的廠商也就那麼幾家。IBM J9 是比較早切入這個領域的JVM,主要是由中國和加拿大的團隊一起開發, IBM 也只是做了 JVM 這層的虛擬化,並沒有支持到容器級別。不過據我所知, 這個項目已經停了, 停的原因可能很多,我個人認為主要的原因是: 第一,IBM 沒有真實的應用場景來檢視高密度部署的實際價值。第二,資源和優先級上的考慮,Java 技術中心有更重要的東西來做。不過到目前為止,IBM 好像還沒有在正式場合公布這個東西。 如果我們廣義上來談JVM 虛擬化,而不要局限於多租戶JVM(即一個JVM 上跑多個Java 應用的場景), 我個人覺得 JVM 虛擬化技術在高密度部署領域是有非常大的價值,尤其是在雲計算大行其道的當今, 我想這也是 Waratek 一直所信奉的。 這裡談到應用的前景,我想有兩個問題值得再深入考慮: 第一,在雲計算的環境下為 JVM 虛擬化找到高密度部署的應用場景,單個租戶應用部署成本是關鍵的考量因素。第二,基於特定的場景,規避一些技術實現上難點。

Java 語言的發展

InfoQ:一晃眼,Java 就已經 20 歲了,你認為 Java 的發展經歷了哪幾個階段?

李三紅: James Gosling 帶領團隊在 1991 年開始了一個叫"Oak"的項目,這個就是 Java 的 前身。1995 年,Java1.0 發佈。「Write once, run anywhere" 這句 Java 口號想必大家耳熟能詳。Java 剛開始出現的時候主要面向 Interactive Television 領域,直至後來幾年的發展, SUN 一度想用 Java 來打造桌面的網絡操作系統,取代當時如日中天的 Windows。不過不曾想,Java 雖未在Embedded、Desktop 領域內取得多大的建樹,出乎意料地,卻在企業級應用領域開花結果,佔據了如今幾乎統治的地位。失之東隅,卻收之桑榆。 Sun 在 2006 年的Java One 大會上,宣布Java 技術開源,隨後年底的時候在GPL 協議下發佈 HotSpot 以及 javac,這是 Java 發展中的里程碑事件。從 2006 到 2010 年,這期間 SUN 一路磕磕絆絆,儘管手握 Java 這個金礦,但在商業上一直找不到好的盈利點,直到 2010 被 Oracle 收購。 2010 年,也是Java 發展的一個重要的分水嶺,Java 面臨分家的風險, 一方是 Apache Harmony 為代表的, 其後是 IBM 的支持, 另一方是 OpenJDK 及其背後的Oracle。最後博弈的結果現在大家都知道了, IBM 轉向 OpenJDK,Apache Harmony 也結束了它的歷史使命,被Apache 之後束之高閣。Harmony 為 IBM 在Java 上贏得的應有的話語權,另外一個副產品,就是給移動端Android 平台貢獻了Java 核心類庫代碼。2010 年是Java 重生的一年。隨後 2011 年OpenJDK 7 發佈, OpenJDK 7 是第一個Java SE 的引用實現。

InfoQ:反過頭來看,你認為為什麼 Java 能夠如此成功?

李三紅: 好像有這麼一句話,原話不太記得了,一流的公司建生態,二流的公司定標 准,三流的公司賣產品。這句話也可以用在Java 上。Java 的成功,離不開逐步完善,日臻成熟的 Java 技術生態圈,這個是遠遠超出語言層面優劣的東西。 在產品的選型上,無論縱向上,還是橫向上,以 Java 技術構建的產品都有着無比的豐富性,Apache 社區的繁榮,可以作為這個故事的佐證。這個也是許多小眾語言諸如Scala、JRuby願意選擇運行在JVM 上的原因。 如果單從語言這個層面,談論 Java 的成功,我就借用 Mark Reinhold 的一句總結,四個詞概括 Java 的特徵:Readability、Simplicity、 Universality 和 Compatibility。這也是 Java 語言能夠風行,並被大家所接受的重要因素。