58沈劍:數(shù)據(jù)庫秒級平滑擴容架構(gòu)方案
一、緣起
(1)并發(fā)量大,流量大的互聯(lián)網(wǎng)架構(gòu),一般來說,數(shù)據(jù)庫上層都有一個服務層,服務層記錄了“業(yè)務庫名”與“數(shù)據(jù)庫實例”的映射關系,通過數(shù)據(jù)庫連接池向數(shù)據(jù)庫路由sql語句以執(zhí)行:
如上圖:服務層配置用戶庫user對應的數(shù)據(jù)庫實例物理位置為ip(其實是一個內(nèi)網(wǎng)域名)。
(2)隨著數(shù)據(jù)量的增大,數(shù)據(jù)要進行水平切分,分庫后將數(shù)據(jù)分布到不同的數(shù)據(jù)庫實例(甚至物理機器)上,以達到降低數(shù)據(jù)量,增強性能的擴容目的:
如上圖:用戶庫user分布在兩個實例上,ip0和ip1,服務層通過用戶標識uid取模的方式進行尋庫路由,模2余0的訪問ip0上的user庫,模2余1的訪問ip1上的user庫。
關于數(shù)據(jù)庫水平切分,垂直切分的更多細節(jié),詳見《一分鐘掌握數(shù)據(jù)庫垂直拆分》 。
(3)互聯(lián)網(wǎng)架構(gòu)需要保證數(shù)據(jù)庫高可用,常見的一種方式,使用雙主同步+keepalived+虛ip的方式保證數(shù)據(jù)庫的可用性:
如上圖:兩個相互同步的主庫使用相同的虛ip。
如上圖:當主庫掛掉的時候,虛ip自動漂移到另一個主庫,整個過程對調(diào)用方透明,通過這種方式保證數(shù)據(jù)庫的高可用。
關于高可用的更多細節(jié),詳見《究竟啥才是互聯(lián)網(wǎng)架構(gòu)“高可用”》。
(4)綜合上文的(2)和(3),線上實際的架構(gòu),既有水平切分,又有高可用保證,所以實際的數(shù)據(jù)庫架構(gòu)是這樣的:
提問:如果數(shù)據(jù)量持續(xù)增大,分2個庫性能扛不住了,該怎么辦呢?
回答:繼續(xù)水平拆分,拆成更多的庫,降低單庫數(shù)據(jù)量,增加庫主庫實例(機器)數(shù)量,提高性能。
最終問題拋出:分成x個庫后,隨著數(shù)據(jù)量的增加,要增加到y(tǒng)個庫,數(shù)據(jù)庫擴容的過程中,能否平滑,持續(xù)對外提供服務,保證服務的可用性,是本文要討論的問題。
二、停服務方案
在討論平滑方案之前,先簡要說明下“x庫拆y庫”停服務的方案:
(1)站點掛一個公告“為了為廣大用戶提供更好的服務,本站點/游戲?qū)⒃诮裢?0:00-2:00之間升級,屆時將不能登錄,用戶周知”
(2)停服務
(3)新建y個庫,做好高可用
(4)數(shù)據(jù)遷移,重新分布,寫一個數(shù)據(jù)遷移程序,從x個庫里導入到y(tǒng)個庫里,路由規(guī)則由%x升級為%y
(5)修改服務配置,原來x行配置升級為y行
(6)重啟服務,連接新庫重新對外提供服務
整個過程中,最耗時的是第四步數(shù)據(jù)遷移。
回滾方案:
如果數(shù)據(jù)遷移失敗,或者遷移后測試失敗,則將配置改回x庫,恢復服務,改天再掛公告。
方案優(yōu)點:簡單
方案缺點:
(1)停服務,不高可用
(2)技術同學壓力大,所有工作要在規(guī)定時間內(nèi)做完,根據(jù)經(jīng)驗,壓力越大約容易出錯(這一點很致命)
(3)如果有問題***時間沒檢查出來,啟動了服務,運行一段時間后再發(fā)現(xiàn)有問題,難以回滾,需要回檔,可能會丟失一部分數(shù)據(jù)
有沒有更平滑的方案呢?
三、秒級、平滑、帥氣方案
再次看一眼擴容前的架構(gòu),分兩個庫,假設每個庫1億數(shù)據(jù)量,如何平滑擴容,增加實例數(shù),降低單庫數(shù)據(jù)量呢?三個簡單步驟搞定。
(1)修改配置
主要修改兩處:
a)數(shù)據(jù)庫實例所在的機器做雙虛ip,原來%2=0的庫是虛ip0,現(xiàn)在增加一個虛ip00,%2=1的另一個庫同理
b)修改服務的配置(不管是在配置文件里,還是在配置中心),將2個庫的數(shù)據(jù)庫配置,改為4個庫的數(shù)據(jù)庫配置,修改的時候要注意舊庫與辛苦的映射關系:
%2=0的庫,會變?yōu)?4=0與%4=2;
%2=1的部分,會變?yōu)?4=1與%4=3;
這樣修改是為了保證,拆分后依然能夠路由到正確的數(shù)據(jù)。
(2)reload配置,實例擴容
服務層reload配置,reload可能是這么幾種方式:
a)比較原始的,重啟服務,讀新的配置文件
b)高級一點的,配置中心給服務發(fā)信號,重讀配置文件,重新初始化數(shù)據(jù)庫連接池
不管哪種方式,reload之后,數(shù)據(jù)庫的實例擴容就完成了,原來是2個數(shù)據(jù)庫實例提供服務,現(xiàn)在變?yōu)?個數(shù)據(jù)庫實例提供服務,這個過程一般可以在秒級完成。
整個過程可以逐步重啟,對服務的正確性和可用性完全沒有影響:
a)即使%2尋庫和%4尋庫同時存在,也不影響數(shù)據(jù)的正確性,因為此時仍然是雙主數(shù)據(jù)同步的
b)服務reload之前是不對外提供服務的,冗余的服務能夠保證高可用
完成了實例的擴展,會發(fā)現(xiàn)每個數(shù)據(jù)庫的數(shù)據(jù)量依然沒有下降,所以第三個步驟還要做一些收尾工作。
(3)收尾工作,數(shù)據(jù)收縮
有這些一些收尾工作:
a)把雙虛ip修改回單虛ip
b)解除舊的雙主同步,讓成對庫的數(shù)據(jù)不再同步增加
c)增加新的雙主同步,保證高可用
d)刪除掉冗余數(shù)據(jù),例如:ip0里%4=2的數(shù)據(jù)全部干掉,只為%4=0的數(shù)據(jù)提供服務啦
這樣下來,每個庫的數(shù)據(jù)量就降為原來的一半,數(shù)據(jù)收縮完成。
四、總結(jié)
該帥氣方案能夠?qū)崿F(xiàn)n庫擴2n庫的秒級、平滑擴容,增加數(shù)據(jù)庫服務能力,降低單庫一半的數(shù)據(jù)量,其核心原理是:成倍擴容,避免數(shù)據(jù)遷移。
遷移步驟:
(1)修改配置
(2)reload配置,實例擴容完成
(3)刪除冗余數(shù)據(jù)等收尾工作,數(shù)據(jù)量收縮完成
【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者】