大家好,我是七淅(xī)。
如標題所說,本文會結合我自己的親身經歷,介紹 3 部分內容:
- 線上單庫單表變更到多庫多表的各個實現方案
- 方案優劣對比
- 對於歷史存在的單表,並且它們不需要變成多表,需要怎麼處理
先下個結論,沒有百分百完美的方案,技術方案永遠要結合產品業務來設計。
以下舉例的方案也只是較為通用的做法,具體細節是可以根據業務場景進行變化調整的。
只要能夠滿足業務需求,就是好方案,不要為了秀技術而忽略業務。
看完這篇文章,如果後面有人問你,關於變更到多庫多表的方案問題,那你可以和他談笑風生了。
好了,下面我說下我這邊的業務背景,和大家解釋清楚為什麼需要多庫多表。後面會引申出方案的,莫急。
1. 業務背景
有一個線上上執行著的資料庫,假設是 user 庫,庫中只有 1 張單表。
現在有個新需求,該需求的功能有一定的請求量和資料量。
其中資料量初期是百萬級,考慮到業務增加,增長到千萬、上億都是有可能的。所以從資料量上看,單庫單表不合適。
Q1:如果只是資料量問題,那用單庫多表行不行?
A1:行。
Q2:那為什麼還用多庫多表呢?
A2:因為一個資料庫的連線數量是有限的,怕翻車。
上面有介紹業務有一定的請求量,擔心一個庫來處理的話,萬一哪天網路不好/慢查/該表業務有突發性活動等情況出現。
一不小心就把連線數佔滿了,那就直接翻車了。
加上我司對多庫多表的基建比較成熟,所以我這邊就直接上多庫多表了。
Q3:既然如此,前期先上單庫多表,等量上來後再多庫多表行不行?
A3:可以。但是到時再來一次太累了。
比如再來一次會經歷以下事情:
- 每天需要看看資料監控
- 有沒有到瓶頸
- 到時再次變更時,開發運維測試業務的排期和執行
- 業務變動:說好的下個季度大推,結果提前到下一個月進行,此時資料庫能不能扛住,扛不住改造時間是否充足?
所以,我們要不還是一步到位吧。
滴,七淅提醒你:看到這,如果有人問你單庫多表和多庫多表的使用場景,你應該知道怎麼發揮了吧
2. 歷史資料處理
我先說下對歷史資料處理,篇幅較少。
這裡的內容對應文章開頭的第三點:對於歷史存在的單表,並且它們不需要變成多表,需要怎麼處理
這裡可以有兩種處理方式。
我們知道,歷史資料在 user 庫,假設業務需要增加到 8 個庫,並且新表需要在這 8 個庫中
2.1 方式一
新增 user_0、user_1、...、user_7
共 8 個庫,使用 rename
命令,將 user 庫的表遷移到 user_0
庫中,最後將 user 庫刪掉即可。
rename 命令其實就是重新命名,實現剪下資料的效果,而不是複製。當然要用複製的方式遷移資料也是可以的,但我們這邊沒用。
reanme 命令使用如下:
rename table user.table_name to user_0.table_name;
2.2 方式二
新增 user_0、user_1、...、user_7
共 8 個庫,user 庫資料不動,繼續使用。
至於選哪種方式,大多情況下,我個人認為都可以,但如果歷史表本身請求就很高,那可以考慮用方式二,避免 0 號庫壓力太大。
我這邊是選擇的方式一。當使用者要訪問歷史表時,指定路由到 0 號庫就好了,順便省下一臺資料庫的錢,真香
3. 變更方案
方案這塊內容,我會基於方式一的歷史資料處理方式來講。
首先,先不考慮任何方案,我把最簡單的,變更到多庫多表的操作按順序列舉一下:
- 修改服務連線資料庫的配置,業務程式碼編寫
- 增加 user 0-7 號資料庫
- 將 user 庫舊錶資料遷移到新增 user_0 庫
- 部署服務
但是如果按照上述做法,在第 3、4 步執行期間,如果使用者訪問原 user 庫的資料會有問題。
具體來說:user 庫的舊資料此時已經通過 rename,遷移到了 user_0 庫,但因為部署還沒部署完成,連線資料庫的配置沒有更新。
所以請求依舊會跑去 user 庫查詢,導致查不到資料,後續業務邏輯沒法順序繼續執行。
使用者也會納悶:「這個地方之前進來都有資料的呀,怎麼現在全空了?」
所以,需要確定合理的升級方案,最大程度減少對業務和使用者的影響,
3.1 方案一
這是最簡單的方式。
看監控,挑選沒有流量的時候,進行 db 變更和服務部署。
當然,監控也只是過去的情況,保不準功能上線那天就一直有流量沒停歇過呢。
所以再求穩一點的話,可以發個公告,告知使用者 xx 功能會在 xxx 時間段進行維護,期間不可訪問。
如果有玩農藥(王者榮耀)的朋友應該很熟悉吧,每次版本更新都需要停服,就是這樣的效果哈。
最後在完成之後,進行迴歸測試和新功能測試,看看功能是否正常。
如果正常那就可以去睡覺了,有問題就繼續改 bug 解決;
如果評估沒法在公告所說的截止時間解決,那就只能進行回滾,改日再(jia)戰(ban)。
PS:如果需要對歷史資料進行分庫分表的話,最好進行資料量的對比檢驗。因為我這邊不涉及對歷史資料進行分庫分表,所以這步就省了。
3.2 方案二
這個方案會複雜很多,開發量也會很大。
我這邊就只說關鍵步驟,具體細節就沒法一一寫了。因為要寫的話又多出幾千字的內容,篇幅太長,我估計也沒多少人有耐心看完。
那話說回來,這個方案最大的好處就是業務功能不用停用,所以也就不用熬大夜了。
那要怎麼做呢?
3.2.1 歷史單表資料處理
1、先把 user 庫現有的資料複製一份到 user_0 庫。
2、因為 user 庫的資料是會被修改和新增的。所以當複製完成後,資料依舊存在變化,所以需要新增雙寫邏輯,保證 user_0 庫的資料也能同步到變更。
3、對於資料的讀寫,都支援由開關控制,分別可以控制資料讀寫是請求到哪個資料庫。
4、服務更新完成後,進行兩個庫的資料一致性對比。都沒問題後,開關控制讀寫資料都請求到 user_0 庫
3.2.2 新功能的多表資料處理
因為是新功能,其實不用怎麼特殊處理。
為什麼這麼說呢?
因為我們部署服務的順序肯定是運算元據庫的底層服務先發布,釋出完成後,才對用到底層服務的應用服務進行釋出。
所以作為業務功能入口的應用服務都還沒釋出,此時是不會有新功能資料到達底層服務的。
要是不能保證這個順序,你想下功能入口開放了,使用者請求進來後,底層服務發現找不到這個表,是不是就直接報錯了?
所以才會有上面說的釋出順序,只要保證釋出順序沒錯,那這塊新功能的資料是不需要特殊處理。
3.3 方案優劣對比
其實 2 個方案就是互補的,一個方案的優點就是解決了另一個方案的缺點。
七淅用表格總結一下:
優點 | 缺點 | |
---|---|---|
方案一 | 操作簡單,無需編寫複雜程式碼來保證有流量時,業務的正常執行 | 累人,熬大夜太酸爽了;會停用部分業務,影響使用者體驗 |
方案二 | 業務不必停用,不影響使用者 | 開發成本大 |
最後,你問我當初是選哪個方案?
那肯定是方案一啊,大不了熬一夜嘛。
不然那麼麻煩的方案,排期又那麼緊張,開發是不可能開發的,這輩子都不可能的。真有什麼問題,大不了就人工介入處理,yyds
文章首發公眾號:七淅在學Java ,持續原創輸出 Java 後端乾貨。
如果對你有幫助的話,可以給個贊再走嗎