MySql分庫分表實踐
隨著系統業務的發展,資料量的增長,海量資料的儲存和讀取成為系統性能提升的最大瓶頸。通過資料切分水平擴充套件資料庫成為首要方案。
Mysql分庫分表技術層面的文章已經很多,但涉及的如何實施的文章並不多,本人結合剛剛結束的遷移專案經歷整理此文,由於本文為純文字性文章,內容可能比較枯燥,但仍希望能夠為即將執行遷移的人提供些許幫助。
遷庫前的梳理與準備。
架構的三思,通常情況下如果系統已經發展到需要分庫分表來提高效能,那麼應該可以考慮將系統拆分成多個垂直應用和分散式服務框架來重構系統。另外有些系統或公司可能希望在遷移的過程中實現雙寫,雙寫的多數目的是為了當新系統存在問題時能夠切換回到舊系統和方便後期驗證工作。結合本人經驗,此時一定不要盲目準備雙寫,而是要重點考慮一但切換帶來的影響是否是可以承受的,遷庫引發的錯誤是可以通過測試發現的,但是切換引起的損失可能是不好估量的。所以如果選擇雙寫,除了雙寫方案還要考慮因切換導致的不一致資料如何修復以及資料驗證的相關工具。
工作該如何開展?梳理現有業務,並繪製一張資料庫ER圖,然後分析統計哪些表需要拆分再結合業務特點進行分類。假設資料庫中有20張表那麼很可能只有10幾張表需要分庫分表,而且在這10幾張表中有些業務是相互獨立的,那麼就可以分批次進行遷移了。在分析時可結合業務特點、歷史資料量、年增長率等資訊進行綜合評判。而且像系統中的資料字典表、申請、審批等型別的表一般是不需要進行分庫分表的,針對此型別的表可考慮放在一個單獨的資料庫例項中。
定義分庫分表的路由規則。結合資料ER圖,通盤考慮需要事務保障一致性的操作,定義資料路由規則使其能夠將同一事務下的所有表路由到同一資料庫中。
檢查現有業務表是否包含自增主鍵(全量遷移時會比較方便),createTime和updateTime欄位,如果沒用應該考慮進行擴充套件(修改應用程式碼或新增觸發器維護這兩個欄位)方便資料的全量和增量遷移。
遷移工作的開展
經歷過前期的梳理,下面重點工作就是實施的過程了,這個過程中的重點工作除了開發與測試工作之外還有就是指令碼及工具的準備。
工欲善其事必先利其器。如果涉及新的dao層程式碼開發,那麼開發一個程式碼生成工具無疑會帶來事半功倍的效果。同時還需要準備資料遷移的工具,這時之前提及到的新增createTime和updateTime及自增欄位就派上用場了。由於資料同步功能一般對記憶體消耗較大,所以可以多機部署然後建立不同的同步任務,對於資料量較大的表可以根據時間段或id範圍拆分成多個同步任務。另外自增主鍵連續性較強所以單次載入資料量比較均勻比較適合做全量資料同步,而updateTime則適用於增量資料同步。另外分庫分表後,由於需要建立整百上千個表,所以編寫一個簡單的建表sql生成工具也是必要的。對於資料遷移之後資料核查工作也是比較複雜和耗時的所以編寫一個數據核查工具也能減少不少的工作量。
程式碼開發與測試,不能鬆懈的任務。架構和方案雖然定義完成,但是程式碼開發工作仍然是重中之重。如果資料庫操作被封裝成分散式服務,那麼此時需要注意在資料操作層程式碼中不能有過重的業務邏輯,需要保障方法的效能。對於一些單表操作的資料庫層程式碼一般可能比較簡單通常情況下交由一個人開發即可,但是對於公共資料表操作的程式碼開發很可能由多人同時進行,那麼就需要注意避免出現大量臃腫和重複性程式碼或方法,最好的方式是結合業務對公共方法進行統一定義然後分工實現。程式碼開發過程中和完成後的走查也尤為重要。
開發測試完成之後,上線之前需要梳理相關應用系統的上線順序,並準備建表指令碼。在上線前可以先遷移全量資料到新資料庫並記錄時間點,在正式上線前執行增量資料同步。資料遷移完成後要對資料的正確性、完整性進行驗證,應用上線之後要對系統功能逐一驗證。
架構設計與程式碼開發的一些技巧
複雜業務拆分為批量作業。資料庫層操作方法如果遷移為分散式服務之後,為了避免業務處理時間過長造成超時,一般可以將複雜業務封裝成批量作業,然後使用定時任務或多執行緒逐一處理,處理完成後記錄處理結果。對於資料量較大的業務還可以在服務呼叫方對資料進行分頁處理,以降低單次操作的時長。
定時任務的高可用改造功能。對於定時任務,由於資料可能分佈在不同的資料庫中,不能使用事務提供一致性保障,這時可以將任務拆分成多個步驟,逐步執行並記錄下當前任務的處理步驟,如果因為服務重啟或宕機導致業務處理只完成一半當服務恢復後可以繼續執行,但是最好同時具備完善的監控或告警機制以避免資料處於長期處理失敗和重試狀態。
針對複雜查詢的處理。對於需要事務保障一致性的操作資料記錄後可能並不方便其他業務對其進行查詢,這時可以通過儲存多個維度的資料來解決此問題。例如我們對銀行卡和其消費資訊進行分庫分表改造。為保障資料一致性,一張銀行卡的消費資料應該和銀行卡資訊儲存在同一資料庫中,但是如果通過使用者名稱維度查詢訊息資訊時就沒有那麼方便了。這時可以將銀行卡資料按照使用者名稱維度冗餘一份,在以使用者名稱查詢消費資料時可先通過使用者表查詢到該使用者下的銀行卡資訊,然後在查詢消費資訊。或者冗餘一份消費資訊,但是這樣消耗的儲存空間顯然是比前者大的。除此之外我們也可用通過搜尋引擎解決查詢問題,canal+es就是不錯的組合。