作者介紹
楊建榮,競技世界數據庫專家、dbaplus社群聯合發起人,騰訊云TVP,Oracle ACE,《Oracle DBA工作筆記》和《MySQL DBA工作筆記》作者;現就職于競技世界,擅長數據管理、數據遷移、性能優化,目前專注于開源技術、運維自動化和性能優化,堅持寫技術博客,已堅持2400多天。
數據庫是基礎資源的重要組成部分,隨著業務的發展,數據庫版本升級的話題自然會擺上桌面。
一、如何看待MySQL版本升級
關于數據庫版本升級,一直都是熱議話題,對于升級的緣由各家也有所不同,有業務驅動的,有DBA自發驅動的,有規劃導向也有方向指引的……拋開各種原因,當升級這個決定落下來的時候,對于DBA手頭的幾百幾千套數據庫來說,就好比是一場動物大遷徙,滿滿的畫面感。
從Oracle發布的版本生命周期規劃可以看到,MySQL5.7已經走到了生命周期的終點,意味著后續將不再為 MySQL 5.7 提供官方更新、錯誤修復或安全補丁。
阿里云和AWS都在官方公布了版本支持計劃,MySQL 5.7版本已經開始了倒計時。
而要想讓這件事情獲得研發同學的大力支持,就需要平滑升級或者最低成本的改動。所以對于這場遷移的基本要求,我在心里默默對自己提了要求:零故障,平滑升級。
(一)行業內的MySQL版本數據情況
我在2022年底左右調研了下行業內的一些公司的MySQL數據庫版本情況,列表如下:
可以看到大部分的公司還是在MySQL 5.7這個版本,而且從服務規模來看,越是規模大的公司,要想做整體升級這個事情的復雜度就會高出幾個數量級。
(二)我們做數據庫版本升級的理由
我們做這件事情是從規劃導向來切入的,也有一部分DBA自驅的因素。說是規劃導向,轉義過來就是不打無準備之仗,MySQL后續的整體架構是構建在基礎存儲之上的,如果基礎存儲存在瓶頸,對于后續的架構演進也存在明顯短板,所以我們在2019年底就開始調研并小范圍在新業務中試點MySQL 8.0了。
如下是早期調研中對于MySQL 8.0和MySQL 5.7使用sysbench壓測的一些信息供參考,可以看到MySQL 8.0是有明顯性能提升的。至于MySQL 8.0的版本,我們的考慮是和驗證測試的8.0.19保持一致,在后期支持新版本的無縫升級。
從功能上來說,開發特性更加豐富,SQL優化效果和運維功能上都有明顯的提升,在兼容性方面會更加嚴格(兼容性嚴格具有兩面性)。
在經過了一個相對穩定的周期驗證之后,無論從穩定性、性能和功能方面確實達到了預期的效果,有一些特性確實解決了當時的一些運維問題。
說是DBA自驅的理由,是因為我們盤點了一下近些年來的MySQL技術棧使用情況,發現實際的情況比我們預想的要差一些,比如MySQL 5.5我會定義為一個分支技術棧,以此類推,我們目前存在7個分支技術棧。
在這些因素的基礎之上,我們以點帶面展開分析,發現多分支技術棧散亂只是表象,還有一些潛在問題和瓶頸問題:
1、MySQL版本過舊,架構管理不一致,運維復雜度較高
1) MySQL 5.5和5.6為過舊技術棧,官方已不再維護
2) 未來3年內需要從MySQL 5.7升級至8.0,演進復雜度高
3) 40%操作系統版本過舊,后續的數據庫版本升級存在風險
2、部分技術棧已閉源,服務異常時存在恢復風險
1) Infobright已轉為商業版維護
2) TokuDB已于2020年不再維護
3、數據庫規范和審核機制難以支撐現有的業務需求
1) SQL審核工具解決了早期的研發規范問題,后續閉源難以持續
2) 數據庫開發規范已4年未更新,部分開發規范已難以滿足業務需要
4、人員穩定性和持續發展
1)DBA不可避免地在做一些重復勞動,一些繁瑣的差異化操作勢必會削弱工作熱情,也會發生一些意料之外的異常
2)個人運維經驗無法有效的沉淀轉化
所以這是一個綜合的問題,涉及到對技術、業務和人的管理,而且是環環相扣。
當然對于一件事情的基本邏輯越簡單,實現起來也更聚焦。所以我們進一步提煉了一下目標,7->2,即7個分支技術棧整合為2個,在這個基礎上進行生態技術棧的補充和完善。
(三)數據庫版本升級的意義
做這件事情有什么好處呢,也就是所謂的意義,我覺得是:降本增效,提高整體業務穩定性。主要體現在如下六個方面:
- 應對未來3年內的數據庫基礎服務風險,對后續的數據存儲平臺架構迭代奠定基礎(這個需要由明確的規劃支撐)
- 通過版本升級提高整體業務性能和穩定性
- 實現支持系統的一致性,提高基礎服務支撐能力
- 將單點業務遷移至MySQL主流技術棧,預防故障風險
- 對開發規范和SQL審核機制進行規范化支持和落地
- 為后續的環境標準化建設提供實踐經驗
我從公有云和私有云的視角盤點了下MySQL技術棧發展的情況,其實MySQL 8.0已經成為了行業主流的基線版本,各種數據庫產品層出不窮,如果基線版本已經落后了,后續勢必會有整合和返工,所以這也算是一個技術的戰略點。在協議兼容的前提下,還需要進一步考慮到國產化數據庫的影子,當然也可以有更多的選擇,重心在于協議和生態技術棧兼容。
畢竟數據庫的升級是一項大工程,大開大合,研發同學再配合支持也需要權衡,所以MySQL 8.0的大版本基礎之上,在滿足驅動和協議兼容之后,后續的小版本和迭代升級計劃都是在8.0的體系之內完全平滑閃斷完成,也就不需要研發同學全程跟進了。
(四)數據庫版本升級的潛在難點
當然任何事情都得多面看,看到好處(意義),也需要看到難點:
- 跨中心多團隊協作,周期較長
- 開發語言技術棧有7個,MySQL 8.0的驅動兼容性都需要充分考慮
- 部分升級改造需要研發側支持旁路數據雙寫
- 根據數據庫拓撲關聯主機業務的親和性,避免服務器故障
- 按照業務特點和優先級制定差異化升級方案
- 基于滾動模式的數據庫資源全量替換,避免資源冗余
- 制定平滑的MySQL集群遷移方案,對業務侵入性最低
因為我們升級的基調是平滑模式,所以基本是資源平替,快速切換的實現策略,在這種情況下,每一個數據庫實例都需要反復確認,會有大量的溝通協調工作,況且業務不能停,因為數據庫升級直接影響到業務使用,這件事情的性質也就變了。
二、通過五個方面保障數據庫升級的穩定性
接下來我會從如下的幾個方面來保障整個升級過程的穩定性。
(一)梳理和確認目標和范圍
整個數據庫版本升級,不是單單有標準版的主從集群,還需要考慮到中間件集群,因為NewSQL集群上線已經完成了兼容性測試,所以不在本次升級的考慮范圍之內。
通過這項梳理也能夠基本明確其他分支技術棧該如何做方案設計。
(二)制定升級策略
1、整體升級策略
這場數據庫版本升級的大遷徙,是從7個分支技術棧收縮為2個,所以需要對不同的分支技術棧規劃落地方案,整體上我們是傾向于讓MySQL 8.0承載盡可能完整的業務。
因為上一步明確了數據庫版本升級的范圍是標準版和中間件集群和其他分支技術棧,則需要制定相應的升級策略。
2、標準版升級策略
對于標準版主從來說,如果是MySQL 5.5,5.6版本,需要先過渡到MySQL 5.7,完成兼容性測試之后,觀察一段時間之后,再次升級到MySQL 8.0;如果是MySQL 5.7版本,則可以直接升級到MySQL 8.0。
3、中間件集群升級策略
對于中間件集群來說,整體的思路還是做拓撲下沉,即通過級聯的方式,把從庫提升為主庫。
4、其他分支技術棧升級策略
對于其他的分支技術棧來說,這些技術棧早期也確實解決了一些業務厄待解決的問題,隨著MySQL 8.0的性能提升和集群技術的迭代,需要做一些整合。
- TokuDB遷移至TiDB
- Infobright遷移至MySQL 8.0
- 對于一些歷史遺留業務,還需要研發協助完成數據旁路雙寫
所以整體來上來看,數據庫版本升級不是單一升級到8.0,在策略上需要考慮完整。
(三)定制化升級列表
如果有成百上千個實例要落地升級計劃,顯然是一件龐大的工程,某個業務有幾十個實例,斷斷續續地溝通,研發同學也受不了,而且整體的進度也不好控制,所以我們是從兩個維度來做梳理和整合的。
- 先按照數據庫版本把所有業務的信息都梳理出來,比如MySQL 5.6,MySQL 5.7的,可以整理成不同的tab頁,按照業務負責人進行匯總;
- 然后按照不同的業務大類或者業務負責人,把上面這個數據中的信息提取出來,這樣就形成了業務視角的數據庫升級計劃,基本就可以開始和研發同學溝通了;
- 當然溝通也不能全靠嘴,還需要一些標準化的文檔,比如我們整理了不同版本升級需要注意的事項,把整個過程需要研發協助的事情都列清楚,避免重復的解釋和無效溝通;
- 最后是回退方案,這應該是整個方案里面研發同學最關心的部分了,畢竟先把最壞的結果考慮到,一旦發現問題也能及時處理。
如下是我們計劃和研發同學進行的溝通的雙方協作的流程。
(四)研發驅動兼容性/功能測試
1、數據庫驅動兼容性測試
數據庫驅動測試是升級的一個關鍵環節,而且涉及到很多開發語言,所以兼容性測試是重中之重。
為了避免走彎路,我們先期和一些研發同學一起梳理測試,整理了如下的驅動兼容性列表,這樣后續的一些研發同學接入時,就可以參考了。
而對于C++、.NET、Python/ target=_blank class=infotextkey>Python、php、Go、NodeJS等開發語言,兼容性變動相對較小,總結如下:
除了驅動型兼容測試,對于MySQL的不同分支版本,也需要進一步測試SQL兼容性和其他注意事項。
2、MySQL 5.5,5.6升級到MySQL 8.0的兼容性測試:
1)針對group by語法、日期格式字段等有特定要求
如對于group by聚合操作,select列必須在group by中出現,若不在group by子句中,認為不合法。示例:
mysql> select name,age from test group by name,age;
+------+------+
name | age |
+------+------+
aa | 18 |
+------+------+
1 row in set (0.00 sec)
mysql> select name,age from test group by name;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contAIns nonaggregated column 'test.test.age' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
對于group by聚合操作,order by 列必須在group by中出現
mysql> select name,age from test group by name,age order by name;
+------+------+
name | age |
+------+------+
aa | 18 |
+------+------+
1 row in set (0.00 sec)
mysql> select name,age from test group by name,age order by id;
ERROR 1055 (42000): Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'test.test.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
mysql>
- 解決方案1:研發側調整對應的SQL語句
- 解決方案2:調整MySQL5.7/8.0的sql_mode參數,保證兼容MySQL5.5的語法
2)MyISAM存儲引擎的表可能存在潛在問題
解決方案:經過排查,目前線上bbs的庫表均為innodb存儲引擎或者memory存儲引擎
3)部分SQL會出現執行計劃發生改變,可能需要略微調整
解決方案:目前暫時沒有發現,后續有類似SQL,可以針對性處理
4)字符集驗證
MySQL5.7默認字符集是utf8字符集,如果是gbk等字符集需要調整并驗證
解決方案:DBA側保證升級過后,不會出現亂碼等字符集報錯信息
3、MySQL 5.7升級到MySQL8.0的補充兼容性測試:
1)表中需要包含主鍵
在8.0版本中會強制要求表中包含主鍵
2)timestamp數據類型默認值
如果表結構中有timestamp類型字段,并且設置了默認值DEFAULT CURRENT_TIMESTAMP,建議將參數設置為off:
explicit_defaults_for_timestamp=OFF(8.0默認為on)
否則有可能會出現:Error:1048 - Column ‘createTime‘ cannot be null
3)執行計劃變化
部分SQL會出現執行計劃發生改變,可能需要略微調整
解決方案:跨版本升級中的SQL異常,可以通過提前交付只讀實例來進行預先驗證,并且抓取原庫的慢日志在8.0數據庫中進行回放驗證
4)MySQL8.0 新增關鍵字(如rank),可能導致查詢、寫入失敗
mysql> select rank from activity_public_log limit 1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from activity_public_log limit 1' at line 1
解決方案:改寫成 `rank`或者調整字段名
mysql> select `rank` from activity_public_log limit 1;
查詢方式:
select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME from information_schema.COLUMNS where COLUMN_NAME="rank";
5)對于load權限的確認
部分業務具有導入數據的權限,在默認模板中參數secure_file_priv和local_infile是關閉的,需要和業務側確認是否有該類需求,或者從定時任務中識別
6)存儲過程權限檢查
部分業務中存在存儲過程時,對于存儲過程的權限粒度 invoker和definer差異可能導致遷移后業務調用失敗,需要在遷移中進行檢查
(五)制定資源申請和回收流程
有了前面的流程支持,整個過程基本可以跑起來了,還有一個風險則是采用資源平替的方案,也就意味著今天數據庫實例是業務A的主庫,完成升級之后我們會讓系統的同事重新格式化后交付給我們,很可能明天就變成業務B的從庫了,所以資源是以資源池的形式在反復利用,對于如何申請資源和下線資源就是關鍵,我們制定的流程是需要至少3次審核才可以下線,而且下線的過程中還需要有一定的觀察期窗口。
為此我們也指定了專人負責制度,即最終的下線操作只能由固定的一個人來操作,他需要對下線操作做最后的審核,并且負責。
三、版本升級問題總結
具體實施的過程還是相對順利的,為此我們也儲備了一些標準化能力,比如平臺化搭建跨版本從庫的服務,保證每個人交付的質量是基本一致的。
所以結果整體上是預期中的,當然也發現了一些潛在問題,通過梳理和總結,也在其他業務方向能夠參考借鑒,提高了整體服務升級的穩定性和專業性。
版本升級的事情做完了,也盤點出了一些新的收獲:
(一)業務便于接入:通過大規模升級的過程對于多語言體系的兼容性支持做到了心中有數;
(二)數據庫子版本平滑升級:后續的子版本升級演變為在線升級模式,就不需要研發做額外的溝通和測試;
(三)操作系統無感升級:操作系統升級可以演變為平滑升級模式,centos 7后續的版本選型和支持都可以做一些調研測試;
(四)資源治理:通過升級也發現有一些服務資源使用率不足需要降配,后續可以開展容量治理。
四、小結
MySQL版本升級工作,從2022年上旬開始規劃到生態完善實施了近1年,得到了多個中心研發團隊的大力支持和理解。MySQL數據庫也從原本的7個技術棧收縮為2個,挑戰和難度在落地時才發現比預期的要復雜不少,為了保證業務的穩定性和研發工作的侵入度最低,DBA團隊也制定了完整的數據升級流程和業務切換方案,并對業務異常的回退進行了全流程準備,整個過程零故障。
后續計劃在SQL云數據庫、SQL高可用體系,SQL分布式架構體系和SQL資源標準化四個方面持續發展,并制定相應的建設計劃。
(一)SQL資源標準化:MySQL 8.0作為基線版本,為后續的運維管理工作提供統一、標準的基礎服務支持,并對外提供一致性系統服務,后續提供平滑升級的平臺化方案;同時做一些資源治理,對一些使用率不足的業務可以在線降配。
(二)SQL分布式架構體系演進:隨著水平擴展需求、信創、分布式事務方案的調研和業務落地演進,未來可能會基于OceanBase等國產化數據庫進行對比分析,適時引入;
(三)SQL高可用體系:SQL高可用體系對于標準版主從集群會基于MySQL 8.0版本作為基線,對于拓撲發現,數據管理模式會基于新的運維命令和使用模式;
(四)SQL云數據庫服務支持:基于MySQL 8.0的服務體系會在功能和性能上面提供更加豐富,高性能的數據存儲支持,如對于JSON的格式解析和查詢等,對于SQL查詢優化的優化器支持等。