天天看點

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

Java 語言的垃圾回收機制(即 GC )是提高 Java 代碼開發效率的利器,然而 GC 引發的暫停往往嚴重影響 Java 業務的響應時間。Java11 引入了毫秒級暫停的 ZGC(The Z Garbage Collector),給 Java 業務響應時間的優化帶來福音,成為衆多業務從 Java8 切換到 Java11 的理由之一。

阿裡巴巴維護的 Alibaba Dragonwell 11是一款免費且生産就緒的 OpenJDK 11 發行版,提供了性能增強和安全修複的長期支援。早在第一版釋出時,Dragonwell 11 應阿裡内部業務和雲上客戶的需求,預設提供了 Java 11 的實驗性(experimental)ZGC 特性。随着 ZGC 進入生産實踐而逐漸落地,阿裡業務和雲上客戶享受到響應時間的優化的過程中也遭遇到了一些實際問題。正因為如此,阿裡巴巴釋出了 Dragonwell11.0.11.7 ,其中的 ZGC 特性由 OpenJDK 11 中的實驗特性改造為生産就緒(production-ready)特性,同時保證 Dragonwell 11 長期支援的品質穩定性。

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

本篇開啟 Alibaba Dragonwell ZGC 系列的技術分享,介紹 Alibaba Dragonwell11 上的 ZGC:本系列共計 3 篇文章,本篇将介紹 GC 的基本概念和 ZGC 的規模化實踐,第二篇将介紹 ZGC 的原理和調優,第三篇将介紹 Dragonwell 對于 ZGC 的生産就緒改造。

Java GC簡介

垃圾回收 GC 是 Java 語言的自動記憶體管理機制,能夠自動銷毀垃圾對象(不再能夠被引用的對象),進而釋放記憶體以供後續使用。在 GC 的幫助下,Java 開發者隻需專注在自身業務邏輯,調用 new 語句建立對象,而無需編寫銷毀對象的語句,進而提高了代碼開發效率和代碼品質。

GC性能名額

天下沒有免費的午餐,GC 帶來便捷的同時也帶來顯著的副作用。對于 Java 業務而言,使用者通常關心兩個名額:吞吐率 QPS(query per second,每秒可處理的請求數量)和響應時間 RT(response time)。GC 通常會對 QPS 和 RT 産生負面的影響。

GC 暫停會延長 RT,特别是長尾請求的RT P99/P999(從快到慢排名 99%/99.9% 的請求的 RT)。GC 為了保證回收算法的正确性,往往需要暫停所有正在執行業務邏輯的 Java 線程,來避免 GC 線程與配置設定對象的 Java 線程的競争。Java 線程在暫停期間無法響應任何請求,導緻業務的 RT 變長。

GC 會降低吞吐率(QPS上限)。GC 線程占用額外的 CPU 資源,進而影響 Java 線程使用 CPU 的份額。人們往往認為 GC 必然與暫停相生相伴。然而此觀點不完全正确。現代 Java 的 GC 可以啟動并發 GC 線程與 Java 線程并發執行。

絲般順滑的ZGC體驗

Java 語言提供了若幹種 GC 來适應不同的需求。這些 GC 在吞吐率和響應時間兩方面的表現有不同的特點:

  • Parallel GC:吞吐率高,GC 暫停時間長;
  • G1 GC,CMS GC:吞吐率和 GC 暫停時間都比較好,G1 GC 是 Java11 的預設 GC(目标 GC 暫停時間為 200ms),而 CMS GC 在 Java11 中已經不推薦使用;
  • ZGC,Shenandaoh GC:GC 暫停時間短,吞吐率一般。

本文的主角 ZGC 是 OpenJDK11 引入的新一代 GC,暫停時間能夠保持在 10ms 以内,且最高能支援 TB 級别的大堆。

Java11 之前的 GC 通常需要 100ms 以上的暫停,會給 RT P99 等名額帶來負面影響,讓運作中的 Java 業務仿佛在坑坑窪窪的道路上磕磕絆絆地前行。毫秒級别暫停的 ZGC 能夠讓 RT P99 進一步下降,運作中的 Java 業務得了到絲般順滑的體驗。ZGC 大多數情況下隻需要調節堆的大小和并發 GC 線程數量,調優較為容易,大大節約心智成本。

ZGC 實踐

本節在 ZGC 投入實戰之前首先介紹了 ZGC 的适用場景,目的是讓業務上線之前能夠選擇正确的 GC。我們在充分評估業務特點的基礎上,讓相應的業務運作在 ZGC 上,取得了 RT 的提升。然而 OpenJDK 11 的 ZGC 尚處于實驗性階段,我們在實踐中遇到了一些問題。我們将這些問題作為風險項記錄下來,并在 Dragonwell 11 中嘗試解決這些問題。

ZGC 适用場景

ZGC 取得了卓越的毫秒級暫停性能,然而副作用是 ZGC 可能降低業務吞吐率( ZGC 項目首頁聲稱損失至多 15% 的吞吐率)。其原因主要包括三個方面:

