數據庫水平切分的實現原理解析---分庫,分表,主從,集羣,負載均衡器

第1章 引言

        隨着互聯網應用的廣泛普及,海量數據的存儲和訪問成爲了系統設計的瓶頸問題。對於一個大型的互聯網應用,每天幾十億的PV無疑對數據庫造成了相當高的負載。對於系統的穩定性和擴展性造成了極大的問題。通過數據切分來提高網站性能,橫向擴展數據層已經成爲架構研發人員首選的方式。

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

第2章 基本原理和概念

什麼是數據切分

        "Shard" 這個詞英文的意思是"碎片",而作爲數據庫相關的技術用語,似乎最早見於大型多人在線角色扮演遊戲中。"Sharding" 姑且稱之爲"分片"。Sharding 不是一個某個特定數據庫軟件附屬的功能,而是在具體技術細節之上的抽象處理,是水平擴展(Scale Out,亦或橫向擴展、向外擴展)的解決方案,其主要目的是爲突破單節點數據庫服務器的 I/O 能力限制,解決數據庫擴展性問題。通過一系列的切分規則將數據水平分佈到不同的DB或table中,在通過相應的DB路由或者table路由規則找到需要查詢的具體的DB或者table,以進行Query操作。“sharding”通常是指“水平切分”,這也是本文討論的重點。接下來舉個簡單的例子:我們針對一個Blog應用中的日誌來說明,比如日誌文章(article)表有如下字段:

        面對這樣的一個表,我們怎樣切分呢?怎樣將這樣的數據分佈到不同的數據庫中的表中去呢?我們可以這樣做,將user_id爲1~10000的所有的文章信息放入DB1中的article表中,將user_id爲10001~20000的所有文章信息放入DB2中的 article表中,以此類推,一直到DBn。這樣一來,文章數據就很自然的被分到了各個數據庫中,達到了數據切分的目的。

接下來要解決的問題就是怎樣找到具體的數據庫呢?其實問題也是簡單明顯的,既然分庫的時候我們用到了區分字段user_id,那麼很自然,數據庫路由的過程當然還是少不了user_id的。就是我們知道了這個blog的user_id,就利用這個user_id,利用分庫時候的規則,反過來定位具體的數據庫。比如user_id是234,利用剛纔的規則,就應該定位到DB1,假如user_id是12343,利用該才的規則,就應該定位到DB2。以此類推,利用分庫的規則,反向的路由到具體的DB,這個過程我們稱之爲“DB路由”。

平常我們會自覺的按照範式來設計我們的數據庫,考慮到數據切分的DB設計,將違背這個通常的規矩和約束。爲了切分,我們不得不在數據庫的表中出現冗餘字段,用作區分字段或者叫做分庫的標記字段。比如上面的article的例子中的user_id這樣的字段(當然,剛纔的例子並沒有很好的體現出user_id的冗餘性,因爲user_id這個字段即使就是不分庫,也是要出現的,算是我們撿了便宜吧)。當然冗餘字段的出現並不只是在分庫的場景下才出現的,在很多大型應用中,冗餘也是必須的,這個涉及到高效DB的設計,本文不再贅述。

爲什麼要數據切分

上面對什麼是數據切分做了個概要的描述和解釋,讀者可能會疑問,爲什麼需要數據切分呢?像 Oracle這樣成熟穩定的數據庫,足以支撐海量數據的存儲與查詢了?爲什麼還需要數據切片呢?

的確,Oracle的DB確實很成熟很穩定,但是高昂的使用費用和高端的硬件支撐不是每一個公司能支付的起的。試想一下一年幾千萬的使用費用和動輒上千萬元的小型機作爲硬件支撐,這是一般公司能支付的起的嗎?即使就是能支付的起,假如有更好的方案,有更廉價且水平擴展性能更好的方案,我們爲什麼不選擇呢?

