天天看點

私信服務MySQL遷移到PolarDB實戰

作者:閃念基因
私信服務MySQL遷移到PolarDB實戰

引言

業務背景

映客作為一款廣受歡迎的社交應用,其私信功能是維系使用者互動的重要橋梁。随着使用者數量的增長,原有的MySQL資料庫已經無法滿足日益增長的資料存儲需求。本文将詳細介紹如何将映客的私信服務從MySQL遷移到PolarDB,以解決存儲瓶頸問題,并提高系統的擴充性。

業務現狀

目前私信服務使用資料庫的情況:

  • 讀寫都很多
  • 資料庫分N庫N表
  • SQL語句未使用特殊功能
  • 讀服務前面有Redis緩存層
  • 計算使用率低,存儲達到瓶頸

業務架構如圖1,資料庫使用情況如圖2

私信服務MySQL遷移到PolarDB實戰

圖1

私信服務MySQL遷移到PolarDB實戰

圖2

目前私信服務面臨着以下挑戰:

  • 資料量持續增大,目前的存儲空間已經使用了85%,且每天還在繼續增長。
  • 如何快速、業務無損的遷移資料,對目前資料庫操作代碼盡量無侵入修改且完全支援 MySQL協定,同時還能支援海量存儲、動态擴縮容。

遷移方案探索

遷移方案選型

針對以上情況我們立足當下結合業務與成本考慮目前都有哪些解決方案。期間我們分别想了以下這些方案的可行性與各自的限制。

  • 優化存儲
  • 縱向擴容
  • 橫向擴容
  • 分布式資料庫

下面我們一一來分析每個方案的優缺點。

優化存儲

1. 歸檔幾年前的資料,能空出20%的空間,但存在redis和db一緻性的問題。比如redis拿的msgid去資料庫查不到的情況,可能還需要開發懶加載資料的功能,需要同時清理redis緩存與歸檔資料。

2. 壓縮content字段,能空出30%空間。需要修改業務代碼和修改曆史資料。

優點:不需要增加機器成本

缺點:需要修改程式,寫歸檔、壓縮腳本,長期來看還是有存儲空間瓶頸。

縱向擴容

縱向擴容的意思就是硬體提升,硬體提升存在的問題:

第一:目前選擇的存儲是否還能支援更大的存儲空間(比如3T到20T),我們RDS目前規格已經達到最大磁盤容量。

第二:存儲擴容可能受計算的影響,也就是存、算需同時更新 (這種成本顯著提高,而且就目前業務來說,瓶頸不在計算,主要在存儲),為了更新存儲還要更新計算,無形中導緻總體成本太高。

優點:對業務無感覺,不需要改造程式。

缺點:需要增加每月成本,計算資源白白浪費。

私信服務MySQL遷移到PolarDB實戰

橫向擴容

因為我們業務本身就是分庫分表,橫向擴容我們可以将一半的庫表拆分到另外一套新叢集來分擔存儲,意思就是通過增加機器來減少每台機器的存儲資料量,如果每台機器的存儲已經達到最大,并且還繼續使用Rds-MySQL的話可以通過該方案進行解決,該方案的缺點是需要寫程式清洗資料,主要步驟就是将目前資料使用DTS同步到另外一個新建立的叢集,此時兩邊各保留一半資料,另一半删除,然後同時對外提供服務。

優點:可降低一半存儲,甚至更多存儲空間

缺點:需要寫程式清洗資料,成本增加

私信服務MySQL遷移到PolarDB實戰

分布式存儲資料庫

在對比了多種分布式資料庫産品後,我們選擇了PolarDB For MySQL作為遷移的目标資料庫。PolarDB的存算分離、高可用性和水準擴充能力成為解決我們目前問題的理想選擇。分布式資料庫,上層都會實作主流資料庫文法的解析層、優化執行層、引擎層在依賴各種日志實作同步與可靠性,最終落盤到分布式檔案系統來實作多副本、高可用。分布式資料庫PolarDB For MySQL與MySQL在存儲上有何差別,如下圖,分布式資料庫全局就一份資料,當然為了可用性、一緻性,各個節點之間還是需要同步協調資料,反過來Rds MySQL,因為軟體本身設計問題(當然它誕生的時候沒有這麼多資料要存)主從是要各自擁有一份完整資料。

PolarDB不用因為slave的增加而額外增加存儲成本,因為叢集所有的計算節點都是共享這一份資料的,為我們節省了大量的存儲空間。

私信服務MySQL遷移到PolarDB實戰
私信服務MySQL遷移到PolarDB實戰

遷移實施政策

遷移方案概述

遷移方案我們考慮了停服遷移與線上遷移兩種政策,最終我們采用了線上遷移政策。

通過建立新的PolarDB執行個體,并開啟DTS資料同步。在資料同步追上後,我們選擇了業務低峰期進行遷移切換,以最大程度保持對業務無感。