1.Java11 的 ZGC 是單代 GC,每一輪 ZGC 均需要處理長壽對象(多次 GC 之後依然存活的對象),而 Java11 以前的 GC 均是分代 GC,不需要每次 GC 都處理長壽對象;

2. ZGC 需要開啟并發 GC 線程,減少 Java 線程使用 CPU 的份額;

3.ZGC 的讀屏障(後文将介紹)使得每個從堆中加載對象的操作都有額外的開銷。此外,由于 ZGC 不支援壓縮指針技術,ZGC 在 32GB 以内小堆上無法享受壓縮指針帶來的性能提升。

綜合以上的 ZGC 特點的描述,筆者總結了 ZGC 适用場景,供有意切換到 ZGC 的朋友們參考:

1.對長尾請求 RT P99/P999 等名額有高要求的 Java 業務:這些業務通常要求實時響應,對最慢的 1% 或 0.1% 的請求非常敏感;

2.機器的記憶體與 CPU 資源豐富:豐富的計算資源可以開啟更大的堆和更多的并發 GC 線程;

3.可以容忍吞吐率降低:業務經過權衡後,認為 RT P99/P999 的名額比 QPS 名額更重要;

4.長壽對象相對較少:Java11 的 ZGC 尚未分代,無法高效地處理此類對象。

此外,Java 業務如果仍然運作在 Java 8 上,那麼還需要考慮到切換到 Java 11 的代價。

ZGC規模化實踐

阿裡内部許多對長尾請求 RT 有嚴格要求的 Java 業務,為了突破 GC 暫停對于 RT 的瓶頸,這些 Java 業務逐漸更新到 Java11,并且選擇 ZGC 作為 GC。下面展示了阿裡内部使用 ZGC 獲得 RT 提升的案例。本節提到的Concurrent Mark/Relocate将在本系列第二篇文章中闡述。

1.高性能資料庫:Lindorm 是阿裡内部高性能 NoSQL HBase 分支。Lindorm 在 ZGC 上穩定運作近兩年,期間順利通過雙十一大考。Lindorm 運作期間的 ZGC 暫停時間穩定在 5ms 左右,最大暫停時間不超過 8ms 。ZGC 大大改善了線上運作叢集的 RT 與毛刺名額,平均 RT 優化 15%~20%, P999 RT 減少到原先的一半以内。2019 年雙十一螞蟻叢集在 ZGC 的加持下, Lindorm RT P999 時間從 12ms 降低到了 5ms 。下圖展示了 Lindorm 在 ZGC 上的 GC 暫停表現(機關為微秒)。

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

2.消息隊列應用:RocketMQ 為了提升彈性伸縮能力,不再依賴本地檔案系統,新增支援分布式檔案系統作為存儲。RocketMQ 原先采用 G1GC,但 GC 暫停時間達到 200ms 以上,即使經過大量的調優依然無法将暫停時間降下來。經過研究發現 GC 暫停的主要因素是通路分布式檔案系統時必須基于 JNA 調用 C 語言庫,而 JNA 依賴 finalizer 回收 native 記憶體中的對象,這些對象至少經過 2 個 G1 的 GC 周期才會被回收,大量對象轉移(每次 GC 約有 50 萬對象轉移)導緻長時間的暫停。由于 ZGC 回收 native 對象是在并發階段完成的,進而避免長時間暫停。RocketMQ 僅僅設定了 ZGC 的堆大小和并發線程數量,就使得目前線上 GC 暫停時間都小于 2ms ,大大減少了系統通路的毛刺。下圖展示了 RocketMQ 使用 ZGC 之後的 RT 名額。

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

3.風控調用:線上部分應用對風控調用耗時敏感。這些應用設定的服務調用逾時時間很短(< 50ms ),而目前風控系統一次 Young GC 的耗時在 60ms 左右。隻要遇到 GC ,業務調用就會逾時。以紅包業務為例,逾時後紅包要麼發放不出去,要麼發出去但有可能被羊毛黨薅走,對業務都是有影響。為了提升可用性,需要 ZGC 的支援。線上實際運作 ZGC 的暫停時間保持在 10ms 以内,能夠滿足這些 RT 敏感的應用等需求。由于風控系統緩存對象較多,導緻 Concurrent Mark 階段時間較長,影響吞吐率提升。為了支援 ZGC 更流暢地運作,風控系統減少了緩存的長壽對象,進而提高 QPS 上限。

OpenJDK11 ZGC的風險

在以上實踐過程的早期,我們采用了 OpenJDK11 的 ZGC ,而該特性僅僅處于實驗性階段。從 OpenJDK 11 釋出實驗性 ZGC 以來, ZGC 的穩定性得以增強,功能日臻完善。到 OpenJDK 15 釋出的時候, ZGC 已經成為生産就緒的特性。OpenJDK 11 是長期支援的版本,而目前釋出的 OpenJDK12-16 都不是長期支援的,是以在生産實踐中直接部署 OpenJDK 15/16 來嘗鮮生産就緒的 ZGC 存在困難。