我們知道每臺機器無論配置多麼好它都有自身的物理上限,所以當我們應用已經能觸及或遠遠超出單臺機器的某個上限的時候,我們惟有尋找別的機器的幫助或者繼續升級的我們的硬件,但常見的方案還是橫向擴展,通過添加更多的機器來共同承擔壓力。我們還得考慮當我們的業務邏輯不斷增長,我們的機器能不能通過線性增長就能滿足需求?Sharding可以輕鬆的將計算,存儲,I/O並行分發到多臺機器上,這樣可以充分利用多臺機器各種處理能力,同時可以避免單點失敗,提供系統的可用性,進行很好的錯誤隔離。

綜合以上因素,數據切分是很有必要的。 我們用免費的MySQL和廉價的Server甚至是PC做集羣,達到小型機+大型商業DB的效果,減少大量的資金投入,降低運營成本,何樂而不爲呢?所以,我們選擇Sharding,擁抱Sharding。

怎麼做到數據切分

    數據的切分(Sharding)根據其切分規則的類型,可以分爲兩種切分模式。一種是按照不同的表(或者Schema)來切分到不同的數據庫(主機)之上,這種切可以稱之爲數據的垂直(縱向)切分;另外一種則是根據表中的數據的邏輯關係,將同一個表中的數據按照某種條件拆分到多臺數據庫(主機)上面,這種切分稱之爲數據的水平(橫向)切分。

數據切分可以是物理上的,對數據通過一系列的切分規則將數據分佈到不同的DB服務器上,通過路由規則路由訪問特定的數據庫,這樣一來每次訪問面對的就不是單臺服務器了,而是N臺服務器,這樣就可以降低單臺機器的負載壓力。

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


綜上,分庫降低了單點機器的負載;分表,提高了數據操作的效率,尤其是Write操作的效率。行文至此我們依然沒有涉及到如何切分的問題。接下來,我們將對切分規則進行詳盡的闡述和說明。

