數據庫的讀寫分離與負載均衡策略

最近工做室開始了一個項目,因爲需求方面的問題,數據庫的設計開始往中型電商系統靠近。也趁此機會,學習一下數據庫的優化策略,。sql

原文地址:blog.csdn.net/seudongnan/…數據庫

數據庫的優化策略

隨着互聯網的普及,電商行業的發展,一個大型的電商平臺將對數據庫形成極大的負載。爲了維持系統的穩定性和拓展性,經過數據切分來提升網站性能,橫向擴展數據層已經成爲架構人員首選方式。服務器

  • 水平切分數據庫:能夠下降單臺機器的負載,同時最大限度的下降了宕機產生的損失。
  • 負載均衡策略:能夠下降單臺機器的訪問負載,下降宕機的可能性。
  • 集羣方案:解決了數據庫宕機帶來的單點數據庫不能訪問的問題。
  • 讀寫分離策略:最大限度提升了應用中讀取數據的訪問量和併發量

基本原理

數據切分

數據切分(Sharding)是水平擴展(Scale Out,或叫作橫向擴展)的解決方案。markdown

Sharding的主要目的

突破單節點數據庫服務器的I/O能力限制,解決數據庫擴展性的問題。架構

Sharding的實現策略

Sharding的實現是經過一系列的切分策略,將數據水平切分到不一樣的Database或者table中。在查詢過程當中,經過必定的路由策略,找到須要查詢的具體Database或table,進行Query操做。併發

舉個例子:負載均衡

咱們要對一張article表進行切分,article中有兩個主要字段,article_iduser_id。咱們能夠採用這樣的切分策略:將user_id在1~10000的數據寫入DB1,10001~20000的數據寫入DB2,以此類推,這就是數據庫的切分。分佈式

固然,咱們將切分策略反轉,便可從一個給定的user_id來查詢到具體的記錄,這個過程被稱爲DB路由高併發

數據切分的方式

數據切分能夠是物理上的,也就是對數據進行一系列的切分策略,分佈到不一樣的DB服務器上,經過DB路由規則訪問相應的數據庫。以此下降單臺機器的負載壓力。oop

數據切分也能夠是數據庫內的,對數據進行一系列的切分策略,將數據分佈到一個數據庫不一樣的表中,好比將article分爲article_001article_002,若干個子表水平拼合有組成了邏輯上一個完整的article表,這樣作的目的其實也是很簡單的。舉個例子說明,好比article表中如今有5000w條數據,此時咱們須要在這個表中增長(insert)一條新的數據,insert完畢後,數據庫會針對這張表從新創建索引,5000w行數據創建索引的系統開銷仍是不容忽視的。可是反過來,假如咱們將這個表分紅100 個table呢,從article_001一直到article_100,5000w行數據平均下來,每一個子表裏邊就只有50萬行數據,這時候咱們向一張 只有50w行數據的table中insert數據後創建索引的時間就會呈數量級的降低,極大了提升了DB的運行時效率,提升了DB的併發量。固然分表的好處還不知這些,還有諸如寫操做的鎖操做等,都會帶來不少顯然的好處。

因而可知:分庫下降了單點機器的負載;分表,提升了數據操做的效率

接下來簡單瞭解一下分庫的方式和規則:

依然沿用以前的article表的例子

  • 號段分區

    user_id爲1~1000在DB1,1001~2000在DB2,以此類推

    • 優勢:可部分遷移
    • 缺點:數據分佈不均
  • hash取模分區

    user_id進行hash,而後用一個數字對應一個具體的DB。好比有4個數據庫,就將user_id%4,結果爲0的對應DB1,結果爲1的對應DB2,以此類推。這樣一來就能夠將數據均勻分佈。

    • 優勢:數據分佈均勻
    • 缺點:數據遷移麻煩,不能按照機器性能分攤數據
  • 在認證庫中保存數據庫配置

    就是創建一個DB,這個DB單獨保存user_id到DB的映射關係,每次訪問數據庫的時候都要先查詢一次這個數據庫,以獲得具體的DB信息,而後才能進行咱們須要的查詢操做。

    • 優勢:靈活性強,一對一關係
    • 缺點:每次查詢以前都要多一次查詢,性能大打折扣

