數據庫水平切分的實現原理解析——分庫,分表,主從,集群,負載均衡器(轉)...

第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。

怎么做到數據切分

數據切分可以是物理上的,對數據通過一系列的切分規則將數據分布到不同的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操作的效率。行文至此我們依然沒有涉及到如何切分的問題。接下來,我們將對切分規則進行詳盡的闡述和說明。

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

(1)?號段分區

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

優點:可部分遷移

缺點:數據分布不均

(2)hash取模分區

對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中。

優點:數據分布均勻

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

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

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

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

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

以上就是通常的開發中我們選擇的三種方式,有些復雜的項目中可能會混合使用這三種方式。 通過上面的描述,我們對分庫的規則也有了簡單的認識和了解。當然還會有更好更完善的分庫方式,還需要我們不斷的探索和發現。

第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個節點上進行,從另一個方面有效的提高了讀的效率,保證了系統的高可用性。

?

原文:

http://zhengdl126.iteye.com/blog/419850

轉載于:https://www.cnblogs.com/bangaj/p/6087523.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/255922.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/255922.shtml
英文地址,請注明出處:http://en.pswp.cn/news/255922.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【深度學習】——糾錯error: Unable to find vcvarsall.bat:關于安裝pycocotools

1、安裝包下載 大佬改寫支持 Windows 的 COCO 地址:https://github.com/philferriere/cocoapi 下載后如下: 進入pythonAPI 先后運行: python setup.py build_ext --inplacepython setup.py build_ext install 出現以下標志時&#xff0c…

【小貼士】虛擬鍵盤與fixed帶給移動端的痛!

前言今天來公司的主要目的就是研究虛擬鍵盤與fixed的問題,期間因為同事問起閉包與事件委托(阻止冒泡)相關問題,便穿插了一篇別的:【小貼士】工作中的”閉包“與事件委托的”阻止冒泡“,有興趣的朋友可以去看…

[OJ] Wildcard Matching (Hard)

LintCode 192. Wildcard Matching (Hard)LeetCode 44. Wildcard Matching (Hard) 第二次刷還是被這題虐. 其實就是跪在一個地方, 就是關于mustFail的地方. 當*p && !*s的時候, 說明s已經被用完了, p還沒有被窮盡, 這種情況下要直接退出所有的遞歸返回false, 因為s都匹配…

CSS3 -webkit-transition(屬性漸變)

-webkit-transition:CSS屬性(none|all|屬性) 持續時間 時間函數 延遲時間 CSS屬性(transition-property):要變化的屬性,比如元素變寬則是width,文字顏色要變色這是color;W3C給出了一個可變換屬性的列表:…

vxworks的default boot line說明

boot程序的主要功能是引導vxworks 內核,所以boot程序需要知道vxworks的內核存放在何處,通過什么手段去獲取。在vxworks缺省的boot程序里有一條內建的default boot line,它指明了獲得vxworks內核的途徑,在boot程序啟動時,它先尋找NVRAM里面有無…

【機器視覺】——相機和鏡頭的選擇

目錄 1、相機選擇 2、鏡頭選擇 3、其他計算公式 1)芯片尺寸計算:

React Native中pointerEvent屬性

在React Native界面開發中, 如果使用絕對定位布局,在代碼運行時的某個時刻有可能會遮蓋住它的下方的某個組件。這是因為絕對定位只是說這個組件的位置由它父組件的邊框決定。 絕對定位的組件可以被認為會覆蓋在它前面布局(JSX代碼順序)的組件的上方. 如果…

Rar Java Zip

http://wolfdream.iteye.com/blog/428588轉載于:https://www.cnblogs.com/diyunpeng/p/5218381.html

庫卡機器人CELL程序解析

KUKA機器人 CELL程序 解析及注釋&ACCESS RVP&REL 4&COMMENT HANDLER on external automaticDEF CELL ( );EXT EXAMPLE1 ( );EXT EXAMPLE2 ( );EXT EXAMPLE3 ( ) ;FOLD INITDECL CHAR DMY[3]DMY[]"---";ENDFOLD (INIT);FOLD BASISTECH INIIR_STOPM ( )…

Ubuntu 16.04服務器安裝及軟件配置

