一億數(shù)據(jù)量 MySQL,怎么秒級平滑擴(kuò)容?
數(shù)據(jù)庫秒級平滑擴(kuò)容,這個(gè)問題之前寫過,上周有個(gè)童鞋在評論區(qū)問我,說找不到原文了。這個(gè)方案實(shí)操性很強(qiáng),曾經(jīng)在58我們就是這么玩的。
另外,思路比結(jié)論更重要。

一般來說,并發(fā)量大,吞吐量大的互聯(lián)網(wǎng)分層架構(gòu)是怎么樣的?
數(shù)據(jù)庫上層都有一個(gè)微服務(wù),服務(wù)層記錄“業(yè)務(wù)庫”與“數(shù)據(jù)庫實(shí)例配置”的映射關(guān)系,通過數(shù)據(jù)庫連接池向數(shù)據(jù)庫路由sql語句。

如上圖所示,服務(wù)層配置用戶庫user對應(yīng)的數(shù)據(jù)庫實(shí)例ip。
畫外音:其實(shí)是一個(gè)內(nèi)網(wǎng)域名。
該分層架構(gòu),如何應(yīng)對數(shù)據(jù)庫的高可用?
數(shù)據(jù)庫高可用,很常見的一種方式,使用雙主同步+keepalived+虛ip的方式進(jìn)行。

如上圖所示,兩個(gè)相互同步的主庫使用相同的虛ip。

當(dāng)主庫掛掉的時(shí)候,虛ip自動(dòng)漂移到另一個(gè)主庫,整個(gè)過程對調(diào)用方透明,通過這種方式保證數(shù)據(jù)庫的高可用。
畫外音:關(guān)于高可用,之前介紹過,本文不再展開。
該分層架構(gòu),如何應(yīng)對數(shù)據(jù)量的暴增?
隨著數(shù)據(jù)量的增大,數(shù)據(jù)庫要進(jìn)行水平切分,分庫后將數(shù)據(jù)分布到不同的數(shù)據(jù)庫實(shí)例(甚至物理機(jī)器)上,以達(dá)到降低數(shù)據(jù)量,增強(qiáng)性能的擴(kuò)容目的。

如上圖所示,用戶庫user分布在兩個(gè)實(shí)例上,ip0和ip1,服務(wù)層通過用戶標(biāo)識uid取模的方式進(jìn)行尋庫路由,模2余0的訪問ip0上的user庫,模2余1的訪問ip1上的user庫。
畫外音:此時(shí),水平切分集群的讀寫實(shí)例加倍,單個(gè)實(shí)例的數(shù)據(jù)量減半,性能增長可不止一倍。
綜上三點(diǎn)所述,大數(shù)據(jù)量,高可用的互聯(lián)網(wǎng)微服務(wù)分層的架構(gòu)如下:

既有水平切分,又保證高可用。
如果數(shù)據(jù)量持續(xù)增大,2個(gè)庫性能扛不住了,該怎么辦呢?
此時(shí),需要繼續(xù)水平拆分,拆成更多的庫,降低單庫數(shù)據(jù)量,增加庫主庫實(shí)例(機(jī)器)數(shù)量,提高性能。
新的問題來了,分成n個(gè)庫后,隨著數(shù)據(jù)量的增加,要增加到2*n個(gè)庫,數(shù)據(jù)庫如何擴(kuò)容,數(shù)據(jù)能否平滑遷移,能夠持續(xù)對外提供服務(wù),保證服務(wù)的可用性?
畫外音:你遇到過類似的問題么?
停服擴(kuò)容,是最容易想到的方案?
在討論秒級平滑擴(kuò)容方案之前,先簡要說明下停服擴(kuò)容的方案的步驟:
(1) 站點(diǎn)掛一個(gè)公告“為了為廣大用戶提供更好的服務(wù),本站點(diǎn)/游戲?qū)⒃诮裢?0:00-2:00之間升級,屆時(shí)將不能登錄,用戶周知”;
畫外音:見過這樣的公告么,實(shí)際上在遷移數(shù)據(jù)。
(2) 微服務(wù)停止服務(wù),數(shù)據(jù)庫不再有流量寫入;
(3) 新建2*n個(gè)新庫,并做好高可用;
(4) 寫一個(gè)小腳本進(jìn)行數(shù)據(jù)遷移,把數(shù)據(jù)從n個(gè)庫里select出來,insert到2*n個(gè)庫里;
(5) 修改微服務(wù)的數(shù)據(jù)庫路由配置,模n變?yōu)槟?*n;
(6) 微服務(wù)重啟,連接新庫重新對外提供服務(wù);
整個(gè)過程中,最耗時(shí)的是第四步數(shù)據(jù)遷移。
如果出現(xiàn)問題,如何進(jìn)行回滾?
如果數(shù)據(jù)遷移失敗,或者遷移后測試失敗,則將配置改回舊庫,恢復(fù)服務(wù)即可。
停服方案有什么優(yōu)劣?
優(yōu)點(diǎn):簡單。
缺點(diǎn):
- 需要停止服務(wù),方案不高可用;
- 技術(shù)同學(xué)壓力大,所有工作要在規(guī)定時(shí)間內(nèi)完成,根據(jù)經(jīng)驗(yàn),壓力越大越容易出錯(cuò);
畫外音:這一點(diǎn)很致命。
- 如果有問題第一時(shí)間沒檢查出來,啟動(dòng)了服務(wù),運(yùn)行一段時(shí)間后再發(fā)現(xiàn)有問題,則難以回滾,如果回檔會丟失一部分?jǐn)?shù)據(jù);
有沒有秒級實(shí)施、更平滑、更帥氣的方案呢?

