升級 Uber 的 MySQL 艦隊至8.0版
提升 MySQL 艦隊至 8.0 版,兼顧效能與穩定。
作者: Siddharth Singh, Sriram Rao Udupi, Raja Sriram Ganesan, Debadarsini Nayak
前言
Uber 的 MySQL 艦隊是資料基礎架構的骨幹,支援平台上各種關鍵運作。從 2023 年開始,我們展開了將 MySQL 艦隊升級至最新版本 (MySQL v8.0) 的重大工程。
本文將深入探討這次升級的動機、挑戰、解決方案,以及我們如何在不影響服務水準目標 (SLO) 的情況下完成升級。
升級動機
以下幾個重要因素促使我們決定從 MySQL v5.7 升級至 v8.0:
解決生命週期終止的考量: 由於 MySQL v5.7 已到達「延長支援結束日期」,繼續使用將使我們暴露於潛在的安全漏洞,且缺乏持續的錯誤修復。這對資料的穩定性和完整性構成重大風險。
提升效能和並行處理能力: MySQL v8.0 提供了顯著的效能提升。索引和資源利用率的優化,帶來更快的查詢執行速度和更好的並行處理能力,進而提升用戶體驗。
導入新功能: 除了效能提升之外,v8.0 還引入了許多寶貴的功能,例如支援視窗函數、增強的 JSON 處理能力,以及更佳的空間資料功能。這些功能為資料操作和分析開闢了新的途徑,讓我們得以在平台上解鎖新的功能。
密碼輪替: v8.0 導入的「雙重密碼」功能,讓安全事件期間的密碼輪替更加順暢,同時減少服務中斷。
簡化操作效率: Schema 變更管理是一項持續性的工作。v8.0 的「即時新增欄位」功能大幅簡化了這個流程,減少 schema 變更期間的停機時間,從而提升整體營運效率。
Uber 龐大的 MySQL 基礎架構概觀
在深入探討 MySQL 升級過程之前,必須先了解 Uber MySQL 基礎架構的規模和複雜性:
規模: Uber 的 MySQL 基礎架構包含超過 2,100 個叢集,分布在橫跨三個區域的 19 個生產區。超過 16,000 個節點構成了 Uber 資料儲存和處理能力的骨幹。
資料量和查詢負載: 我們的 MySQL 基礎架構每天處理數 PB 的資料和約 300 萬次查詢。
叢集架構: 每個 MySQL 叢集整合了在個別節點上運行的多個 MySQL 程序。叢集中的每個節點都包含相同的資料,並策略性地分布在不同的資料中心,以確保資料可用性和支援故障轉移機制。
主從複製: 每個叢集中,一個主節點負責管理所有寫入流量,而從節點則會非同步複製資料。這種架構確保了冗餘和容錯能力,允許在主節點故障時無縫進行故障轉移。
升級考量: 值得注意的是,MySQL v5.7 主節點可以複製到 MySQL v8.0 唯讀副本,但反之 (MySQL v8.0 主節點複製到 MySQL v5.7 副本) 則不支援。這一點在我們的升級規劃和執行策略中扮演著至關重要的角色。
MySQL 升級過程中的挑戰
Uber MySQL 基礎架構規模龐大,超過 2,100 個叢集和 16,000 多個節點分布在各個區域,這對我們來說是一項重大挑戰。手動升級顯然不可行。為此,我們設計了一套全面、多步驟的升級策略,可以在不同環境中有效執行,並需要縝密的協調。
另一個關鍵考量是如何在升級過程中將停機時間降到最低。維持服務水準目標 (SLO) 和服務水準協議 (SLA) 至關重要,以確保使用者服務不中斷。我們的解決方案包含周密的規劃,並專注於在整個升級過程中將停機時間降到最低。
與現有應用程式和服務的相容性是另一個難題。為確保與現有生態系統的無縫整合,我們進行了大量的測試,包括完整的驗證和回歸測試。
為了進一步提高系統可靠性並減少服務中斷,我們實施了自動回滾機制。如果發生故障或不相容問題,這些機制可以自動還原升級。
最後,盡量減少升級過程中的人工介入也至關重要。為了簡化操作並降低人為錯誤的風險,我們開發了穩健的自動化工作流程。這些工作流程將重複性任務自動化,讓數千個叢集和節點可以無縫升級。
總體來說,升級到 v8.0 對 Uber 而言是一大勝利,它不僅提升了安全性、效能,還帶來了許多令人興奮的新功能。但如果要手動處理數千個叢集的升級?不了,謝謝!我們需要一個更智慧、可擴展的解決方案。於是,我們打造了客製化的自動化系統,用來精確引導每個叢集完成多步驟的升級過程,完全自動化。
Uber 的 MySQL 升級路徑
在考慮將 MySQL 叢集從 v5.7 升級到 v8.0 時,我們有兩種可行的方案:
並行升級
並行升級是指新版 MySQL (在本例中為 v8.0) 與現有版本 (v5.7) 同時安裝。這種方法需要設置一台獨立的伺服器來部署和設定新版本。新伺服器就緒後,流量會逐步導向新版本,以實現平穩過渡。
就地升級
就地升級是指直接將現有的 MySQL 安裝升級到新版本 (v8.0),無須設置新的環境。這個過程通常需要停止 MySQL 服務、執行升級,然後重新啟動服務。就地升級的設定比較簡單,但停機時間可能比並行升級更長。此外,如果在升級過程中遇到意外問題,回滾的空間也比較小。
選定的策略
經過仔細考量和全盤評估各種優缺點後,我們決定採用並行升級的方式,將 v5.7 節點升級到 v8.0,而不是就地升級。選擇這個策略的原因如下:
- 最小化停機時間: 並行升級允許我們在設置新 MySQL 8.0 節點的同時,保持舊 MySQL 5.7 節點繼續運行。這表示我們可以逐步將應用程式遷移到新節點,而不會造成顯著的停機時間。
- 降低風險: 由於舊 MySQL 5.7 節點仍在運行,如果新 MySQL 8.0 節點出現任何問題,我們可以回滾到舊版本。這降低了效能降低、資料遺失 (僅限於升級過程中的維護階段之前) 或升級過程中可能發生的其他問題的風險。
- 更完善的測試: 透過讓新 MySQL 8.0 節點與舊 MySQL 5.7 節點同時運行,我們可以使用正式環境的唯讀應用程式負載來測試新節點,再進行正式切換。這有助於我們及早發現任何問題,並確保在完成遷移之前一切都能正常運作。
為了克服這些挑戰,我們開發了一套系統,將 MySQL 叢集從 v5.7 升級到 v8.0 的過程完全自動化。我們的自動警報和監控系統會主動監督整個流程,確保順利過渡,並及時發出任何潛在問題的警報。
升級過程概要如下:
- 節點複製: 為叢集中每個 MySQL v5.7 節點,在同一個區域/可用區中新增一個對應的 MySQL v8.0 副本節點,維持 v5.7 和 v8.0 節點之間的分布一致性。
- 觀察期: 透過約一週的監控期,我們可以觀察系統效能,並偵測新版本節點可能造成的任何效能衰退或 SLA 違規。
- 流量轉移: 觀察期結束後,停用 MySQL v5.7 副本節點,將流量導向 v8.0 節點。
- 主節點晉升: 將一個 MySQL v8.0 節點晉升為叢集的主節點。
- 移除舊節點: 最後,移除所有 MySQL v5.7 節點,完成 MySQL v8.0 的升級作業。
上述過程分為四個階段:
預維護: 在此階段,透過新增 MySQL v8.0 節點作為副本,為叢集升級做好準備。這些節點會與現有的 v5.7 節點一起運行,以服務實際的生產流量。
系統監控: 新新增的 MySQL v8.0 節點作為副本運行,讓我們可以監控實際的生產流量。任何偏離預期行為的情況都會被記錄和處理。
維護: 系統監控階段完成後,會將一個 MySQL v8.0 節點晉升為主節點,並監控系統穩定性。
維護後: 在最後階段,會刪除非複製的 MySQL v5.7 節點,形成一個純 MySQL v8.0 叢集。
回滾機制
雖然我們採用漸進式部署策略,但我們仍然需要在每個步驟都具備回滾能力,並且需要可觀察性來識別何時需要回滾。在整個升級過程中,我們將風險最小化和確保資料完整性列為首要任務。在維護步驟之前,所有操作都是完全可逆的,不會有任何資料遺失的風險。如果客戶因為高延遲或 CPU 使用率等因素而遇到服務降級,我們可以無縫且立即還原到 MySQL v5.7,完全不會遺失資料。這表示只要刪除或停用在預維護階段新增的 MySQL v8.0 副本節點,我們就可以快速回到之前的狀態。
然而,必須注意的是,一旦 MySQL v8.0 節點升級為主節點,就無法再複製到 MySQL v5.7 節點。這標誌著與 MySQL v5.7 的相容性將無法回頭。
在此階段之後若嘗試還原到 MySQL v5.7 主節點,可能會導致資料遺失,因為 MySQL v8.0 主節點上的任何變更都無法複製回 MySQL v5.7 節點。因此,在將 MySQL v8.0 節點升級為主節點之前,我們會仔細評估和徹底測試,以確保順利過渡,同時維護資料的完整性。
利害關係人溝通
我們系統地逐步升級每個層級,從第五層級開始,最後到第零層級。在每個層級,我們將叢集分成數個可管理的批次,以確保系統化且受控的轉換過程。在每個升級階段開始之前,我們都會積極與負責每個叢集的值班團隊合作,促進協作並確保全面的監督。
這種深思熟慮且有條理的方法,使我們能夠有效地應對升級 MySQL 艦隊的複雜性。透過將協調、溝通和團隊合作列為優先事項,我們成功地完成了每個層級的轉換,順利升級到 MySQL 8.0 版本。
遇到的問題
v8.0 與 5.7 的查詢執行計畫變更
升級到 MySQL 8.0 不僅帶來了新功能,也為某些叢集帶來了一些意料之外的查詢執行計畫調整。這導致延遲增加和資源消耗提高,可能影響使用者體驗。支援 Uber 所有儀表板的叢集就發生了這種情況。為了
解決這個問題,我們與 Percona 合作,找出了一個修補程式,並成功地將其應用於受影響的叢集。這個解決方案確保升級後的 MySQL 版本能夠恢復最佳化的查詢效能和資源效率。
不支援的查詢和設定
從 MySQL v5.7 升級到 v8.0 版本時,某些關鍵字的語法發生了變化,導致正式環境中的一些查詢失效。此外,我們現有的大部分叢集都沒有啟用 MySQL 8.0 預設的「STRICT_TRANS_TABLES」SQL 模式,這導致許多客戶在升級過程中遇到錯誤。「ONLY_FULL_GROUP_BY」SQL 模式也出現了類似的挑戰,這凸顯了為了確保與升級版本的規範相容,必須仔細修改設定。
先前預設的校對設定
MySQL 8.0 的預設字元集是 utf8mb4,搭配 utf8mb4_0900_ai_ci 校對設定。之前的 MySQL 5.7 版本使用的是 utf8mb4_unicode_520_ci 校對設定,不支援最新的 utf8mb4_0900_ai_ci。這種轉變在統一升級系統的校對設定方面帶來了挑戰。
用戶端函式庫不相容
函式庫升級需求: 許多現有的用戶端函式庫與 MySQL v8.0 不相容。為了因應這個問題,我們必須升級這些函式庫,並在測試環境中進行全面測試,以確保它們在新版本中能正常運作,然後才能繼續進行主要升級。這個步驟對於確保客戶端互動的順暢過渡至關重要。
效能提升
新版本讓我們受益於以下效能提升:
MySQL v8.0 伺服器端效能提升
在 1,024 個執行緒下,執行 100 萬次插入操作的 p99 延遲提升了 29%。
在 1,024 個執行緒下,執行 100 萬次讀取操作的 p99 延遲提升了 33%。
在 1,024 個執行緒下,執行 100 萬次更新操作的 p99 延遲提升了 47%。
MySQL 升級帶來的用戶端效能提升
整體資料庫鎖定時間減少了約 94%。
某些查詢的查詢時間減少了約 78%。
經驗與心得
在這一年多的全面升級過程中,我們的 MySQL 團隊工程師完美地執行了各個關鍵階段。
將整個 MySQL 艦隊遷移到 MySQL 8.0 的這項重大任務,不僅包含了測試叢集,還包含了支援 Uber 和內部工具執行個體的正式環境叢集。這次大規模升級凸顯了我們的可觀察性平台、測試機制和穩健的回滾功能的重要性。
我們嚴謹的測試程序和分階段部署策略證明非常寶貴,讓我們能夠及早發現並解決潛在問題。藉由採用這種方法,我們大幅降低了在主要升級階段遇到新故障模式的風險。
結論
在 Uber 將 MySQL 艦隊升級到 8.0 版本的旅程充滿挑戰,但也收穫良多。透過採用最新技術和運用自動化,我們不僅確保了資料庫基礎架構的安全性與效能,也展現了我們對創新和卓越的承諾。
這次由我們專業的工程師團隊精心規劃和執行的升級過程,彰顯了我們致力於維持最高可靠性和效率標準的決心。透過仔細考量優缺點,我們成功地完成了轉換,降低風險,並將服務中斷降到最低。
我們要感謝所有為這次升級成功做出貢獻的人。我們將持續攜手合作,突破界限、推動創新,共同形塑 Uber 的科技未來。