Java 11遷移成功案例

banq發表於2018-12-20

這篇文章總結了如何成功將微服務從Java 8遷移到Java 11。
對於每項服務,已經完成了以下步驟:
  • 使用Java 11編譯程式碼
  • 在Java 8上執行Java 11相容服務
  • 在Java 11上執行該服務

實際上,我們有一些額外的步驟,因為當我們開始遷移時,Java 11還沒有釋出,我們只能使用Java 10. 假設程式碼是在Java 10上編譯的,那麼遷移到的工作就不會那麼多了。 Java 11和Jigsaw專案引入了Java 11作為模組化的最大變化。謝天謝地,就是這樣!

1.使用Java 11編譯程式碼
我們不得不提高我們正在使用的大多數框架和工具的版本。特別是,我們必須處理從Spring Boot 1到2以及Spring 4到5的遷移。由於這些是主要版本,我們必須修復幾個重大變化。
對於Spring Boot 2,Spring Boot 2.0Spring Boot 2.1的官方遷移指南編寫得很好並且詳細。

  • 配置檔案載入已經演變
  • 屬性輕鬆繫結是有點不夠放得開
  • 某些屬性已重新命名,其他屬性不可用(例如security.basic.enabled property,必須替換為a WebSecurityConfigurerAdapter)
  • 一些端點被重新命名(例如執行器健康檢查)
  • 現在預設禁用bean過載,這是我們在整合測試中使用的東西,我們不得不使用新屬性重新啟用它spring.main.allow-bean-definition-overriding。

在Spring5遷移是從檢視與一些小的改動程式碼點非常簡單。困難的部分與專案遺留的事實有關,我們必須處理複雜的Spring XML配置和遷移到Dropwizard Metrics 4。

很少有框架仍然與Java 9+不相容,除非它們沒有得到社群的積極維護。在我們的案例中,我們必須找到Cassandra Unit的解決方法。我們不打算花時間更改測試框架,因此我們計劃遷移到DynamoDB。

我們還必須處理Maven依賴地獄,因為一些必需的依賴項帶來了與Java 9+不相容的舊依賴項。在大多數情況下,在POM中新增一些排除項解決了這個問題。

我們在bash配置檔案中新增了一組簡單的別名,以便在Java版本之間切換。

alias setjava8=”export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/”
alias setjava10=”export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-10.0.2.jdk/Contents/Home/”
alias setjava11=”export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-11.jdk/Contents/Home/”


在IntelliJ上,可以從專案設定(“Project SDK”下拉選單)更改Java版本。

CI環境:
對於持續整合方(我們使用Bamboo),我們更新了代理以使用Java 11. 我們注意到,由於計劃配置是全域性的,因此不可能為分支計劃和主計劃提供不同版本的代理。這意味著如果其他人正在將更改推送到master(例如,新功能或完全獨立於Java 11遷移的錯誤修復),則將代理更新為Java 11將破壞master。
為了緩解此問題並避免紅色構建,我們必須確保專案正在使用Java 11進行編譯,並且在更新代理之前所有測試都在本地傳遞,以便快速合併Java遷移拉取請求。另一個選擇是在Java 11上分支計劃為綠色時暫時將代理程式設定為Java 8,而不會忘記在合併之前將其設定回Java 11。

2.在Java 8上執行Java 11相容服務
一旦所有內容都修復,合併並且主構建為綠色,我們必須確保Java 11相容版本在我們的測試環境中正常執行。基本上確保沒有任何損壞...我們有單元,整合和端到端測試,所以我們的信心水平相當高。
為了安全起見,我們對API進行了一些額外的探索性和手動測試,並提供了一些異常和邊緣案例請求,以確保其行為正確。我們還確保日誌和Grafana儀表板都很好。
下一步是將新版本推向生產。即使程式碼與Java 11相容,該服務仍然使用Java 8執行,我們不想同時引入太多更改,畢竟我們不喜歡有風險的版本。由於多次重構和版本提升,我們特別小心處理此版本。在檢視Grafana儀表板幾天後,比較遷移前後的指標,結果表明一切順利。

3.在Java 11上執行服務
最終目標是在Java 11上執行服務。理論上,它將像更新Docker檔案一樣簡單,比如使用Java 11映像並在生產中推送工件。然而,在實踐中它並不那麼簡單......
首先,我們必須更新Java JVM引數(該-d64[url=https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8180286]引數已棄用[/url],將阻止服務啟動,我們還必須更新GC日誌引數)
然後,我們很快意識到服務日誌已經從我們的本地生產環境中的Splunk中消失了,這些日誌實際上是在AWS上正常工作時顯示的。我們必須以更新的logback配置來解決這個“時間失真”;透過更新)日期模式從%d{ISO8601}到%d{yyyy-MM-dd’T’HH:mm:ss.SSSZ,UTC}。

在部署到生產期間出現了另一個奇怪的錯誤VerifyError: Bad type on operand stack,AppDynamics因為一些奇特的位元組碼操作而阻止某些例項啟動。由於某些原因,它在prod-canary上很好,然後在幾個例項上成功部署後開始失敗!我們不得不禁用AppDynamics,這很好,因為我們在團隊中沒有使用此工具。

當我們轉向Java 11時,我們還必須更新一些Grafana儀表板以使用新垃圾收集器的G1。

結論
今天,我們專案中使用Spring Boot 2提供使用者通知的3個服務,以及使用Spring 5提供網站頁首和頁尾的1個服務已經在Java 11上執行順利有幾個星期了。使用預設的G1垃圾收集器,我們沒有遇到任何與記憶體佔用或任何其他效能問題相關的奇怪行為。另一方面,我們的響應時間沒有任何改善。
下一步是什麼?Java 12將於2019年3月釋出。目前,我們仍然不知道是否將使用此版本或等待下一個Java LTS。它可能取決於包含哪些功能。

相關文章