離線遷移步驟

  1. 建立PolarDB For MySQL 執行個體
  2. 開啟DTS資料同步
  3. 等到資料同步追上後,找個低峰時間停止服務Pod,繼續等DTS同步完全一緻
  4. 程式中修改資料庫連結到PolarDB
  5. 繼續釋出上線
  6. 遷移完成

線上遷移步驟

遷移前準備階段:

  1. DBA:提前建立 PolarDB For MySQL 執行個體
  2. DBA:開啟DTS資料同步
  3. 研發:程式改造
    1. 添加雙寫連接配接資訊,讓程式中同時存在連接配接 MySQL和 PolarDB的連接配接池
    2. 停止寫入資料改造,因為我們資料庫前面有一層 Redis緩存,是以我們可以讓資料寫寫入緩存,延遲寫入 MySQL,具體改造如下:
      1. Add操作:使用 Chan 暫時将寫入資料儲存起來
      2. Update、Delete 操作:使用 Sleep 阻塞資料庫 Goroutine 執行
    3. 添加遷移開關,使用 Redis 控制每一步的遷移狀态
      1. 1:讀寫MySQL
      2. 2:停止程式寫入
      3. 3:雙寫,讀PolarDB
      4. 4:讀寫PolarDB

遷移過程中:

  1. 研發:找到業務低峰期,設定開關狀态為 2,停止寫入資料
  2. DBA:觀察 DTS 将MySQL資料全部同步到 PolarDB後停止 DTS,該過程大概持續1-2分鐘
  3. 研發:設定開關狀态為 3,開始雙寫
  4. 研發、DBA:觀察兩個資料庫的記錄行數是否一緻、觀察錯誤日志、App上發送私信驗證是否可用

遷移完成後:

  1. 研發:如果發現有錯誤,設定開關狀态為 1,切回讀寫MySQL
  2. 研發:觀察 1、2 天時間,如果完全沒問題,設定開關狀态為 4,完全讀寫PolarDB,并删除程式中連接配接的 MySQL資訊,替換為 PolarDB連接配接資訊,代碼中去掉開關邏輯并從新釋出項目
  3. DBA:觀察MySQL是否還有流量,如果沒有則下掉執行個體
  4. 遷移完成
私信服務MySQL遷移到PolarDB實戰

線上遷移詳解

我們的目的是通過一個Redis開關,讓程式支援在MySQL, PolarDB之間随時切換、以及停止寫入的能力,這樣我們就能保證在MySQL中的資料完全同步到PolarDB之後, 此時MySQL和PolarDb資料完全一緻,最後在讓流量雙寫MySQL、 PolarDB。如果發現有異常可以在全部切回MySQL,否則全部切到PolarDB完成資料庫切換,之後下掉開關,代碼中完全換成讀寫PolarDB在釋出一次。

以上過程有個問題,如何在運作時停止寫入資料呢?比如add, delete, upate 操作,分析代碼後我們發現可以使用 Channel暫存、延緩goroutine執行方法解決。具體這種政策也要結合業務看是否能接受短暫的1,2分鐘資料不一緻。如果能接受的話,接下來就分析在這1,2分鐘内暫存的Channels資料和阻塞的 Goroutine 能占用多大記憶體,是否需要提前增加記憶體,找到一天中流量最少的時刻通過計算這個時間的寫 QPS計算需要多少緩沖區的 Chan,以及需要阻塞多少 Goroutine,算下來之後完全可以接受,同時這些步驟都要最好日志記錄。

舉個例子:比如在淩晨 6 點業務低峰,Add操作 500 QPM,Update操作 100 QPM,總共業務執行個體 pod 10 個,計算可得:

Add: 500 / 10 = 50 Channel緩沖區長度

Update: 100 / 10 = 10 Goroutine數量

也就是每個Pod在這一分鐘内最多增加 10個協程、暫存50個通道資料,這點資料在轉換為記憶體完全沒啥影響。

以下是整個過程的開關狀态流轉圖,如下:

私信服務MySQL遷移到PolarDB實戰
私信服務MySQL遷移到PolarDB實戰

遷移後PolarDB名額

遷移後 PolarDB 監控名額也滿足預期

私信服務MySQL遷移到PolarDB實戰

總結

注意事項

  1. 停止寫入過程如果出現 Panic 記憶體資料會丢失這是一個問題,是以要注意測試環境演練代碼确定沒問題,并記錄日志保險起見使用挂載的持久存儲卷,這樣就是真的 Pod 退出還能有地方恢複資料。
  2. 線上遷移需要完全掌握目前業務代碼,不能漏掉資料庫操作,否則會導緻資料資料遷移不完整。

遷移成果

  1. 相對離線停服遷移對業務影響較小
  2. 遷移後相對之前MySQL成本下降18%
  3. P99耗時40MS左右,符合業務預期
  4. 遷移後計算、存儲分離。存儲最大支援 100TB

作者:王繼超

來源-微信公衆号:映客技術

出處:https://mp.weixin.qq.com/s/AywOQDw4t_XmChZ0TU_YIA

繼續閱讀