1.配置靜態地址 vim /etc/network/interfaces auto enp1s0 iface enp1s0 inet static address 192.168.1.131 netmask 255.255.255.0auto enp2s0 iface enp2s0 inet static address 192.168.2.131 netmask 255.255.255.0auto enp3s0 iface enp3s0 inet static address 192.168.…

[軟件測試airtest軟件安裝]——填坑

目錄 1、安裝Python環境(版本問題) 2、連接手機出現連接上了但是無法進行點擊 airtest官網: https://airtest.doc.io.netease.com/for_newer/ 關于軟件測試剛入門的可以參考進行了解:https://airtest.doc.io.netease.com/tuto…

KUKA 機器人SPS.SUB程序解析

&ACCESS RVO&COMMENT PLC on controlDEF SPS ( );FOLD DECLARATIONS;FOLD BASISTECH DECL;Automatik externDECL STATE_T STAT定義STATE_T類型的變量。該結構為:STRUC STATE_T CMD_STAT RET1, CMD_STAT是枚舉類型數據,組成了STATE_…

jquery validate表單驗證插件

1 表單驗證的準備工作 在開啟長篇大論之前,首先將表單驗證的效果展示給大家。 1.點擊表單項,顯示幫助提示         2.鼠標離開表單項時,開始校驗元素    3.鼠標離開后的正確、錯誤提示及鼠標移入時的幫助提醒 對于初學者而言&…

【Python位運算】——左移操作(<<)右移操作>>

目錄 左移操作 右移操作 其他博主的理解 應用——力扣題目78. 子集 解法 深度優先搜索 位運算 參考文獻 左移操作 # 左移操作&#xff0c;左移一位相當于乘以b&#xff0c;a<<b,a a*(2^b) print(2<<3) # 2*2^3 16&#xff0c;2的二進制10&#xff0c;向…

sql中字段名中包含特殊字符的查詢方法

sql中字段名章包含特殊字符的查詢方法&#xff1a;例如包含""&#xff0c;student表中字段為&#xff1a;id“學號”、name"姓名"。 解決辦法&#xff1a;用英文下的 ""&#xff08;Tab鍵上面那個鍵,不需要shift&#xff09;把字段名包起來。如&…

tomcat Server.xml Context配置

有時候需要在tomcat里面做特殊的配置&#xff0c;來進行訪問&#xff1a; 例如你的程序 名字是hello端口是80 這時候你要訪問你的程序 就要用 localhost/hello 來訪問了。 但是怎么直接用 localhost來訪問呢&#xff1f;就需要進行tomcat 的配置了呢 看以下配置&#xff1a;to…

絕望,絕望、希望

晚上&#xff0c;經歷了一場小小的絕望&#xff0c;因為在論文方面&#xff0c;經過一些實踐檢驗&#xff0c;我發現之前所提出的理論竟然差別太大&#xff0c;這件事情讓人感到絕望&#xff0c;但是&#xff0c;也只有被逼繼續前行&#xff0c;沒有退路&#xff0c;前行才能慢…

【Python數據結構】——二叉查找樹(查找、構建、刪除、插入、打印)

#!/usr/bin/env python # -*- coding: utf-8 -*- # Time : 2021/7/15 0:34 # Author : linlianqin # Site : # File : 二叉查找樹類實現&#xff08;查找、創建、刪除、插入、遍歷&#xff09;.py # Software: PyCharm # description:class TreeNode:def __init__(s…

ABB RAPID SOCKET編程

相傳在2009年6月11日&#xff0c;微博的鼻祖t-w-i-t-t-e-r還沒有被封鎖的時候&#xff0c;于仁頗黎寫了了一個東西可以將staubli機器人在運行時的狀態&#xff0c;實時發送上去&#xff0c;可以被實時的查看&#xff0c;任何一個人都可以查看&#xff0c;于是就有了這個名為TWI…

Plupload文件上傳組件使用API

Plupload有以下功能和特點&#xff1a; 1、擁有多種上傳方式&#xff1a;HTML5、flash、silverlight以及傳統的<input type”file” />。Plupload會自動偵測當前的環境&#xff0c;選擇最合適的上傳方式&#xff0c;并且會優先使用HTML5的方式。所以你完全不用去操心當前…