在互聯(lián)網(wǎng)初創(chuàng )時(shí)期,企業(yè)往往采用單體架構去搭建自己的應用系統,但是,隨著(zhù)企業(yè)的不斷壯大,系統訪(fǎng)問(wèn)量不斷隨之上升,數據量也急劇增長(cháng)。數據的存儲是首先要解決的問(wèn)題,在這個(gè)大數據時(shí)代,數據就是企業(yè)的命根子,數據庫的單體架構很難滿(mǎn)足數據的存儲,這時(shí),我們要對數據進(jìn)行切分,數據的切分又分為垂直切分和水平切分。
在數據切分之前,我們的所有業(yè)務(wù)都放在一個(gè)數據庫中,比如:我們的用戶(hù)業(yè)務(wù),商品業(yè)務(wù),訂單業(yè)務(wù)。數據庫的架構如下:
在業(yè)務(wù)發(fā)展到一定規模時(shí),一個(gè)數據庫很難滿(mǎn)足數據的存儲,并且導致數據的訪(fǎng)問(wèn)比較慢,導致用戶(hù)的流失。這時(shí),我們要對數據進(jìn)行切分,使其從單一的數據庫的存儲分散到多個(gè)數據庫的存儲。在進(jìn)行數據切分時(shí),我們要遵循先垂直后水平的原則。
數據的垂直切分也就是數據的縱向切分,按照業(yè)務(wù)將數據進(jìn)行切分。在上面的例子中,我們將一個(gè)數據庫切分為:用戶(hù)庫,商品庫,訂單庫。將原來(lái)的一個(gè)數據庫分為了三個(gè)數據庫,分散了數據的存儲壓力,同時(shí)也分散了數據的讀取壓力。如圖所示:
但是,隨著(zhù)業(yè)務(wù)的發(fā)展,單個(gè)業(yè)務(wù)庫也會(huì )遇到存儲的瓶頸,比如:用戶(hù)的急劇增長(cháng),導致單一的用戶(hù)庫無(wú)法存儲,用戶(hù)訪(fǎng)問(wèn)的速度變慢等。這時(shí),我們就要對數據進(jìn)行水平切分了,將用戶(hù)按照某種規則平均分配到多個(gè)數據庫中,也就是將原來(lái)的單一的用戶(hù)庫進(jìn)行了水平擴展。如圖所示:
這里,我們只是水平的拆分了兩個(gè)庫,大家可以根據自己的系統情況,拆分成更多的數據庫。
數據庫的整體架構我們規劃好了,那么我們在進(jìn)行開(kāi)發(fā)的時(shí)候,怎么確定一條數據從哪個(gè)數據庫讀取呢?或者插入一條數據的時(shí)候,這條數據要插入到哪一個(gè)數據庫呢?數據庫的選擇是交給開(kāi)發(fā)人員負責呢?還是統一的設置一個(gè)代理層呢?開(kāi)發(fā)人員在開(kāi)發(fā)的時(shí)候,關(guān)注的焦點(diǎn)是業(yè)務(wù),復雜的業(yè)務(wù)已經(jīng)占據了他們大部分的精力,如果再讓他們去考慮數據庫的問(wèn)題,對他們的壓力是非常大的,而且每個(gè)開(kāi)發(fā)人員的代碼風(fēng)格也不一樣,導致項目混亂,臃腫,難以維護。所以,我們往往采用代理層統一處理數據的分片,這時(shí),我們的MyCAT分庫分表中間件就登場(chǎng)了,它去做統一的數據庫層的代理。如圖:
MyCAT統一做數據庫層的代理,對外暴露一個(gè)地址,應用系統直接連接MyCAT,就像連接普通的MySQL一樣,沒(méi)有任何的區別。所有的CRUD操作都直接對應MyCAT,再由MyCAT做具體的數據分片,數據分片的過(guò)程對于開(kāi)發(fā)人員來(lái)說(shuō)是透明的,不需要額外的處理,這樣,開(kāi)發(fā)人員只需要關(guān)注業(yè)務(wù)就可以了。
可用性對于一個(gè)系統來(lái)說(shuō)是非常重要的,尤其是在當今的互聯(lián)網(wǎng)時(shí)代,系統宕機1分鐘,帶來(lái)的損失都是非常嚴重的,所以,我們在搭建系統時(shí),往往采用集群方式,某一個(gè)節點(diǎn)的不可用,不影響整體系統的可用性。在前面的例子中,我們所有的節點(diǎn)都是單節點(diǎn),存在著(zhù)單點(diǎn)故障,這是我們不希望看到的,所以我們要搭建集群。6個(gè)業(yè)務(wù)數據庫我們都可以做主從,這時(shí),用戶(hù)1庫可以搭建為 用戶(hù)1(主)和用戶(hù)1(從),用戶(hù)2庫可以搭建為 用戶(hù)2(主)和用戶(hù)2(從)。訂單庫和商品庫也可以做同樣的操作,如圖:
這樣我們的業(yè)務(wù)數據庫不存在單點(diǎn)故障了,但是MyCAT成為了單點(diǎn),如果MyCAT發(fā)生故障,或者M(jìn)yCAT承載了大量的數據庫的請求,MyCAT成了整個(gè)系統的唯一瓶頸。那么MyCAT我們如何搭建集群呢?有的小伙伴可能會(huì )說(shuō)了,我們再部署一個(gè)MyCAT,這個(gè)MyCAT和前一個(gè)MyCAT配置一樣就可以了。是的,這只是其中的第一步,我們有了兩個(gè)MyCAT連接數據庫,那么我們的應用系統也需要連接兩個(gè)MyCAT嗎??jì)蓚€(gè)MyCAT我們要如何分配請求呢?這是不是又增加了應用系統的復雜性呢?所以,我們在兩個(gè)MyCAT上面再增加一個(gè)負載均衡器,它可以將請求按照某種規則分配到兩個(gè)MyCAT上,這個(gè)負載均衡器我們采用HAProxy。整體架構如圖:

這樣MyCAT的單點(diǎn)故障解決了,但是HAProxy又成了單點(diǎn),這是不是很有意思,似乎總有一個(gè)單點(diǎn)解決不了。在這里最后一個(gè)單點(diǎn)HAProxy,我們使用KeepAlived做故障轉移就可以解決了,兩個(gè)KeepAlived可以提供一個(gè)虛擬IP,業(yè)務(wù)系統直接連接這個(gè)虛擬IP,后面的過(guò)程對于應用系統是透明的。如圖所示:

這就是我們最終的數據庫架構,不存在任何的單點(diǎn)故障。
進(jìn)行了分庫分表后,隨之而來(lái)的問(wèn)題也就出現了,那就是ID的問(wèn)題和分布式事務(wù)的問(wèn)題,分布式ID和分布式事務(wù)在MyCAT中都有相應的解決方案,我們在MyCAT中進(jìn)行配置就可以了。
聯(lián)系客服