JVM性能提升50%,聊一聊背后的秘密武器Alibaba Dragonwell
簡介:?你要知道的關(guān)于Alibaba Dragonwell一些重要優(yōu)化措施。
今年四月五日,阿里云開放了新一代ECS實(shí)例的邀測[1],Alibaba Dragonwell也在新ECS上進(jìn)行了極致的優(yōu)化。相比于之前的dragonwell_11.0.8.3版本,即將發(fā)布的dragonwell_11.0.11.6在SPECjbb2015[2] composite模式測試中,系統(tǒng)吞吐量max-jOPS提升55%,響應(yīng)時(shí)間約束下的系統(tǒng)吞吐量critical-jOPS提升602%。
如下圖所示,圖中數(shù)據(jù)做了歸一化處理,以11.0.8.3_GA的critical-jOPS為1個(gè)基準(zhǔn)單位。測試環(huán)境:阿里云80核,256g內(nèi)存ECS實(shí)例,操作系統(tǒng)為Alinux3 [3]。
Alibaba Dragonwell
過去的十幾年中,Java在阿里巴巴內(nèi)部迅猛發(fā)展。阿里內(nèi)使用Java語言編寫的應(yīng)用越來越多,數(shù)萬的Java開發(fā)者每年產(chǎn)出超過十億行Java代碼,這些代碼都運(yùn)行在阿里巴巴內(nèi)部的OpenJDK定制版AJDK上。
Alibaba Dragonwell是AJDK的開源版[4](github鏈接見文章末尾),使用和OpenJDK一樣的License,并永久免費(fèi)。Alibaba Dragonwell有8和11兩個(gè)版本,于2019年開源,當(dāng)時(shí)僅支持x86-64架構(gòu),在2020年擴(kuò)展到AArch64平臺(tái)。
Alibaba Dragonwell結(jié)合阿里在線電商、金融、物流等各個(gè)業(yè)務(wù)場景做了大量細(xì)致優(yōu)化,添加了協(xié)程/多租戶/Jwarmup等諸多自研特性,并且在阿里云超大規(guī)模的服務(wù)器集群上經(jīng)受了長時(shí)間大規(guī)模的驗(yàn)證。
調(diào)優(yōu)方案與工具
由于SPECjbb2015動(dòng)輒就需要兩個(gè)小時(shí)才能得到一次完整的跑分分?jǐn)?shù),為了壓榨性能調(diào)優(yōu)單位時(shí)間內(nèi)我們所能獲得的信息量和性能試驗(yàn)的效率,我們開發(fā)了自動(dòng)測試平臺(tái)和性能分析工具來輔助SPECjbb2015性能調(diào)優(yōu),并且這套方法可以用在未來更多類似的性能調(diào)優(yōu)案例中。
自動(dòng)測試平臺(tái)可以自動(dòng)發(fā)起測試,并且在測試過程中調(diào)用基于perf的性能分析工具來采集CPU微架構(gòu)數(shù)據(jù)以及系統(tǒng)熱點(diǎn)數(shù)據(jù),從而收集到每次實(shí)驗(yàn)過程中的關(guān)鍵性能數(shù)據(jù),并將數(shù)據(jù)存檔以可視化界面的形式展現(xiàn),方便未來回顧和分析。
同時(shí)為了避免SPECjbb2015單次實(shí)驗(yàn)耗時(shí)長影響效率,跑性能實(shí)驗(yàn)時(shí)我們采用了SPECjbb2015特殊的PRESET模式。該模式下可以指定壓力指定時(shí)間來啟動(dòng)性能測試,不僅方便調(diào)優(yōu)系統(tǒng)進(jìn)行性能采集,還可以觀察在一定壓力下SPECjbb2015的系統(tǒng)熱點(diǎn)和微架構(gòu)數(shù)據(jù)情況。
我們通過該套調(diào)優(yōu)系統(tǒng)獲取到了Alibaba Dragonwell和其他JDK在跑SPECjbb2015時(shí)的熱點(diǎn)和微架構(gòu)數(shù)據(jù),并且發(fā)現(xiàn)了諸多優(yōu)化機(jī)會(huì),如在GC熱點(diǎn)和暫停時(shí)間上有較為明顯的問題,從而深入到相關(guān)代碼,并以性能數(shù)據(jù)為線索解決了相關(guān)的性能問題,具體的技術(shù)細(xì)節(jié)將在下文中向大家一一道來。
GC暫停時(shí)間優(yōu)化
這項(xiàng)優(yōu)化源于一個(gè)出人意料的發(fā)現(xiàn),在SPECjbb2015中GC暫停時(shí)間竟然超過了總運(yùn)行時(shí)間的20%,并且穩(wěn)定復(fù)現(xiàn)。
通過上一小節(jié)中提到的調(diào)優(yōu)系統(tǒng),定位到出問題的是一個(gè)GC任務(wù)隊(duì)列相關(guān)函數(shù),并且明確的指向了原子Compare and Swap(CAS)相關(guān)代碼。
新ECS采用的CPU架構(gòu)中CAS主要有如下的兩種實(shí)現(xiàn)方式:
- 使用帶load-aquire和store-release語義的指令對的實(shí)現(xiàn)方式
- LSE指令集中的CAS專項(xiàng)指令
多數(shù)JVM在GC中使用第一種方法,然而第二種在高沖突的情況下性能更加出色,因此Dragonwell改變了編譯方式,使用LSE指令集實(shí)現(xiàn)CAS,有效的減少了暫停時(shí)間。下圖展示了優(yōu)化效果,我們采集了SPECjbb2015運(yùn)行在不同核數(shù)上的GC數(shù)據(jù),并采用吞吐量作為衡量GC性能的指標(biāo)。 ? ?
吞吐量 = (運(yùn)行時(shí)間 – Stop-The-World時(shí)間)/運(yùn)行時(shí)間 * 100%
我們可以看到優(yōu)化前的CAS方式會(huì)造成吞吐量隨使用的核數(shù)增加而劇烈下降,在80核的情況下甚至不足80%,而使用LSE CAS后吞吐量穩(wěn)定在99%以上。
對這個(gè)優(yōu)化的另外兩點(diǎn)補(bǔ)充說明:
1. 此改動(dòng)只針對JVM內(nèi)部的CAS實(shí)現(xiàn),不包括JIT(Just-In-Time)生成的代碼。JIT會(huì)動(dòng)態(tài)檢查硬件特性,在支持LSE指令集的系統(tǒng)上會(huì)優(yōu)先使用LSE指令集。
2. 除了使用LSE CAS外,改變GC隊(duì)列算法減少CAS也可以達(dá)到減少暫停時(shí)間的效果,OpenJDK社區(qū)在新版本中采用了這種方法。不過兩種辦法并不沖突,Alibaba Dragonwell同時(shí)采用了兩種優(yōu)化,達(dá)到了最優(yōu)效果。
快速序列化
Alibaba Dragonwell在保證兼容性基礎(chǔ)上對java原生序列化進(jìn)行了優(yōu)化,通過緩存大幅提高了性能。通過分析發(fā)現(xiàn), 原生序列化瓶頸大多在于大量的class 查找,如在反序列化時(shí)需要獲取對端類定義的元信息等。引入了一層通過類全限定名和類加載器映射到j(luò)ava類對象的緩存,減少了大量Class.forName的調(diào)用。
具體做法:在反序列化時(shí)獲取到類描述符,再根據(jù)類描述符查找信息時(shí)將會(huì)受限從classCache中查找,命中則立即返回,如果沒有找到當(dāng)前classloader和類全限定名唯一指定的類對象,將會(huì)走默認(rèn)的類查找流程并且將結(jié)果緩存。同時(shí), 在反序列化時(shí)會(huì)大量調(diào)用latestUserDefinedLoader 來查找首個(gè)用戶定義的類加載器,因?yàn)榇诉^程較重(涉及一次JNI調(diào)用和爬棧)也進(jìn)行了緩存。
指令融合
指令融合是指將多個(gè)指令使用效率更高的一條或者幾條指令進(jìn)行替換從而提高性能。
Dragonwell對內(nèi)存屏障/內(nèi)存讀寫/比較跳轉(zhuǎn)等多個(gè)場景做了優(yōu)化,由于篇幅限制而且此類優(yōu)化原理較為類似,在此僅舉一例,三條指令融合成一條,如下圖所示。
上面介紹了Alibaba Dragonwell內(nèi)部的一些優(yōu)化,下面我們換一個(gè)角度,從參數(shù)調(diào)優(yōu)方面介紹對SPECjbb2015的優(yōu)化。
大內(nèi)存系統(tǒng)開啟壓縮指針
SPECjbb2015是一個(gè)內(nèi)存敏感型的測試,壓縮指針對SPECjbb2015分?jǐn)?shù)的提升非常明顯。不過默認(rèn)情況下使用壓縮指針最大只能用32g內(nèi)存,這對80核的系統(tǒng)來說實(shí)在是太小了。其實(shí)通過適當(dāng)?shù)膮?shù)組合,我們完全可以在更大的內(nèi)存中使用壓縮指針。
首先我們了解下壓縮指針的基本原理。如上圖所示,由于Java對象有明確的對齊要求,因此對象的地址必然由數(shù)個(gè)0結(jié)尾,0的個(gè)數(shù)由對齊位數(shù)決定。省略java對象地址結(jié)尾的數(shù)個(gè)0可解決內(nèi)存而且不會(huì)丟失有效地址信息,需要訪問對象時(shí)可以通過補(bǔ)0獲得完整的地址。
由此可知,我們可以通過調(diào)整Java對象對齊位數(shù)控制壓縮指針生效的最大內(nèi)存。默認(rèn)情況下Java為8字節(jié)對齊(3bit),加上壓縮指針本身的的32bit,最多只能表示32g內(nèi)存。但如果調(diào)整為32字節(jié)對齊,那么有37bit可以使用,也就是128g,這對于80核來說基本上夠用了。
分層編譯調(diào)優(yōu)
分層編譯是JVM最基礎(chǔ)的機(jī)制之一,一般情況下對它改動(dòng)比較少,不過在SPECjbb2015的場景下,在分層編譯上仍有調(diào)優(yōu)空間。首先介紹下分層編譯。JVM在運(yùn)行的時(shí)候動(dòng)態(tài)的將字節(jié)碼編譯成機(jī)器碼執(zhí)行,JVM(hotspot)內(nèi)部編譯引擎主要有三個(gè):
這三個(gè)編譯引擎相互配合,執(zhí)行次數(shù)較少的代碼由解釋器和C1負(fù)責(zé),C2只編譯熱點(diǎn)代碼,從而讓Java可以達(dá)到峰值性能與編譯開銷的平衡,使應(yīng)用運(yùn)行更加平滑。
不過分層編譯也有自己的缺點(diǎn),一個(gè)較為明顯的問題是它會(huì)增大生成代碼的總量。下圖展示SPECjbb2015運(yùn)行時(shí)C1/C2編譯方法數(shù)目。
圖中Level1-3均為C1編譯,根據(jù)收集運(yùn)行信息的力度不同分為了三個(gè)等級(jí),Level4為C2編譯。我們可以看到C1編譯了70%的方法,因此關(guān)閉分層編譯,僅保留C2編譯器可以減少生成代碼,從而一定程度上提高高速緩存和葉表命中率。
對于SPECjbb2015來說,由于分?jǐn)?shù)只取決于最后幾分鐘的峰值處理能力,前面大概兩個(gè)小時(shí)的請求爬升階段都可以視作預(yù)熱,因此啟動(dòng)期的編譯開銷并不關(guān)鍵。我們可以關(guān)閉分層編譯來減少生成代碼,提高高速緩存和列表命中率。最終在測試中發(fā)現(xiàn)關(guān)閉分層編譯生成代碼總量由29M降低到9M,有明顯減少。
本文總結(jié)了Alibaba Dragonwell的一些重要優(yōu)化措施,請注意阿里承諾會(huì)持續(xù)的優(yōu)化Dragonwell性能,同時(shí)更緊密地和OpenJDK等開源社區(qū)協(xié)作,貢獻(xiàn)更多的定制化特性,促進(jìn)Java技術(shù)的持續(xù)發(fā)展。
引用
[1] https://www.aliyun.com/daily-act/ecs/ecs_arm
[2] SPECjbb2015是一款模擬電商應(yīng)用的權(quán)威基準(zhǔn)測試程序,包含了購買下單、折扣優(yōu)惠、庫存計(jì)算、客戶數(shù)據(jù)存儲(chǔ)與分析等典型電商應(yīng)用行為:https://www.spec.org/jbb2015/
[3]Alinux3:Alibaba Cloud Linux是阿里云推出的Linux發(fā)行版,它為云上應(yīng)用程序環(huán)境提供Linux社區(qū)的最新增強(qiáng)功能,在提供云上最佳用戶體驗(yàn)的同時(shí),也針對阿里云基礎(chǔ)設(shè)施做了深度的優(yōu)化https://help.aliyun.com/document_detail/212631.html
[4] Alibaba Dragonwell是阿里巴巴開源JDK:https://github.com/alibaba/dragonwell8https://github.com/alibaba/dragonwell11
云上年中鉅惠注冊抽好禮!
8月31日前,用戶注冊登錄阿里云即可抽iPhone12 Pro、Cherry機(jī)械鍵盤、天貓精靈等好禮!馬上點(diǎn)此免費(fèi)抽獎(jiǎng):http://click.aliyun.com/m/1000289891/
原文鏈接
本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的JVM性能提升50%,聊一聊背后的秘密武器Alibaba Dragonwell的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 双系统安装ubuntu后没有window
- 下一篇: 双龙贺岁,龙蜥 LoongArch GA