再次看一眼擴(kuò)容前的架構(gòu),分兩個(gè)庫,假設(shè)每個(gè)庫1億數(shù)據(jù)量,如何平滑擴(kuò)容,增加實(shí)例數(shù),降低單庫數(shù)據(jù)量呢?三個(gè)簡單步驟搞定。
步驟一:修改配置。

主要修改兩處:
其一,數(shù)據(jù)庫實(shí)例所在的機(jī)器做雙虛ip:
- 原%2=0的庫是虛ip0,現(xiàn)增加一個(gè)虛ip00;
- 原%2=1的庫是虛ip1,現(xiàn)增加一個(gè)虛ip11;
其二,修改服務(wù)的配置,將2個(gè)庫的數(shù)據(jù)庫配置,改為4個(gè)庫的數(shù)據(jù)庫配置,修改的時(shí)候要注意舊庫與新庫的映射關(guān)系:
- %2=0的庫,會變?yōu)?4=0與%4=2;
- %2=1的部分,會變?yōu)?4=1與%4=3;
畫外音:這樣能夠保證,依然路由到正確的數(shù)據(jù)。
步驟二:reload配置,實(shí)例擴(kuò)容。

服務(wù)層reload配置,reload可能是這么幾種方式:
- 比較原始的,重啟服務(wù),讀新的配置文件;
- 高級一點(diǎn)的,配置中心給服務(wù)發(fā)信號,重讀配置文件,重新初始化數(shù)據(jù)庫連接池;
不管哪種方式,reload之后,數(shù)據(jù)庫的實(shí)例擴(kuò)容就完成了,原來是2個(gè)數(shù)據(jù)庫實(shí)例提供服務(wù),現(xiàn)在變?yōu)?個(gè)數(shù)據(jù)庫實(shí)例提供服務(wù),這個(gè)過程一般可以在秒級完成。

整個(gè)過程可以逐步重啟,對服務(wù)的正確性和可用性完全沒有影響:
- 即使%2尋庫和%4尋庫同時(shí)存在,也不影響數(shù)據(jù)的正確性,因?yàn)榇藭r(shí)仍然是雙主數(shù)據(jù)同步的;
- 即使%4=0與%4=2的尋庫落到同一個(gè)數(shù)據(jù)庫實(shí)例上,也不影響數(shù)據(jù)的正確性,因?yàn)榇藭r(shí)仍然是雙主數(shù)據(jù)同步的;
完成了實(shí)例的擴(kuò)展,會發(fā)現(xiàn)每個(gè)數(shù)據(jù)庫的數(shù)據(jù)量依然沒有下降,所以第三個(gè)步驟還要做一些收尾工作。
畫外音:這一步,數(shù)據(jù)庫實(shí)例個(gè)數(shù)加倍了。
步驟三:收尾工作,數(shù)據(jù)收縮。

有這些一些收尾工作:
- 把雙虛ip修改回單虛ip;
- 解除舊的雙主同步,讓成對庫的數(shù)據(jù)不再同步增加;
- 增加新的雙主同步,保證高可用;
- 刪除掉冗余數(shù)據(jù),例如:ip0里%4=2的數(shù)據(jù)全部刪除,只為%4=0的數(shù)據(jù)提供服務(wù);
畫外音:這一步,數(shù)據(jù)庫單實(shí)例數(shù)據(jù)量減半了。
總結(jié)

互聯(lián)網(wǎng)大數(shù)據(jù)量,高吞吐量,高可用微服務(wù)分層架構(gòu),數(shù)據(jù)庫實(shí)現(xiàn)秒級平滑擴(kuò)容的三個(gè)步驟為:
- 修改配置(雙虛ip,微服務(wù)數(shù)據(jù)庫路由);
- reload配置,實(shí)例增倍完成;
- 刪除冗余數(shù)據(jù)等收尾工作,數(shù)據(jù)量減半完成;
知其然,知其所以然。
思路比結(jié)論更重要。





























