
今年四月五日,阿裡雲開放了新一代ECS執行個體的邀測[1],Alibaba Dragonwell也在新ECS上進行了極緻的優化。相比于之前的dragonwell_11.0.8.3版本,即将釋出的dragonwell_11.0.11.6在SPECjbb2015[2] composite模式測試中,系統吞吐量max-jOPS提升55%,響應時間限制下的系統吞吐量critical-jOPS提升602%。
如下圖所示,圖中資料做了歸一化處理,以11.0.8.3_GA的critical-jOPS為1個基準機關。測試環境:阿裡雲80核,256g記憶體ECS執行個體,作業系統為Alinux3 [3]。
Alibaba Dragonwell
過去的十幾年中,Java在阿裡巴巴内部迅猛發展。阿裡内使用Java語言編寫的應用越來越多,數萬的Java開發者每年産出超過十億行Java代碼,這些代碼都運作在阿裡巴巴内部的OpenJDK定制版AJDK上。
Alibaba Dragonwell是AJDK的開源版[4](github連結見文章末尾),使用和OpenJDK一樣的License,并永久免費。Alibaba Dragonwell有8和11兩個版本,于2019年開源,當時僅支援x86-64架構,在2020年擴充到AArch64平台。
Alibaba Dragonwell結合阿裡線上電商、金融、物流等各個業務場景做了大量細緻優化,添加了協程/多租戶/Jwarmup等諸多自研特性,并且在阿裡雲超大規模的伺服器叢集上經受了長時間大規模的驗證。
調優方案與工具
由于SPECjbb2015動辄就需要兩個小時才能得到一次完整的跑分分數,為了壓榨性能調優機關時間内我們所能獲得的資訊量和性能試驗的效率,我們開發了自動測試平台和性能分析工具來輔助SPECjbb2015性能調優,并且這套方法可以用在未來更多類似的性能調優案例中。
自動測試平台可以自動發起測試,并且在測試過程中調用基于perf的性能分析工具來采集CPU微架構資料以及系統熱點資料,進而收集到每次實驗過程中的關鍵性能資料,并将資料存檔以可視化界面的形式展現,友善未來回顧和分析。
同時為了避免SPECjbb2015單次實驗耗時長影響效率,跑性能實驗時我們采用了SPECjbb2015特殊的PRESET模式。該模式下可以指定壓力指定時間來啟動性能測試,不僅友善調優系統進行性能采集,還可以觀察在一定壓力下SPECjbb2015的系統熱點和微架構資料情況。
我們通過該套調優系統擷取到了Alibaba Dragonwell和其他JDK在跑SPECjbb2015時的熱點和微架構資料,并且發現了諸多優化機會,如在GC熱點和暫停時間上有較為明顯的問題,進而深入到相關代碼,并以性能資料為線索解決了相關的性能問題,具體的技術細節将在下文中向大家一一道來。
GC暫停時間優化
這項優化源于一個出人意料的發現,在SPECjbb2015中GC暫停時間竟然超過了總運作時間的20%,并且穩定複現。
通過上一小節中提到的調優系統,定位到出問題的是一個GC任務隊列相關函數,并且明确的指向了原子Compare and Swap(CAS)相關代碼。
新ECS采用的CPU架構中CAS主要有如下的兩種實作方式:
- 使用帶load-aquire和store-release語義的指令對的實作方式
- LSE指令集中的CAS專項指令
多數JVM在GC中使用第一種方法,然而第二種在高沖突的情況下性能更加出色,是以Dragonwell改變了編譯方式,使用LSE指令集實作CAS,有效的減少了暫停時間。下圖展示了優化效果,我們采集了SPECjbb2015運作在不同核數上的GC資料,并采用吞吐量作為衡量GC性能的名額。
吞吐量 = (運作時間 – Stop-The-World時間)/運作時間 * 100%
我們可以看到優化前的CAS方式會造成吞吐量随使用的核數增加而劇烈下降,在80核的情況下甚至不足80%,而使用LSE CAS後吞吐量穩定在99%以上。
對這個優化的另外兩點補充說明:
1. 此改動隻針對JVM内部的CAS實作,不包括JIT(Just-In-Time)生成的代碼。JIT會動态檢查硬體特性,在支援LSE指令集的系統上會優先使用LSE指令集。
2. 除了使用LSE CAS外,改變GC隊列算法減少CAS也可以達到減少暫停時間的效果,OpenJDK社群在新版本中采用了這種方法。不過兩種辦法并不沖突,Alibaba Dragonwell同時采用了兩種優化,達到了最優效果。
快速序列化
Alibaba Dragonwell在保證相容性基礎上對java原生序列化進行了優化,通過緩存大幅提高了性能。通過分析發現, 原生序列化瓶頸大多在于大量的class 查找,如在反序列化時需要擷取對端類定義的元資訊等。引入了一層通過類全限定名和類加載器映射到java類對象的緩存,減少了大量Class.forName的調用。
具體做法:在反序列化時擷取到類描述符,再根據類描述符查找資訊時将會受限從classCache中查找,命中則立即傳回,如果沒有找到目前classloader和類全限定名唯一指定的類對象,将會走預設的類查找流程并且将結果緩存。同時, 在反序列化時會大量調用latestUserDefinedLoader 來查找首個使用者定義的類加載器,因為此過程較重(涉及一次JNI調用和爬棧)也進行了緩存。
指令融合
指令融合是指将多個指令使用效率更高的一條或者幾條指令進行替換進而提高性能。
Dragonwell對記憶體屏障/記憶體讀寫/比較跳轉等多個場景做了優化,由于篇幅限制而且此類優化原理較為類似,在此僅舉一例,三條指令融合成一條,如下圖所示。
上面介紹了Alibaba Dragonwell内部的一些優化,下面我們換一個角度,從參數調優方面介紹對SPECjbb2015的優化。
大記憶體系統開啟壓縮指針
SPECjbb2015是一個記憶體敏感型的測試,壓縮指針對SPECjbb2015分數的提升非常明顯。不過預設情況下使用壓縮指針最大隻能用32g記憶體,這對80核的系統來說實在是太小了。其實通過适當的參數組合,我們完全可以在更大的記憶體中使用壓縮指針。
首先我們了解下壓縮指針的基本原理。如上圖所示,由于Java對象有明确的對齊要求,是以對象的位址必然由數個0結尾,0的個數由對齊位數決定。省略java對象位址結尾的數個0可解決記憶體而且不會丢失有效位址資訊,需要通路對象時可以通過補0獲得完整的位址。
由此可知,我們可以通過調整Java對象對齊位數控制壓縮指針生效的最大記憶體。預設情況下Java為8位元組對齊(3bit),加上壓縮指針本身的的32bit,最多隻能表示32g記憶體。但如果調整為32位元組對齊,那麼有37bit可以使用,也就是128g,這對于80核來說基本上夠用了。
分層編譯調優
分層編譯是JVM最基礎的機制之一,一般情況下對它改動比較少,不過在SPECjbb2015的場景下,在分層編譯上仍有調優空間。首先介紹下分層編譯。JVM在運作的時候動态的将位元組碼編譯成機器碼執行,JVM(hotspot)内部編譯引擎主要有三個:
- 解釋器:無編譯開銷,但解釋執行效率很低。
- C1編譯器:編譯開銷較低,生成代碼品質一般。
- C2編譯器:生成代碼品質很高,但編譯開銷很高。
這三個編譯引擎互相配合,執行次數較少的代碼由解釋器和C1負責,C2隻編譯熱點代碼,進而讓Java可以達到峰值性能與編譯開銷的平衡,使應用運作更加平滑。
不過分層編譯也有自己的缺點,一個較為明顯的問題是它會增大生成代碼的總量。下圖展示SPECjbb2015運作時C1/C2編譯方法數目。
圖中Level1-3均為C1編譯,根據收集運作資訊的力度不同分為了三個等級,Level4為C2編譯。我們可以看到C1編譯了70%的方法,是以關閉分層編譯,僅保留C2編譯器可以減少生成代碼,進而一定程度上提高高速緩存和葉表命中率。
對于SPECjbb2015來說,由于分數隻取決于最後幾分鐘的峰值處理能力,前面大概兩個小時的請求爬升階段都可以視作預熱,是以啟動期的編譯開銷并不關鍵。我們可以關閉分層編譯來減少生成代碼,提高高速緩存和清單命中率。最終在測試中發現關閉分層編譯生成代碼總量由29M降低到9M,有明顯減少。
本文總結了Alibaba Dragonwell的一些重要優化措施,請注意阿裡承諾會持續的優化Dragonwell性能,同時更緊密地和OpenJDK等開源社群協作,貢獻更多的定制化特性,促進Java技術的持續發展。
引用
[1]
https://www.aliyun.com/daily-act/ecs/ecs_arm[2] SPECjbb2015是一款模拟電商應用的權威基準測試程式,包含了購買下單、折扣優惠、庫存計算、客戶資料存儲與分析等典型電商應用行為:
https://www.spec.org/jbb2015/[3]Alinux3:Alibaba Cloud Linux是阿裡雲推出的Linux發行版,它為雲上應用程式環境提供Linux社群的最新增強功能,在提供雲上最佳使用者體驗的同時,也針對阿裡雲基礎設施做了深度的優化
https://help.aliyun.com/document_detail/212631.html[4] Alibaba Dragonwell是阿裡巴巴開源JDK:
https://github.com/alibaba/dragonwell8 https://github.com/alibaba/dragonwell11(完)
加入龍蜥社群
加入微信群:添加社群助理-龍蜥社群小龍(微信:openanolis_assis),備注【龍蜥】拉你入群;加入釘釘群:可掃碼或搜釘釘群号(33311793)。歡迎開發者/使用者加入龍蜥OpenAnolis社群交流,共同推進龍蜥社群的發展,一起打造一個活躍的、健康的開源作業系統生态!
龍蜥社群_小龍 釘釘群二維碼
關于龍蜥社群
龍蜥社群是由企事業機關、高等院校、科研機關、非營利性組織、個人等按照自願、平等、開源、協作的基礎上組成的非盈利性開源社群。龍蜥社群成立于2020年9月,旨在建構一個開源、中立、開放的Linux上遊發行版社群及創新平台。
短期目标是開發Anolis OS作為CentOS替代版,重新建構一個相容國際Linux主流廠商發行版。中長期目标是探索打造一個面向未來的作業系統,建立統一的開源作業系統生态,孵化創新開源項目,繁榮開源生态。
加入我們,一起打造面向未來的開源作業系統!
Https://openanolis.cn