分佈式數據方案

  • 提供分庫規則和路由規則(RouteRule簡稱RR)

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

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

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

  • 引入讀/寫分離,提升數據的查詢速度。

集羣

僅僅是分庫分表的數據層設計也是不夠完善的,當咱們採用了數據庫切分方案,也就是說有N臺機器組成了一個完整的DB 。若是有一臺機器宕機的話,也僅僅是一個DB的N分之一的數據不能訪問而已,這是咱們能接受的,起碼比切分以前的狀況好不少了,總不至於整個DB都不能訪問。

通常的應用中,這樣的機器故障致使的數據沒法訪問是能夠接受的,假設咱們的系統是一個高併發的電子商務網站呢?單節點機器宕機帶來的經濟損失是很是嚴重的。也就是說,如今咱們這樣的方案仍是存在問題的,容錯性能是經不起考驗的。

問題老是有解決方案的。咱們引入集羣的概念,在此我稱之爲Group,也就是每個分庫的節點咱們引入多臺機器,每臺機器保存的數據是同樣的,通常狀況下這多臺機器分攤負載,當出現宕機狀況,負載均衡器將分配負載給這臺宕機的機器。這樣一來,就解決了容錯性的問題。

如上圖所示,整個數據層有Group1Group2Group3三個集羣組成,這三個集羣就是數據水平切分的結果,固然這三個集羣也就組成了一個包含完整數據的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分配負載。這樣一來,問題就出來了,客戶端很天然的就會發生數據操做失敗的錯誤或者異常。

怎樣解決這樣的問題呢?咱們引入集羣節點的可用性探測機制,或者是可用性的數據推送機制。這兩種機制有什麼不一樣呢?首先說探測機制吧,顧名思義,探測即便,就是個人數據層客戶端,不定時對集羣中各個數據庫進行可用性的嘗試,實現原理就是嘗試性連接,或者數據庫端口的嘗試性訪問,均可以作到。

那數據推送機制又是什麼呢?其實這個就要放在現實的應用場景中來討論這個問題了,通常狀況下應用的DB 數據庫宕機的話我相信DBA確定是知道的,這個時候DBA手動的將數據庫的當前狀態經過程序的方式推送到客戶端,也就是分佈式數據層的應用端,這個時候在更新一個本地的DB狀態的列表。並告知LB,這個數據庫節點不能使用,請不要給它分配負載。一個是主動的監聽機制,一個是被動的被告知的機制。二者各有所長。可是均可以達到一樣的效果。這樣一來剛纔假設的問題就不會發生了,即便就是發生了,那麼發生的機率也會降到最低。

上面的文字中提到的MasterSlave ,咱們並無作太多深刻的講解。一個Group由1個Master和N個Slave組成。爲何這麼作呢?其中Master負責寫操做的負載,也就是說一切寫的操做都在Master上進行,而讀的操做則分攤到Slave上進行。這樣一來的能夠大大提升讀取的效率。在通常的互聯網應用中,通過一些數據調查得出結論,讀/寫的比例大概在 10:1左右 ,也就是說大量的數據操做是集中在讀的操做,這也就是爲何咱們會有多個Slave的緣由。

可是爲何要分離讀和寫呢?熟悉DB的研發人員都知道,寫操做涉及到鎖的問題,無論是行鎖仍是表鎖仍是塊鎖,都是比較下降系統執行效率的事情。咱們這樣的分離是把寫操做集中在一個節點上,而讀操做其其餘 的N個節點上進行,從另外一個方面有效的提升了讀的效率,保證了系統的高可用性。

相關文章
相關標籤/搜索