數據庫集羣實施

分佈式數據方案提供功能如下:

(1)提供分庫規則和路由規則(RouteRule簡稱RR),將上面的說明中提到的三中切分規則直接內嵌入本系統,具體的嵌入方式在接下來的內容中進行詳細的說明和論述;

(2)引入集羣(Group)的概念,保證數據的高可用性;

(3)引入負載均衡策略(LoadBalancePolicy簡稱LB);

(4)引入集羣節點可用性探測機制,對單點機器的可用性進行定時的偵測,以保證LB策略的正確實施,以確保系統的高度穩定性;

(5)引入讀/寫分離,提高數據的查詢速度;

僅僅是分庫分表的數據層設計也是不夠完善的,當某個節點上的DB服務器出現了宕機的情況的時候,會是什麼樣的呢?是的,我們採用了數據庫切分方案,也就是說有N太機器組成了一個完整的DB ,如果有一臺機器宕機的話,也僅僅是一個DB的N分之一的數據不能訪問而已,這是我們能接受的,起碼比切分之前的情況好很多了,總不至於整個DB都不能訪問。一般的應用中,這樣的機器故障導致的數據無法訪問是可以接受的,假設我們的系統是一個高併發的電子商務網站呢?單節點機器宕機帶來的經濟損失是非常嚴重的。也就是說,現在我們這樣的方案還是存在問題的,容錯性能是經不起考驗的。當然了,問題總是有解決方案的。我們引入集羣的概念,在此我稱之爲Group,也就是每一個分庫的節點我們引入多臺機器,每臺機器保存的數據是一樣的,一般情況下這多臺機器分攤負載,當出現宕機情況,負載均衡器將分配負載給這臺宕機的機器。這樣一來,

就解決了容錯性的問題。所以我們引入了集羣的概念,並將其內嵌入我們的框架中,成爲框架的一部分。

如上圖所示,整個數據層有Group1,Group2,Group3三個集羣組成,這三個集羣就是數據水平切分的結果,當然這三個集羣也就組成了一個包含完整數據的DB。每一個Group包括1個Master(當然Master也可以是多個)和 N個Slave,這些Master和Slave的數據是一致的。比如Group1中的一個slave發生了宕機現象,那麼還有兩個slave是可以用的,這樣的模型總是不會造成某部分數據不能訪問的問題,除非整個 Group裏的機器全部宕掉,但是考慮到這樣的事情發生的概率非常小(除非是斷電了,否則不易發生吧)。

在沒有引入集羣以前,我們的一次查詢的過程大致如下:請求數據層,並傳遞必要的分庫區分字段(通常情況下是user_id)?數據層根據區分字段Route到具體的DB?在這個確定的DB內進行數據操作。 這是沒有引入集羣的情況,當時引入集羣會是什麼樣子的呢?看圖一即可得知,我們的路由器上規則和策略其實只能路由到具體的Group,也就是隻能路由到一個虛擬的Group,這個Group並不是某個特定的物理服務器。接下來需要做的工作就是找到具體的物理的DB服務器,以進行具體的數據操作。基於這個環節的需求,我們引入了負載均衡器的概念(LB)。負載均衡器的職責就是定位到一臺具體的DB服務器。具體的規則如下:負載均衡器會分析當前sql的讀寫特性,如果是寫操作或者是要求實時性很強的操作的話,直接將查詢負載分到Master,如果是讀操作則通過負載均衡策略分配一個Slave。我們的負載均衡器的主要研究放向也就是負載分發策略,通常情況下負載均衡包括隨機負載均衡和加權負載均衡 。 隨機負載均衡很好理解,就是從N個Slave中隨機選取一個Slave。這樣的隨機負載均衡是不考慮機器性能的,它默認爲每臺機器的性能是一樣的。假如真實的情況是這樣的,這樣做也是無可厚非的。假如實際情況並非如此呢?每個Slave的機器物理性能和配置不一樣的情況,再使用隨機的不考慮性能的負載均衡,是非常不科學的,這樣一來會給機器性能差的機器帶來不必要的高負載,甚至帶來宕機的危險, 同時高性能的數據庫服務器也不能充分發揮其物理性能。基於此考慮從,我們引入了加權負載均衡,也就是在我們的系統內部通過一定的接口,可以給每臺DB服務器分配一個權值,然後再運行時LB根據權值在集羣中的比重,分配一定比例的負載給該DB服務器。當然這樣的概念的引入,無疑增大了系統的複雜性和可維護性。有得必有失,我們也沒有辦法逃過的。

有了分庫,有了集羣,有了負載均衡器,是不是就萬事大吉了呢? 事情遠沒有我們想象的那麼簡單。雖然有了這些東西,基本上能保證我們的數據層可以承受很大的壓力 ,但是這樣的設計並不能完全規避數據庫宕機的危害。假如Group1中的slave2 宕機了,那麼系統的LB並不能得知,這樣的話其實是很危險的,因爲LB不知道,它還會以爲slave2爲可用狀態,所以還是會給slave2分配負載。這樣一來,問題就出來了,客戶端很自然的就會發生數據操作失敗的錯誤或者異常。這樣是非常不友好的!怎樣解決這樣的問題呢? 我們引入集羣節點的可用性探測機制 ,或者是可用性的數據推送機制 。這兩種機制有什麼不同呢?首先說探測機制吧,顧名思義,探測即使,就是我的數據層客戶端,不定時對集羣中各個數據庫進行可用性的嘗試,實現原理就是嘗試性鏈接,或者數據庫端口的嘗試性訪問,都可以做到,當然也可以用JDBC嘗試性鏈接,利用Java的Exception機制進行可用性的判斷,具體的會在後面的文字中提到。那數據推送機制又是什麼呢?其實這個就要放在現實的應用場景中來討論這個問題了,一般情況下應用的DB 數據庫宕機的話我相信DBA肯定是知道的,這個時候DBA手動的將數據庫的當前狀態通過程序的方式推送到客戶端,也就是分佈式數據層的應用端,這個時候在更新一個本地的DB狀態的列表。並告知LB,這個數據庫節點不能使用,請不要給它分配負載。一個是主動的監聽機制,一個是被動的被告知的機制。兩者各有所長。但是都可以達到同樣的效果。這樣一來剛纔假設的問題就不會發生了,即使就是發生了,那麼發生的概率也會降到最低。

上面的文字中提到的Master和Slave ,我們並沒有做太多深入的講解。如圖一所示,一個Group由1個Master和N個Slave組成。爲什麼這麼做呢?其中Master負責寫操作的負載,也就是說一切寫的操作都在Master上進行,而讀的操作則分攤到Slave上進行。這樣一來的可以大大提高讀取的效率。在一般的互聯網應用中,經過一些數據調查得出結論,讀/寫的比例大概在 10:1左右 ,也就是說大量的數據操作是集中在讀的操作,這也就是爲什麼我們會有多個Slave的原因。但是爲什麼要分離讀和寫呢?熟悉DB的研發人員都知道,寫操作涉及到鎖的問題,不管是行鎖還是表鎖還是塊鎖,都是比較降低系統執行效率的事情。我們這樣的分離是把寫操作集中在一個節點上,而讀操作其其他的N個節點上進行,從另一個方面有效的提高了讀的效率,保證了系統的高可用性。讀寫分離也會引入新的問題,比如我的Master上的數據怎樣和集羣中其他的Slave機器保持數據的同步和一致呢?這個是我們不需要過多的關注的問題,MySql的Proxy機制可以幫助我們做到這點,由於Proxy機制與本課題相關性不是太強,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章