常見的分庫、分表形式(垂直分表、垂直分庫、水平分表、水平分庫
        

  • 垂直分表:通俗的說法叫做“大表拆小表”,拆分是基於關係型數據庫中的“列”(字段)進行的。通常情況,某個表中的字段比較多,可以新建立一張“擴展表”,將不經常使用或者長度較大的字段拆分出去放到“擴展表”中。拆分到多臺數據庫(主機)上面,這種切分稱之爲數據的水平(橫向)切分。

    優點:拆分後業務清晰,拆分規則明確;便於開發和維護;避免“跨頁”的問題(MySQL、MSSQL底層都是通過“數據頁”來存儲的,“跨頁”問題可能會造成額外的性能開銷)。
    缺點:部分業務表無法 join,只能通過接口方式解決,提高了系統複雜度;受每種業務不同的限制存在單庫性能瓶頸,不易數據擴展跟性能提高;事務處理複雜。 

  • 垂直分庫:基本的思路就是按照業務模塊來劃分出不同的數據庫,而不是像早期一樣將所有的數據表都放到同一個數據庫中。

    ps:數據庫的連接資源比較寶貴且單機處理能力也有限,在高併發場景下,垂直分庫一定程度上能夠突破IO、連接數及單機硬件資源的瓶頸,是大型分佈式系統中優化數據庫架構的重要手段;由於垂直切分是按照業務的分類將表分散到不同的庫,所以有些業務表會過於龐大,存在單庫讀寫與存儲瓶 
    頸,所以就需要水平拆分來做解決。

  • 水平分表:水平分表也稱爲橫向分表,比較容易理解,就是將表中不同的數據行按照一定規律分佈到不同的數據庫表中(這些表保存在同一個數據庫中)。能夠降低單表的數據量,一定程度上可以緩解查詢性能瓶頸。但本質上這些表還保存在同一個庫中,所以庫級別還是會有IO瓶頸。所以,一般不建議採用這種做法。

    優點:降低單表數據量,優化查詢性能,提高了系統的穩定性跟負載能力;
    缺點:雖然分表了,但本質上這些表還保存在同一個庫中,所以庫級別還是會有IO瓶頸。所以,一般不建議採用這種做法;有些業務可能還存在查詢(根據指定條件查詢列表)、分頁、排序問題。

    最常見的分表方式就是通過主鍵或者時間等字段進行Hash和取模後拆分。

  • 水平分庫:水平分庫分表與上面講到的水平分表的思想相同,唯一不同的就是將這些拆分出來的表保存在不同的數據庫中。這也是很多大型互聯網公司所選擇的做法。

    ps:某種意義上來講,有些系統中使用的“冷熱數據分離”(將一些使用較少的歷史數據遷移到其他的數據庫中。而在業務功能上,通常默認只提供熱點數據的查詢),也是類似的實踐。在高併發和海量數據的場景下,分庫分表能夠有效緩解單機和單庫的性能瓶頸和壓力,突破IO、連接數、硬件資源的瓶頸。當然,投入的硬件成本也會更高。同時,這也會帶來一些複雜的技術問題和挑戰(例如:跨分片的複雜查詢,跨分片事務等)

        

切分帶來的問題和解決方法

  • 垂直分庫切分:

    跨庫(跨節點)的join問題:
            在拆分之前,系統中很多列表和詳情頁所需的數據是可以通過sql join來完成的。而拆分後,數據庫可能是分佈式在不同實例和不同的主機上,join將變得非常麻煩。而且基於架構規範,性能,安全性等方面考慮,一般是禁止跨庫join的。那該怎麼辦呢?首先要考慮下垂直分庫的設計問題,如果可以調整,那就優先調整。如果無法調整的情況,下面將結合以往的實際經驗,總結幾種常見的解決思路,並分析其適用場景。

    跨庫(跨節點)的join問題,幾種解決思路:
        1.全局表:
            所謂全局表,就是有可能系統中所有模塊都可能會依賴到的一些表。比較類似我們理解的“數       據 字典”。爲了避免跨庫join查詢,我們可以將這類表在其他每個數據庫中均保存一份。同時,這類數據通常也很少發生修改(甚至幾乎不會),所以也不用太擔心“一致性”問題。

    2.字段冗餘:
            將一個字段同時保存在多個表中。這是一種“時間換空間”的提現,但同時帶來了數據難以一致性的問題。

    3.數據同步:
            A庫中的tab_a表和B庫中tbl_b有關聯,可以定時將指定的表做同步。當然,同步本來會對數據庫帶來一定的影響,需要性能影響和數據時效性中取得一個平衡。這樣來避免複雜的跨庫查詢。

    4.系統層組裝 : 
            在系統層面,通過調用不同模塊的組件或者服務,獲取到數據並進行字段拼裝。說起來很容易,但實踐起來可真沒有這麼簡單,尤其是數據庫設計上存在問題但又無法輕易調整的時候。具體情況通常會比較複雜。組裝的時候要避免循環調用服務,循環RPC,循環查詢數據庫,最好一次性返回所有信息,在代碼裏做組裝。

    跨庫事務(分佈式事務)的問題:
            什麼叫分佈式事務?這樣理解:如果在一個事務中,操作的資源只有一個,那這個事務就是本地事務。如果操作的資源不止一個,那們就可以稱爲分佈式事務。這裏的資源指數據庫的連接,JMS的連接或者其他的一些連接。 通俗的說就是,就是一個事務中,涉及到多個數據源的操作,比如從一個oracle中存一個記錄,再從另一個oracle中刪除那條記錄。 維護所有資源上的數據一致性。    
            
    跨庫事務(分佈式事務)的問題的解決方法:https://mp.csdn.net/postedit/79685717
    1.XA協議指的是TM(事務管理器)和RM(資源管理器)之間的接口;
    2.提供回滾接口;
    3.本地消息表;
    4.非事務消息(MQ)


  • 水平切分:

    分佈式全局唯一ID問題:
        我們往往直接使用數據庫自增特性來生成主鍵ID,這樣確實比較簡單。而在分庫分表的環境中,數據分佈在不同的分片上,不能再借助數據庫自增長特性直接生成,否則會造成不同分片上的數據表主鍵會重複。簡單介紹幾種ID生成算法。

    Twitter的Snowflake(又名“雪花算法”)
    UUID/GUID(一般應用程序和數據庫均支持)
    MongoDB ObjectID(類似UUID的方式)
    Ticket Server(數據庫生存方式,Flickr採用的就是這種方式)

    其中,Twitter 的Snowflake算法生成的是64位唯一Id(由41位的timestamp+ 10位自定義的機器碼+ 13位累加計數器組成)。

    跨節點合併排序分頁問題:
            分頁時需要按照指定字段進行排序。當排序字段就是分片字段的時候,我們通過分片規則可以比較容易定位到指定的分片,而當排序字段非分片字段的時候,情況就會變得比較複雜了。爲了最終結果的準確性,我們需要在不同的分片節點中將數據進行排序並返回,並將不同分片返回的結果集進行彙總和再次排序,最後再返回給用戶。

    常見分片規則問題:
            常見的分片策略有隨機分片和連續分片這兩種,當需要使用分片字段進行範圍查找時,連續分片可以快速定位分片進行高效查詢,大多數情況下可以有效避免跨分片查詢的問題。後期如果想對整個分片集羣擴容時,只需要添加節點即可,無需對其他分片的數據進行遷移。但是,連續分片也有可能存在數據熱點的問題,有些節點可能會被頻繁查詢壓力較大,熱數據節點就成爲了整個集羣的瓶頸。而有些節點可能存的是歷史數據,很少需要被查詢到。隨機分片其實並不是隨機的,也遵循一定規則。通常,我們會採用Hash取模的方式進行分片拆分,所以有些時候也被稱爲離散分片。隨機分片的數據相對比較均勻,不容易出現熱點和併發訪問的瓶頸。但是,後期分片集羣擴容起來需要遷移舊的數據。使用一致性Hash算法能夠很大程度的避免這個問題,所以很多中間件的分片集羣都會採用一致性Hash算法。離散分片也很容易面臨跨分片查詢的複雜問題。

    數據遷移,容量規劃,擴容等問題:
            很少有項目會在初期就開始考慮分片設計的,一般都是在業務高速發展面臨性能和存儲的瓶頸時纔會提前準備。因此,不可避免的就需要考慮歷史數據遷移的問題。一般做法就是通過程序先讀出歷史數據,然後按照指定的分片規則再將數據寫入到各個分片節點中。此外,我們需要根據當前的數據量和QPS等進行容量規劃,綜合成本因素,推算出大概需要多少分片(一般建議單個分片上的單表數據量不要超過1000W)。如果是採用隨機分片,則需要考慮後期的擴容問題,相對會比較麻煩。如果是採用的範圍分片,只需要添加節點就可以自動擴容。

    跨分片的函數處理:
            在使用Max、Min、Sum、Count之類的函數進行統計和計算的時候,需要先在每個分片數據源上執行相應的函數處理,然後再將各個結果集進行二次處理,最終再將處理結果返回。

    跨分片join問題:
            Join是關係型數據庫中最常用的特性,但是在分片集羣中,join也變得非常複雜。應該儘量避免跨分片的join查詢(這種場景,比上面的跨分片分頁更加複雜,而且對性能的影響很大)。通常有以下幾種方式來避免:
            1.全局表:全局表的概念之前在“垂直分庫”時提過。基本思想一致,就是把一些類似數據字典又可能會產生join查詢的表信息放到各分片中,從而避免跨分片的join。
            2.ER分片:在關係型數據庫中,表之間往往存在一些關聯的關係。如果我們可以先確定好關聯關係,並將那些存在關聯關係的表記錄存放在同一個分片上,那麼就能很好的避免跨分片join問題。在一對多關係的情況下,我們通常會選擇按照數據較多的那一方進行拆分。
            3.內存計算:隨着spark內存計算的興起,理論上來講,很多跨數據源的操作問題看起來似乎都能夠得到解決。可以將數據丟給spark集羣進行內存計算,最後將計算結果返回。

切分的一些原則

由於數據切分後數據 Join 的難度在此也分享一下數據切分的經驗: 
第一原則:能不切分儘量不要切分。 
第二原則:如果要切分一定要選擇合適的切分規則,提前規劃好。 
第三原則:數據切分儘量通過數據冗餘或表分組(Table Group)來降低跨庫 Join 的可能。 
第四原則:由於數據庫中間件對數據 Join 實現的優劣難以把握,而且實現高性能難度極大,業務讀取儘量 
少使用多表 Join。


水平切分的方式和規則


上文中提到,要想做到數據的水平切分,在每一個表中都要有相冗餘字符作爲切分依據和標記字段,通常的應用中我們選用user_id作爲區分字段,基於此就有如下幾種分庫的方式和規則:(當然還可以有其他的方式)

(1) 號段分區

user_id爲1~1000的對應DB1,1001~2000的對應DB2,以此類推;

優點:可部分遷移

缺點:數據分佈不均

(2)hash取模分區(或者直接 user_id 取模)

對user_id進行hash(或者如果user_id是數值型的話直接使用user_id 的值也可),然後用一個特定的數字,比如應用中需要將一個數據庫切分成4個數據庫的話,我們就用4這個數字對user_id的hash值進行取模運算,也就是user_id%4,這樣的話每次運算就有四種可能:結果爲1的時候對應DB1;結果爲2的時候對應DB2;結果爲3的時候對應DB3;結果爲0的時候對應DB4。這樣一來就非常均勻的將數據分配到4個DB中。

  1. functikon get_hash_table($table, $userid)
  2. {
  3. $str = crc32($userid)
  4. if ($str < 0) {
  5. $hash = "0" . $substr(abs($str), 0, 1);
  6. }else {
  7. $hash = substr($str, 0, 2);
  8. }
  9. return $table . "_" . $hash;
  10. }
  11. // 'message' 爲表前綴
  12. $table = get_hash_table('message', 'user18992');


優點:數據分佈均勻

缺點:數據遷移的時候麻煩,不能按照機器性能分攤數據

(3)在認證庫中保存數據庫配置

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

優點:靈活性強,一對一關係

缺點:每次查詢之前都要多一次查詢,性能大打折扣    

(4)按照日期,將不同月甚至日的數據分散到不同的庫中

數據庫的切分引申的 數據源管理思考

主要有兩種思路:
1.客戶端模式,在每個應用程序模塊中配置管理自己需要的一個(或者多個)數據源,直接訪問各個數據 

庫,在模塊內完成數據的整合; 【基於應用程序層面的DDAL(分佈式數據庫訪問層)解決 

2.通過中間代理層來統一管理所有的數據源,後端數據庫集羣對前端應用程序透明;【基於中間件,又名“透明網管”去解決】

常用的中間件:mycat cobar ,結構大約如下:

過程如下:

mysql新建3個庫,dn1,dn2,dn3,在linux服務器上安裝mycat,配置好3個庫和規則,新插入的數據會根據規則插入指定的庫。

第3章 本課題研究的基本輪廓

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

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

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

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

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

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

僅僅是分庫分表的數據層設計也是不夠完善的,當我們採用了數據庫切分方案,也就是說有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分配負載。這樣一來,問題就出來了,客戶端很自然的就會發生數據操作失敗的錯誤或者異常。

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

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

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

但是爲什麼要分離讀和寫呢?熟悉DB的研發人員都知道,寫操作涉及到鎖的問題,不管是行鎖還是表鎖還是塊鎖,都是比較降低系統執行效率的事情。我們這樣的分離是把寫操作集中在一個節點上,而讀操作其其他 的N個節點上進行,從另一個方面有效的提高了讀的效率,保證了系統的高可用性。

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