以上實踐表明,對于 10GB 到數百 GB 的 Java 堆,ZGC 的确能将暫停保持在 10ms 以内。然而這些業務均報告“ QPS 上不去”,也就是說對于吞吐型場景, ZGC 表現不理想。在吞吐型場景中, ZGC 的回收速度跟不上配置設定速度,出現了配置設定停頓(Allocation Stall),即暫停目前正在建立對象的線程,等待 ZGC 釋放空閑空間。另外, Lindorm 還報告小堆上的 ZGC 整體效果甚至沒有 G1GC 來得好。此外,以上實踐也遇到了一些 OpenJDK11 實驗性 ZGC 的問題:

1.無征兆的崩潰現象:Lindorm 發現兩個變量指向同一個對象時,代碼卻檢測這兩個變量不相等;RocketMQ 業務也發現程式運作期間無征兆地崩潰了。仔細排查,可發現讀屏障與加載操作相分離,中間可能進入 GC 暫停。這個情況已經在 JDK14 中修複。

2.最壞情況會發生 OOM :風控業務注意到 ZGC 可能抛出 OOM ,此現象發生在 Concurrent Relocate 階段。ZGC 通常會預留一段空間供 Concurrent Relocate,然而 JDK11 的 ZGC 代碼無法保障預留的空間是足夠的,如果對象 Relocate 速度很快,就有可能抛出 OOM 。此問題在 OpenJDK16 中解決。

3.Page Cache Flush 影響 RT :ZGC 把堆分為小/中/大三種規格的 ZPage(不同大小的對象配置設定到不同類型的 ZPage 中),如果各種大小對象配置設定速度不穩定(比如中等大小的對象突然變多,那麼就需要把小/大的 ZPage 轉換成中等 ZPage ,此過程耗時長)。Lindorm 注意到此現象會嚴重影響 RT。OpenJDK15 的 ZGC 對這個現象有所緩解。

以上都是 ZGC 投入生産實踐中亟待解決的問題。Alibaba Dragonwell 11 是 OpenJDK11 的下遊,繼承了 ZGC 在内的全部特性。在後面的篇章中,我們将分享 Dragonwell11 上進行的 ZGC 生産就緒改造的工作。在此之前,讀者可以先嘗試在 Dragonwell11 上開啟 ZGC 。

Dragonwell11開啟ZGC

Java 開發者需要将 JDK 更新到 Alibaba Dragonwell 11.0.11.7 及以上的版本。開啟 ZGC 隻需在 Java 啟動時打開 -XX:+UseZGC 即可。讀者不妨浏覽 Dragonwell ZGC 相關調優選項。

在後面的篇章中,我們将介紹 ZGC 的原理和調優技巧,并且能看到我們的 Alibaba Dragonwell11 通過對 ZGC 進行生産就緒改造,進而解決生産實踐中的一些問題。

關于作者

唐浩,2019 年加入阿裡雲程式設計語言與編譯器團隊,目前從事 JVM 記憶體管理優化方向的工作。

現 DragonWell 已加入 龍蜥社群 (OpenAnolis )Java 語言與虛拟機 SIG,同時龍蜥作業系統(Anolis OS )8 版本支援 DragonWell 雲原生 Java ,歡迎大家加入社群 SIG,參與社群共建。

SIG 位址:官網:

https://openanolis.cn/sig/java/doc/216166872482840581
絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

—— 完 ——

加入龍蜥社群

加入微信群:添加社群助理-龍蜥社群小龍(微信:openanolis_assis),備注【龍蜥】拉你入群;加入釘釘群:掃描下方釘釘群二維碼。歡迎開發者/使用者加入龍蜥OpenAnolis社群交流,共同推進龍蜥社群的發展,一起打造一個活躍的、健康的開源作業系統生态!

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

Dragonwell釘釘交流群

絲般順滑!全新垃圾回收器 ZGC 初體驗 | 龍蜥技術

龍蜥社群釘釘交流群

關于龍蜥社群

龍蜥社群(OpenAnolis)是由企事業機關、高等院校、科研機關、非營利性組織、個人等按照自願、平等、開源、協作的基礎上組成的非盈利性開源社群。龍蜥社群成立于2020年9月,旨在建構一個開源、中立、開放的Linux上遊發行版社群及創新平台。

短期目标是開發龍蜥作業系統(Anolis OS)作為CentOS替代版,重新建構一個相容國際Linux主流廠商發行版。中長期目标是探索打造一個面向未來的作業系統,建立統一的開源作業系統生态,孵化創新開源項目,繁榮開源生态。

龍蜥OS 8.4已釋出,支援x86_64和ARM64架構,完善适配Intel、飛騰、海光、兆芯、鲲鵬晶片。歡迎下載下傳:

https://openanolis.cn/download

加入我們,一起打造面向未來的開源作業系統!

Https://openanolis.cn