數(shù)據(jù)庫(kù)Sharding基本套路

Sharding的基本思想其實(shí)就是采用分治的思想妖滔,要把一個(gè)數(shù)據(jù)庫(kù)切分成多個(gè)部分放到不同的數(shù)據(jù)庫(kù)(server)上,從而緩解單一數(shù)據(jù)庫(kù)的性能問題迁沫。

水平切分&垂直切分

  • 水平切分:?jiǎn)伪淼臄?shù)據(jù)量非常多盾碗,這時(shí)候適合水平切分,即把表的數(shù)據(jù)按某種規(guī)則(比如按ID散列)切分到多個(gè)數(shù)據(jù)庫(kù)(server)上
  • 垂直切分:表多而數(shù)據(jù)多断医,這時(shí)候適合使用垂直切分,即把關(guān)系緊密(比如同一模塊)的表切分出來放在一個(gè)server上奏纪,根據(jù)業(yè)務(wù)需要去不同的server上請(qǐng)求數(shù)據(jù)鉴嗤。

當(dāng)然,現(xiàn)實(shí)中更多是這兩種情況混雜在一起序调,這時(shí)候需要根據(jù)實(shí)際情況做出選擇醉锅,也可能會(huì)綜合使用垂直與水平切分,從而將原有數(shù)據(jù)庫(kù)切分成類似矩陣一樣可以無限擴(kuò)充的數(shù)據(jù)庫(kù)(server)陣列发绢。下面分別詳細(xì)地介紹一下垂直切分和水平切分.

垂直切分

垂直切分的最大特點(diǎn)就是規(guī)則簡(jiǎn)單硬耍,實(shí)施也更為方便垄琐,尤其適合各業(yè)務(wù)之間的耦合度非常低,相互影響很小经柴,業(yè)務(wù)邏輯非常清晰的系統(tǒng)狸窘。在這種系統(tǒng)中,可以很容易做到將不同業(yè)務(wù)模塊所使用的表分拆到不同的數(shù)據(jù)庫(kù)中坯认。根據(jù)不同的表來進(jìn)行拆分翻擒,對(duì)應(yīng)用程序的影響也更小,拆分規(guī)則也會(huì)比較簡(jiǎn)單清晰牛哺。


水平切分

水平切分于垂直切分相比陋气,相對(duì)來說稍微復(fù)雜一些。因?yàn)橐獙⑼粋€(gè)表中的不同數(shù)據(jù)拆分到不同的數(shù)據(jù)庫(kù)中荆隘,對(duì)于應(yīng)用程序來說恩伺,拆分規(guī)則本身就較根據(jù)表名來拆分更為復(fù)雜,后期的數(shù)據(jù)維護(hù)也會(huì)更為復(fù)雜一些椰拒。


混合切分

讓我們從普遍的情況來考慮數(shù)據(jù)的切分:一方面,一個(gè)庫(kù)的所有表通常不可能由某一張表全部串聯(lián)起來凰荚,這句話暗含的意思是燃观,水平切分幾乎都是針對(duì)一小搓一小搓(實(shí)際上就是垂直切分出來的塊)關(guān)系緊密的表進(jìn)行的,而不可能是針對(duì)所有表進(jìn)行的便瑟。另一方面缆毁,一些負(fù)載非常高的系統(tǒng),即使僅僅只是單個(gè)表都無法通過單臺(tái)數(shù)據(jù)庫(kù)主機(jī)來承擔(dān)其負(fù)載到涂,這意味著單單是垂直切分也不能完全解決問明脊框。因此多數(shù)系統(tǒng)會(huì)將垂直切分和水平切分聯(lián)合使用,先對(duì)系統(tǒng)做垂直切分践啄,再針對(duì)每一小搓表的情況選擇性地做水平切分浇雹。從而將整個(gè)數(shù)據(jù)庫(kù)切分成一個(gè)分布式矩陣。


切分策略

如前面所提到的屿讽,切分是按先垂直切分再水平切分的步驟進(jìn)行的昭灵。垂直切分的結(jié)果正好為水平切分做好了鋪墊。垂直切分的思路就是分析表間的聚合關(guān)系伐谈,把關(guān)系緊密的表放在一起烂完。多數(shù)情況下可能是同一個(gè)模塊,或者是同一“聚集”诵棵。這里的“聚集”正是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)里所說的聚集抠蚣。在垂直切分出的表聚集內(nèi),找出“根元素”(這里的“根元素”就是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)里的“聚合根”)履澳,按“根元素”進(jìn)行水平切分嘶窄,也就是從“根元素”開始缓屠,把所有和它直接與間接關(guān)聯(lián)的數(shù)據(jù)放入一個(gè)shard里。這樣出現(xiàn)跨shard關(guān)聯(lián)的可能性就非常的小护侮。應(yīng)用程序就不必打斷既有的表間關(guān)聯(lián)敌完。比如:對(duì)于社交網(wǎng)站,幾乎所有數(shù)據(jù)最終都會(huì)關(guān)聯(lián)到某個(gè)用戶上羊初,基于用戶進(jìn)行切分就是最好的選擇滨溉。再比如論壇系統(tǒng),用戶和論壇兩個(gè)模塊應(yīng)該在垂直切分時(shí)被分在了兩個(gè)shard里长赞,對(duì)于論壇模塊來說晦攒,F(xiàn)orum顯然是聚合根,因此按Forum進(jìn)行水平切分得哆,把Forum里所有的帖子和回帖都隨Forum放在一個(gè)shard里是很自然的脯颜。

對(duì)于共享數(shù)據(jù)數(shù)據(jù),如果是只讀的字典表贩据,每個(gè)shard里維護(hù)一份應(yīng)該是一個(gè)不錯(cuò)的選擇栋操,這樣不必打斷關(guān)聯(lián)關(guān)系。如果是一般數(shù)據(jù)間的跨節(jié)點(diǎn)的關(guān)聯(lián)饱亮,就必須打斷矾芙。

需要特別說明的是:當(dāng)同時(shí)進(jìn)行垂直和水平切分時(shí),切分策略會(huì)發(fā)生一些微妙的變化近上。比如:在只考慮垂直切分的時(shí)候剔宪,被劃分到一起的表之間可以保持任意的關(guān)聯(lián)關(guān)系,因此你可以按“功能模塊”劃分表格壹无,但是一旦引入水平切分之后葱绒,表間關(guān)聯(lián)關(guān)系就會(huì)受到很大的制約,通常只能允許一個(gè)主表(以該表ID進(jìn)行散列的表)和其多個(gè)次表之間保留關(guān)聯(lián)關(guān)系斗锭,也就是說:當(dāng)同時(shí)進(jìn)行垂直和水平切分時(shí)地淀,在垂直方向上的切分將不再以“功能模塊”進(jìn)行劃分,而是需要更加細(xì)粒度的垂直切分拒迅,而這個(gè)粒度與領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中的“聚合”概念不謀而合骚秦,甚至可以說是完全一致,每個(gè)shard的主表正是一個(gè)聚合中的聚合根璧微!這樣切分下來你會(huì)發(fā)現(xiàn)數(shù)據(jù)庫(kù)分被切分地過于分散了(shard的數(shù)量會(huì)比較多作箍,但是shard里的表卻不多),為了避免管理過多的數(shù)據(jù)源前硫,充分利用每一個(gè)數(shù)據(jù)庫(kù)服務(wù)器的資源胞得,可以考慮將業(yè)務(wù)上相近,并且具有相近數(shù)據(jù)增長(zhǎng)速率(主表數(shù)據(jù)量在同一數(shù)量級(jí)上)的兩個(gè)或多個(gè)shard放到同一個(gè)數(shù)據(jù)源里屹电,每個(gè)shard依然是獨(dú)立的阶剑,它們有各自的主表跃巡,并使用各自主表ID進(jìn)行散列,不同的只是它們的散列取模(即節(jié)點(diǎn)數(shù)量)必需是一致的牧愁。

事務(wù)問題

解決事務(wù)問題目前有兩種可行的方案:

  • 使用分布式事務(wù)
    優(yōu)點(diǎn):交由數(shù)據(jù)庫(kù)管理素邪,簡(jiǎn)單有效
    缺點(diǎn):性能代價(jià)高,特別是shard越來越多時(shí)
  • 由應(yīng)用程序和數(shù)據(jù)庫(kù)共同控制
    原理:將一個(gè)跨多個(gè)數(shù)據(jù)庫(kù)的分布式事務(wù)分拆成多個(gè)僅處
    于單個(gè)數(shù)據(jù)庫(kù)上面的小事務(wù)猪半,并通過應(yīng)用程序來總控
    各個(gè)小事務(wù)兔朦。
    優(yōu)點(diǎn):性能上有優(yōu)勢(shì)
    缺點(diǎn):需要應(yīng)用程序在事務(wù)控制上做靈活設(shè)計(jì)。如果使用
    了spring的事務(wù)管理磨确,改動(dòng)起來會(huì)面臨一定的困難沽甥。

跨節(jié)點(diǎn)Join的問題(兩次查、冗余表或字段)

只要是進(jìn)行切分乏奥,跨節(jié)點(diǎn)Join的問題是不可避免的摆舟。但是良好的設(shè)計(jì)和切分卻可以減少此類情況的發(fā)生。解決這一問題的普遍做法是分兩次查詢實(shí)現(xiàn)邓了。在第一次查詢的結(jié)果集中找出關(guān)聯(lián)數(shù)據(jù)的id,根據(jù)這些id發(fā)起第二次請(qǐng)求得到關(guān)聯(lián)數(shù)據(jù)恨诱。

跨節(jié)點(diǎn)的count,order by,group by以及聚合函數(shù)問題

這些是一類問題,因?yàn)樗鼈兌夹枰谌繑?shù)據(jù)集合進(jìn)行計(jì)算驶悟。多數(shù)的代理都不會(huì)自動(dòng)處理合并工作胡野。解決方案:與解決跨節(jié)點(diǎn)join問題的類似,分別在各個(gè)節(jié)點(diǎn)上得到結(jié)果后在應(yīng)用程序端進(jìn)行合并痕鳍。和join不同的是每個(gè)結(jié)點(diǎn)的查詢可以并行執(zhí)行,因此很多時(shí)候它的速度要比單一大表快很多龙巨。但如果結(jié)果集很大笼呆,對(duì)應(yīng)用程序內(nèi)存的消耗是一個(gè)問題。

垂直切分的粒度

垂直切分的粒度指的是在做垂直切分時(shí)允許幾級(jí)的關(guān)聯(lián)表放在一個(gè)shard里.這個(gè)問題對(duì)應(yīng)用程序和sharding實(shí)現(xiàn)有著很大的影響旨别。

關(guān)聯(lián)打斷地越多诗赌,則受影響的join操作越多,應(yīng)用程序?yàn)榇俗龀龅耐讌f(xié)就越大秸弛,但單表的路由會(huì)越簡(jiǎn)單铭若,與業(yè)務(wù)的關(guān)聯(lián)性會(huì)越小,就越容易使用統(tǒng)一機(jī)制處理.在此方向上的極端方案是:打斷所有連接递览,每張表都配有路由規(guī)則叼屠,可以使用統(tǒng)一機(jī)制或框架自動(dòng)處理.比如amoeba這樣的框架,它的路由能且僅能通過SQL的特征(比如某個(gè)表的id)進(jìn)行路由绞铃。

反之镜雨,若關(guān)聯(lián)打斷地越少,則join操作的受到的限制就小儿捧,應(yīng)用程序需要做出的妥協(xié)就越小荚坞,但是表的路由就會(huì)變復(fù)雜挑宠,與業(yè)務(wù)的關(guān)聯(lián)性就越大,就越難使用統(tǒng)一機(jī)制處理颓影,需要針對(duì)每個(gè)數(shù)據(jù)請(qǐng)求單獨(dú)實(shí)現(xiàn)路由各淀。

實(shí)際的粒度掌控需要結(jié)合“業(yè)務(wù)緊密程度”和“表格數(shù)據(jù)量”兩個(gè)因素綜合考慮,一般來說:

  • 若劃歸到一起的表格關(guān)系緊密诡挂,且數(shù)據(jù)量并不大碎浇,增速也非常緩慢,則適宜放在一個(gè)shard里咆畏,不需要再進(jìn)行水平切分;

  • 若劃歸到一起的表格數(shù)據(jù)量巨大且增速迅猛南捂,則勢(shì)必要在垂直切分的基礎(chǔ)上再進(jìn)行水平切分,水平切分就意味著原單一shard會(huì)被細(xì)分成多個(gè)更小的shard旧找,每一個(gè)shard存在一個(gè)主表(即會(huì)以該表ID進(jìn)行散列的表)和多個(gè)相之相關(guān)的關(guān)聯(lián)表溺健。

總之,垂直切分的粒度在兩個(gè)相反的方向上呈現(xiàn)優(yōu)勢(shì)與劣勢(shì)并存并相互博弈的局面.架構(gòu)師需要做的是結(jié)合項(xiàng)目的實(shí)際情況在兩者之間取得收益最大化的平衡钮蛛。

拆分實(shí)施示例

拆分策略


對(duì)數(shù)據(jù)庫(kù)進(jìn)行分庫(kù)分表(Sharding化)前鞭缭,需要開發(fā)人員充分了解系統(tǒng)業(yè)務(wù)邏輯和數(shù)據(jù)庫(kù)schema.一個(gè)好的建議是繪制一張數(shù)據(jù)庫(kù)ER圖或領(lǐng)域模型圖,以這類圖為基礎(chǔ)劃分shard,直觀易行魏颓,可以確保開發(fā)人員始終保持清醒思路岭辣。對(duì)于是選擇數(shù)據(jù)庫(kù)ER圖還是領(lǐng)域模型圖要根據(jù)項(xiàng)目自身情況進(jìn)行選擇。如果項(xiàng)目使用數(shù)據(jù)驅(qū)動(dòng)的開發(fā)方式甸饱,團(tuán)隊(duì)以數(shù)據(jù)庫(kù)ER圖作為業(yè)務(wù)交流的基礎(chǔ)沦童,則自然會(huì)選擇數(shù)據(jù)庫(kù)ER圖,如果項(xiàng)目使用的是領(lǐng)域驅(qū)動(dòng)的開發(fā)方式叹话,并通過OR-Mapping構(gòu)建了一個(gè)良好的領(lǐng)域模型偷遗,那么領(lǐng)域模型圖無疑是最好的選擇。就我個(gè)人來說驼壶,更加傾向使用領(lǐng)域模型圖氏豌,因?yàn)檫M(jìn)行切分時(shí)更多的是以業(yè)務(wù)為依據(jù)進(jìn)行分析判斷,領(lǐng)域模型無疑更加清晰和直觀热凹。

垂直切分

垂直切分的依據(jù)原則是:將業(yè)務(wù)緊密泵喘,表間關(guān)聯(lián)密切的表劃分在一起,例如同一模塊的表般妙。結(jié)合已經(jīng)準(zhǔn)備好的數(shù)據(jù)庫(kù)ER圖或領(lǐng)域模型圖纪铺,仿照活動(dòng)圖中的泳道概念,一個(gè)泳道代表一個(gè)shard股冗,把所有表格劃分到不同的泳道中霹陡。下面的分析示例會(huì)展示這種做法。當(dāng)然,你也可以在打印出的ER圖或模型圖上直接用鉛筆圈烹棉,一切取決于你自己的喜好攒霹。

水平切分

垂直切分后,需要對(duì)shard內(nèi)表格的數(shù)據(jù)量和增速進(jìn)一步分析,以確定是否需要進(jìn)行水平切分。

  • 若劃分到一起的表格數(shù)據(jù)增長(zhǎng)緩慢铅匹,在產(chǎn)品上線后可遇見的足夠長(zhǎng)的時(shí)期內(nèi)均可以由單一數(shù)據(jù)庫(kù)承載,則不需要進(jìn)行水平切分抠刺,所有表格駐留同一shard,所有表間關(guān)聯(lián)關(guān)系會(huì)得到最大限度的保留,同時(shí)保證了書寫SQL的自由度摘昌,不易受join速妖、group by、order by等子句限制聪黎。

  • 若劃分到一起的表格數(shù)據(jù)量巨大罕容,增速迅猛,需要進(jìn)一步進(jìn)行水平分割稿饰。進(jìn)一步的水平分割就這樣進(jìn)行:

    • 結(jié)合業(yè)務(wù)邏輯和表間關(guān)系锦秒,將當(dāng)前shard劃分成多個(gè)更小的shard,通常情況下,這些更小的shard每一個(gè)都只包含一個(gè)主表(將以該表ID進(jìn)行散列的表)和多個(gè)與其關(guān)聯(lián)或間接關(guān)聯(lián)的次表喉镰。這種一個(gè)shard一張主表多張次表的狀況是水平切分的必然結(jié)果旅择。這樣切分下來,shard數(shù)量就會(huì)迅速增多侣姆。如果每一個(gè)shard代表一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)生真,那么管理和維護(hù)數(shù)據(jù)庫(kù)將會(huì)非常麻煩,而且這些小shard往往只有兩三張表捺宗,為此而建立一個(gè)新庫(kù)汇歹,利用率并不高,因此偿凭,在水平切分完成后可再進(jìn)行一次“反向的Merge”,即:將業(yè)務(wù)上相近,并且具有相近數(shù)據(jù)增長(zhǎng)速率(主表數(shù)據(jù)量在同一數(shù)量級(jí)上)的兩個(gè)或多個(gè)shard放到同一個(gè)數(shù)據(jù)庫(kù)上派歌,在邏輯上它們依然是獨(dú)立的shard弯囊,有各自的主表,并依據(jù)各自主表的ID進(jìn)行散列胶果,不同的只是它們的散列取模(即節(jié)點(diǎn)數(shù)量)必需是一致的匾嘱。這樣,每個(gè)數(shù)據(jù)庫(kù)結(jié)點(diǎn)上的表格數(shù)量就相對(duì)平均了早抠。
    • 所有表格均劃分到合適的shard之后霎烙,所有跨越shard的表間關(guān)聯(lián)都必須打斷,在書寫sql時(shí),跨shard的join悬垃、group by游昼、order by都將被禁止,需要在應(yīng)用程序?qū)用鎱f(xié)調(diào)解決這些問題尝蠕。

實(shí)施階段

如果項(xiàng)目在開發(fā)伊始就決定進(jìn)行分庫(kù)分表烘豌,則嚴(yán)格按照分析設(shè)計(jì)方案推進(jìn)即可。如果是在中期架構(gòu)演進(jìn)中實(shí)施看彼,除搭建實(shí)現(xiàn)sharding邏輯的基礎(chǔ)設(shè)施外(關(guān)于該話題會(huì)在下篇文章中進(jìn)行闡述)廊佩,還需要對(duì)原有SQL逐一過濾分析,修改那些因?yàn)閟harding而受到影響的sql靖榕。
jpetstore來演示如何進(jìn)行分庫(kù)分表(sharding)在分析階段的工作标锄。由于一些個(gè)人原因,演示使用的jpetstore來自原ibatis官方的一個(gè)Demo版本茁计,SVN地址為:http://mybatis.googlecode.com/svn/tags/java_release_2.3.4-726/jpetstore-5料皇。關(guān)于jpetstore的業(yè)務(wù)邏輯這里不再介紹,這是一個(gè)非常簡(jiǎn)單的電商系統(tǒng)原型簸淀,其領(lǐng)域模型如下圖:

由于系統(tǒng)較簡(jiǎn)單瓶蝴,我們很容易從模型上看出,其主要由三個(gè)模塊組成:用戶租幕,產(chǎn)品和訂單舷手。那么垂直切分的方案也就出來了。接下來看水平切分劲绪,如果我們從一個(gè)實(shí)際的寵物店出發(fā)考慮男窟,可能出現(xiàn)數(shù)據(jù)激增的單表應(yīng)該是Account和Order,因此這兩張表需要進(jìn)行水平切分。對(duì)于Product模塊來說贾富,如果是一個(gè)實(shí)際的系統(tǒng)歉眷,Product和Item的數(shù)量都不會(huì)很大,因此只做垂直切分就足夠了颤枪,也就是(Product汗捡,Category,Item畏纲,Iventory扇住,Supplier)五張表在一個(gè)數(shù)據(jù)庫(kù)結(jié)點(diǎn)上(沒有水平切分,不會(huì)存在兩個(gè)以上的數(shù)據(jù)庫(kù)結(jié)點(diǎn))盗胀。但是作為一個(gè)演示艘蹋,我們假設(shè)產(chǎn)品模塊也有大量的數(shù)據(jù)需要我們做水平切分,那么分析來看票灰,這個(gè)模塊要拆分出兩個(gè)shard:一個(gè)是(Product(主)女阀,Category)宅荤,另一個(gè)是(Item(主),Iventory浸策,Supplier)冯键,同時(shí),我們認(rèn)為:這兩個(gè)shard在數(shù)據(jù)增速上應(yīng)該是相近的的榛,且在業(yè)務(wù)上也很緊密琼了,那么我們可以把這兩個(gè)shard放在同一個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)上,Item和Product數(shù)據(jù)在散列時(shí)取一樣的模夫晌。根據(jù)前文介紹的圖紙繪制方法雕薪,我們得到下面這張sharding示意圖:


對(duì)于這張圖再說明幾點(diǎn):

  • 使用泳道表示物理shard(一個(gè)數(shù)據(jù)庫(kù)結(jié)點(diǎn))
  • 若垂直切分出的shard進(jìn)行了進(jìn)一步的水平切分,但公用一個(gè)物理shard的話晓淀,則用虛線框住所袁,表示其在邏輯上是一個(gè)獨(dú)立的shard。
  • 深色實(shí)體表示主表
  • X表示需要打斷的表間關(guān)聯(lián)

全局主鍵生成策略

一些常見的主鍵生成策略

  1. UUID:使用UUID作主鍵是最簡(jiǎn)單的方案凶掰,但是缺點(diǎn)也是非常明顯的燥爷。由于UUID非常的長(zhǎng),除占用大量存儲(chǔ)空間外懦窘,最主要的問題是在索引上前翎,在建立索引和基于索引進(jìn)行查詢時(shí)都存在性能問題。
  2. 結(jié)合數(shù)據(jù)庫(kù)維護(hù)一個(gè)Sequence表:此方案的思路也很簡(jiǎn)單畅涂,在數(shù)據(jù)庫(kù)中建立一個(gè)Sequence表港华,表的結(jié)構(gòu)類似于:
CREATE TABLE `SEQUENCE` (  
    `tablename` varchar(30) NOT NULL,  
    `nextid` bigint(20) NOT NULL,  
    PRIMARY KEY (`tablename`)  
) ENGINE=InnoDB   

每當(dāng)需要為某個(gè)表的新紀(jì)錄生成ID時(shí)就從Sequence表中取出對(duì)應(yīng)表的nextid,并將nextid的值加1后更新到數(shù)據(jù)庫(kù)中以備下次使用。此方案也較簡(jiǎn)單午衰,但缺點(diǎn)同樣明顯:由于所有插入任何都需要訪問該表立宜,該表很容易成為系統(tǒng)性能瓶頸,同時(shí)它也存在單點(diǎn)問題臊岸,一旦該表數(shù)據(jù)庫(kù)失效橙数,整個(gè)應(yīng)用程序?qū)o法工作。有人提出使用Master-Slave進(jìn)行主從同步帅戒,但這也只能解決單點(diǎn)問題灯帮,并不能解決讀寫比為1:1的訪問壓力問題。

除此之外逻住,還有一些方案施流,像對(duì)每個(gè)數(shù)據(jù)庫(kù)結(jié)點(diǎn)分區(qū)段劃分ID,以及網(wǎng)上的一些ID生成算法,因?yàn)槿鄙倏刹僮餍院蛯?shí)踐檢驗(yàn)鄙信,本文并不推薦。實(shí)際上忿晕,接下來装诡,我們要介紹的是Fickr使用的一種主鍵生成方案,這個(gè)方案是目前我所知道的最優(yōu)秀的一個(gè)方案,并且經(jīng)受了實(shí)踐的檢驗(yàn)鸦采,可以為大多數(shù)應(yīng)用系統(tǒng)所借鑒宾巍。

一種極為優(yōu)秀的主鍵生成策略

flickr開發(fā)團(tuán)隊(duì)在2010年撰文介紹了flickr使用的一種主鍵生成測(cè)策略,同時(shí)表示該方案在flickr上的實(shí)際運(yùn)行效果也非常令人滿意渔伯,原文連接:

Ticket Servers: Distributed Unique Primary Keys on the Cheap

這個(gè)方案是我目前知道的最好的方案顶霞,它與一般Sequence表方案有些類似,但卻很好地解決了性能瓶頸和單點(diǎn)問題锣吼,是一種非逞』耄可靠而高效的全局主鍵生成方案。


flickr這一方案的整體思想是:建立兩臺(tái)以上的數(shù)據(jù)庫(kù)ID生成服務(wù)器玄叠,每個(gè)服務(wù)器都有一張記錄各表當(dāng)前ID的Sequence表古徒,但是Sequence中ID增長(zhǎng)的步長(zhǎng)是服務(wù)器的數(shù)量,起始值依次錯(cuò)開读恃,這樣相當(dāng)于把ID的生成散列到了每個(gè)服務(wù)器節(jié)點(diǎn)上隧膘。例如:如果我們?cè)O(shè)置兩臺(tái)數(shù)據(jù)庫(kù)ID生成服務(wù)器,那么就讓一臺(tái)的Sequence表的ID起始值為1,每次增長(zhǎng)步長(zhǎng)為2,另一臺(tái)的Sequence表的ID起始值為2,每次增長(zhǎng)步長(zhǎng)也為2寺惫,那么結(jié)果就是奇數(shù)的ID都將從第一臺(tái)服務(wù)器上生成疹吃,偶數(shù)的ID都從第二臺(tái)服務(wù)器上生成,這樣就將生成ID的壓力均勻分散到兩臺(tái)服務(wù)器上西雀,同時(shí)配合應(yīng)用程序的控制萨驶,當(dāng)一個(gè)服務(wù)器失效后,系統(tǒng)能自動(dòng)切換到另一個(gè)服務(wù)器上獲取ID蒋搜,從而保證了系統(tǒng)的容錯(cuò)篡撵。
關(guān)于這個(gè)方案,有幾點(diǎn)細(xì)節(jié)這里再說明一下:

  1. flickr的數(shù)據(jù)庫(kù)ID生成服務(wù)器是專用服務(wù)器豆挽,服務(wù)器上只有一個(gè)數(shù)據(jù)庫(kù)育谬,數(shù)據(jù)庫(kù)中表都是用于生成Sequence的,這也是因?yàn)閍uto-increment-offset和auto-increment-increment這兩個(gè)數(shù)據(jù)庫(kù)變量是數(shù)據(jù)庫(kù)實(shí)例級(jí)別的變量帮哈。
  2. flickr的方案中表格中的stub字段只是一個(gè)char(1) NOT NULL存根字段膛檀,并非表名,因此娘侍,一般來說咖刃,一個(gè)Sequence表只有一條紀(jì)錄,可以同時(shí)為多張表生成ID憾筏,如果需要表的ID是有連續(xù)的嚎杨,需要為該表單獨(dú)建立Sequence表。
  3. 方案使用了mysql的LAST_INSERT_ID()函數(shù)氧腰,這也決定了Sequence表只能有一條記錄枫浙。
  4. 使用REPLACE INTO插入數(shù)據(jù)刨肃,這是很討巧的作法,主要是希望利用mysql自身的機(jī)制生成ID,不僅是因?yàn)檫@樣簡(jiǎn)單箩帚,更是因?yàn)槲覀冃枰狪D按照我們?cè)O(shè)定的方式(初值和步長(zhǎng))來生成真友。
  5. SELECT LAST_INSERT_ID()必須要于REPLACE INTO語句在同一個(gè)數(shù)據(jù)庫(kù)連接下才能得到剛剛插入的新ID,否則返回的值總是0
  6. 該方案中Sequence表使用的是MyISAM引擎紧帕,以獲取更高的性能盔然,注意:MyISAM引擎使用的是表級(jí)別的鎖,MyISAM對(duì)表的讀寫是串行的是嗜,因此不必?fù)?dān)心在并發(fā)時(shí)兩次讀取會(huì)得到同一個(gè)ID(另外愈案,應(yīng)該程序也不需要同步,每個(gè)請(qǐng)求的線程都會(huì)得到一個(gè)新的connection,不存在需要同步的共享資源)叠纷。經(jīng)過實(shí)際對(duì)比測(cè)試刻帚,使用一樣的Sequence表進(jìn)行ID生成,MyISAM引擎要比InnoDB表現(xiàn)高出很多涩嚣!
  7. 可使用純JDBC實(shí)現(xiàn)對(duì)Sequence表的操作崇众,以便獲得更高的效率,實(shí)驗(yàn)表明航厚,即使只使用Spring JDBC性能也不及純JDBC來得快顷歌!

實(shí)現(xiàn)該方案,應(yīng)用程序同樣需要做一些處理幔睬,主要是兩方面的工作:

  1. 自動(dòng)均衡數(shù)據(jù)庫(kù)ID生成服務(wù)器的訪問
  2. 確保在某個(gè)數(shù)據(jù)庫(kù)ID生成服務(wù)器失效的情況下眯漩,能將請(qǐng)求轉(zhuǎn)發(fā)到其他服務(wù)器上執(zhí)行。

Sharding實(shí)現(xiàn)層次

當(dāng)團(tuán)隊(duì)對(duì)系統(tǒng)業(yè)務(wù)和數(shù)據(jù)庫(kù)進(jìn)行了細(xì)致的梳理麻顶,確定了切分方案后赦抖,接下來的問題就是如何去實(shí)現(xiàn)切分方案了,目前在sharding方面有不少的開源框架和產(chǎn)品可供參考辅肾,同時(shí)很多團(tuán)隊(duì)也會(huì)選擇自主開發(fā)實(shí)現(xiàn)队萤,而不管是選擇框架還是自主開發(fā),都會(huì)面臨一個(gè)在哪一層上實(shí)現(xiàn)sharding邏輯的問題矫钓,本文會(huì)對(duì)這一系列的問題逐一進(jìn)行分析和考量要尔。

sharding邏輯的實(shí)現(xiàn)層面

從一個(gè)系統(tǒng)的程序架構(gòu)層面來看,sharding邏輯可以在DAO層新娜、JDBC API層赵辕、介于DAO與JDBC之間的Spring數(shù)據(jù)訪問封裝層(各種spring的template)以及介于應(yīng)用服務(wù)器與數(shù)據(jù)庫(kù)之間的sharding代理服務(wù)器四個(gè)層面上實(shí)現(xiàn)。


  • 在DAO層實(shí)現(xiàn)
    當(dāng)團(tuán)隊(duì)決定自行實(shí)現(xiàn)sharding的時(shí)候概龄,DAO層可能是嵌入sharding邏輯的首選位置还惠,因?yàn)樵谶@個(gè)層面上,每一個(gè)DAO的方法都明確地知道需要訪問的數(shù)據(jù)表以及查詢參數(shù)私杜,借助這些信息可以直接定位到目標(biāo)shard上吸重,而不必像框架那樣需要對(duì)SQL進(jìn)行解析然后再依據(jù)配置的規(guī)則進(jìn)行路由互拾。另一個(gè)優(yōu)勢(shì)是不會(huì)受ORM框架的制約。由于現(xiàn)在的大多數(shù)應(yīng)用在數(shù)據(jù)訪問層上會(huì)依賴某種ORM框架嚎幸,而多數(shù)的shrading框架往往無法支持或只能支持一種orm框架,這使得在選擇和應(yīng)用框架時(shí)受到了很大的制約寄猩,而自行實(shí)現(xiàn)sharding完全沒有這方面的問題嫉晶,甚至不同的shard使用不同的orm框架都可以在一起協(xié)調(diào)工作。比如現(xiàn)在的java應(yīng)用大多使用hibernate田篇,但是當(dāng)下還沒有非常令人滿意的基于hibernate的sharding框架替废,(關(guān)于hibernate hards會(huì)在下文介紹),因此很多團(tuán)隊(duì)會(huì)選擇自行實(shí)現(xiàn)sharding泊柬。
    簡(jiǎn)單總結(jié)一下椎镣,在DAO層自行實(shí)現(xiàn)sharding的優(yōu)勢(shì)在于:不受ORM框架的制約、實(shí)現(xiàn)起來較為簡(jiǎn)單兽赁、易于根據(jù)系統(tǒng)特點(diǎn)進(jìn)行靈活的定制状答、無需SQL解析和路由規(guī)則匹配,性能上表現(xiàn)會(huì)稍好一些;劣勢(shì)在于:有一定的技術(shù)門檻刀崖,工作量比依靠框架實(shí)現(xiàn)要大(反過來看惊科,框架會(huì)有學(xué)習(xí)成本)、不通用亮钦,只能在特定系統(tǒng)里工作馆截。當(dāng)然,在DAO層同樣可以通過XML配置或是注解將sharding邏輯抽離到“外部”蜂莉,形成一套通用的框架. 不過目前還沒有出現(xiàn)此類的框架蜡娶。

  • 在ORM框架層實(shí)現(xiàn)
    在ORM框架層實(shí)現(xiàn)sharding有兩個(gè)方向,一個(gè)是在實(shí)現(xiàn)O-R Mapping的前提下同時(shí)提供sharding支持映穗,從而定位為一種分布式的數(shù)據(jù)訪問框架窖张,這一類類型的框架代表就是guzz另一個(gè)方向是通過對(duì)既有ORM框架進(jìn)行修改增強(qiáng)來加入sharding機(jī)制。此類型的代表產(chǎn)品hibernate shard. 應(yīng)該說以hibernate這樣主流的地位男公,行業(yè)對(duì)于一款面向hibernate的sharding框架的需求是非常迫切的荤堪,但是就目前的hibernate shards來看,表現(xiàn)還算不上令人滿意枢赔,主要是它對(duì)使用hibernate的限制過多澄阳,比如它對(duì)HQL的支持就非常有限。在mybatis方面踏拜,目前還沒有成熟的相關(guān)框架產(chǎn)生碎赢。有人提出利用mybatis的插件機(jī)制實(shí)現(xiàn)sharding,但是遺憾的是,mybatis的插件機(jī)制控制不到多數(shù)據(jù)源的連接層面速梗,另一方面肮塞,離開插件層又失去了對(duì)sql進(jìn)行集中解析和路由的機(jī)會(huì)襟齿,因此在mybatis框架上,目前還沒有可供借鑒的框架枕赵,團(tuán)隊(duì)可能要在DAO層或Spring模板類上下功夫了猜欺。

  • 在JDBC API層實(shí)現(xiàn)
    JDBC API層是很多人都會(huì)想到的一個(gè)實(shí)現(xiàn)sharding的絕佳場(chǎng)所,如果我們能提供一個(gè)實(shí)現(xiàn)了sharding邏輯的JDBC API實(shí)現(xiàn)拷窜,那么sharding對(duì)于整個(gè)應(yīng)用程序來說就是完全透明的开皿,而這樣的實(shí)現(xiàn)可以直接作為通用的sharding產(chǎn)品了。但是這種方案的技術(shù)門檻和工作量顯然不是一般團(tuán)隊(duì)能做得來的篮昧,因此基本上沒有團(tuán)隊(duì)會(huì)在這一層面上實(shí)現(xiàn)sharding,甚至也沒有此類的開源產(chǎn)品赋荆。

  • 在介于DAO與JDBC之間的Spring數(shù)據(jù)訪問封裝層實(shí)現(xiàn)
    在springd大行其道的今天,幾乎沒有哪個(gè)java平臺(tái)上構(gòu)建的應(yīng)用不使用spring懊昨,在DAO與JDBC之間窄潭,spring提供了各種template來管理資源的創(chuàng)建與釋放以及與事務(wù)的同步,大多數(shù)基于spring的應(yīng)用都會(huì)使用template類做為數(shù)據(jù)訪問的入口酵颁,這給了我們另一個(gè)嵌入sharding邏輯的機(jī)會(huì)嫉你,就是通過提供一個(gè)嵌入了sharding邏輯的template類來完成sharding工作.這一方案在效果上與基于JDBC API實(shí)現(xiàn)的方案基本一致,同樣是對(duì)上層代碼透明材义,在進(jìn)行sharding改造時(shí)可以平滑地過度均抽,但它的實(shí)現(xiàn)卻比基于JDBC API的方式簡(jiǎn)單,因此成為了不少框架的選擇其掂。

  • 在應(yīng)用服務(wù)器與數(shù)據(jù)庫(kù)之間通過代理實(shí)現(xiàn)

在應(yīng)用服務(wù)器與數(shù)據(jù)庫(kù)之間加入一個(gè)代理油挥,應(yīng)用程序向數(shù)據(jù)發(fā)出的數(shù)據(jù)請(qǐng)求會(huì)先通過代理,代理會(huì)根據(jù)配置的路由規(guī)則款熬,對(duì)SQL進(jìn)行解析后路由到目標(biāo)shard深寥,因?yàn)檫@種方案對(duì)應(yīng)用程序完全透明,通用性好贤牛,所以成為了很多sharding產(chǎn)品的選擇惋鹅。在這方面較為知名的產(chǎn)品是mysql官方的代理工具:Mysql Proxy和一款國(guó)人開發(fā)的產(chǎn)品:
amoeba。mysql proxy本身并沒有實(shí)現(xiàn)任何sharding邏輯殉簸,它只是作為一種面向mysql數(shù)據(jù)庫(kù)的代理闰集,給開發(fā)人員提供了一個(gè)嵌入sharding邏輯的場(chǎng)所,它使用lua作為編程語言般卑,這對(duì)很多團(tuán)隊(duì)來說是需要考慮的一個(gè)問題武鲁。amoeba則是專門實(shí)現(xiàn)讀寫分離與sharding的代理產(chǎn)品,它使用非常簡(jiǎn)單蝠检,不使用任何編程語言沐鼠,只需要通過xml進(jìn)行配置。不過amoeba不支持事務(wù)(從應(yīng)用程序發(fā)出的包含事務(wù)信息的請(qǐng)求到達(dá)amoeba時(shí),事務(wù)信息會(huì)被抹去饲梭,因此乘盖,即使是單點(diǎn)數(shù)據(jù)訪問也不會(huì)有事務(wù)存在)一直是個(gè)硬傷。當(dāng)然憔涉,這要看產(chǎn)品的定位和設(shè)計(jì)理念订框,我們只能說對(duì)于那些對(duì)事務(wù)要求非常高的系統(tǒng),amoeba是不適合的兜叨。

多數(shù)據(jù)源的事務(wù)處理

系統(tǒng)經(jīng)sharding改造之后布蔗,原來單一的數(shù)據(jù)庫(kù)會(huì)演變成多個(gè)數(shù)據(jù)庫(kù),如何確保多數(shù)據(jù)源同時(shí)操作的原子性和一致性是不得不考慮的一個(gè)問題浪腐。總體上看顿乒,目前對(duì)于一個(gè)分布式系統(tǒng)的事務(wù)處理有三種方式:分布式事務(wù)议街、基于Best Efforts 1PC模式的事務(wù)以及事務(wù)補(bǔ)償機(jī)制。

分布式事務(wù)

  • 優(yōu)勢(shì):
  1. 基于兩階段提交璧榄,最大限度地保證了跨數(shù)據(jù)庫(kù)操作的“原子性”特漩,是分布式系統(tǒng)下最嚴(yán)格的事務(wù)實(shí)現(xiàn)方式。
  2. 實(shí)現(xiàn)簡(jiǎn)單骨杂,工作量小涂身。由于多數(shù)應(yīng)用服務(wù)器以及一些獨(dú)立的分布式事務(wù)協(xié)調(diào)器做了大量的封裝工作,使得項(xiàng)目中引入分布式事務(wù)的難度和工作量基本上可以忽略不計(jì)搓蚪。
  • 劣勢(shì):
    系統(tǒng)“水平”伸縮的死敵蛤售。基于兩階段提交的分布式事務(wù)在提交事務(wù)時(shí)需要在多個(gè)節(jié)點(diǎn)之間進(jìn)行協(xié)調(diào),最大限度地推后了提交事務(wù)的時(shí)間點(diǎn)妒潭,客觀上延長(zhǎng)了事務(wù)的執(zhí)行時(shí)間悴能,這會(huì)導(dǎo)致事務(wù)在訪問共享資源時(shí)發(fā)生沖突和死鎖的概率增高,隨著數(shù)據(jù)庫(kù)節(jié)點(diǎn)的增多雳灾,這種趨勢(shì)會(huì)越來越嚴(yán)重漠酿,從而成為系統(tǒng)在數(shù)據(jù)庫(kù)層面上水平伸縮的"枷鎖", 這是很多Sharding系統(tǒng)不采用分布式事務(wù)的主要原因谎亩。

基于Best Efforts 1PC模式的事務(wù)

與分布式事務(wù)采用的兩階段提交不同炒嘲,Best Efforts 1PC模式采用的是一階段端提交,犧牲了事務(wù)在某些特殊情況(當(dāng)機(jī)匈庭、網(wǎng)絡(luò)中斷等)下的安全性夫凸,卻獲得了良好的性能,特別是消除了對(duì)水平伸縮的桎酷嚎花。Distributed transactions in Spring, with and without XA一文對(duì)Best Efforts 1PC模式進(jìn)行了詳細(xì)的說明寸痢,該文提供的Demo代碼更是直接給出了在Spring環(huán)境下實(shí)現(xiàn)一階段提交的多數(shù)據(jù)源事務(wù)管理示例。

事務(wù)補(bǔ)償機(jī)制

對(duì)于那些對(duì)性能要求很高紊选,但對(duì)一致性要求并不高的系統(tǒng)啼止,往往并不苛求系統(tǒng)的實(shí)時(shí)一致性道逗,只要在一個(gè)允許的時(shí)間周期內(nèi)達(dá)到最終一致性即可,這使得事務(wù)補(bǔ)償機(jī)制成為一種可行的方案献烦。事務(wù)補(bǔ)償機(jī)制最初被提出是在“長(zhǎng)事務(wù)”的處理中滓窍,但是對(duì)于分布式系統(tǒng)確保一致性也有很好的參考意義」牵籠統(tǒng)地講吏夯,與事務(wù)在執(zhí)行中發(fā)生錯(cuò)誤后立即回滾的方式不同,事務(wù)補(bǔ)償是一種事后檢查并補(bǔ)救的措施即横,它只期望在一個(gè)容許時(shí)間周期內(nèi)得到最終一致的結(jié)果就可以了噪生。事務(wù)補(bǔ)償?shù)膶?shí)現(xiàn)與系統(tǒng)業(yè)務(wù)緊密相關(guān),并沒有一種標(biāo)準(zhǔn)的處理方式东囚。一些常見的實(shí)現(xiàn)方式有:對(duì)數(shù)據(jù)進(jìn)行對(duì)帳檢查;基于日志進(jìn)行比對(duì);定期同標(biāo)準(zhǔn)數(shù)據(jù)來源進(jìn)行同步跺嗽,等等。

Sharding擴(kuò)容方案

Sharding就是將原來單一數(shù)據(jù)庫(kù)按照一定的規(guī)則進(jìn)行切分页藻,把數(shù)據(jù)分散到多臺(tái)物理機(jī)(我們稱之為Shard)上存儲(chǔ)桨嫁,從而突破單機(jī)限制,使系統(tǒng)能以Scale-Out的方式應(yīng)對(duì)不斷上漲的海量數(shù)據(jù)份帐,但是這種切分對(duì)上層應(yīng)用來說是透明的璃吧,多個(gè)物理上分布的數(shù)據(jù)庫(kù)在邏輯上依然是一個(gè)庫(kù)。實(shí)現(xiàn)Sharding需要解決一系列關(guān)鍵的技術(shù)問題废境,這些問題主要包括:切分策略畜挨、節(jié)點(diǎn)路由、全局主鍵生成彬坏、跨節(jié)點(diǎn)排序/分組/表關(guān)聯(lián)朦促、多數(shù)據(jù)源事務(wù)處理和數(shù)據(jù)庫(kù)擴(kuò)容等。

任何Sharding系統(tǒng)栓始,在上線運(yùn)行一段時(shí)間后务冕,數(shù)據(jù)就會(huì)積累到當(dāng)前節(jié)點(diǎn)規(guī)模所能承載的上限,此時(shí)就需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行擴(kuò)容了幻赚,也就是增加新的物理結(jié)點(diǎn)來分?jǐn)倲?shù)據(jù)禀忆。如果系統(tǒng)使用的是基于ID進(jìn)行散列的路由方式,那么團(tuán)隊(duì)需要根據(jù)新的節(jié)點(diǎn)規(guī)模重新計(jì)算所有數(shù)據(jù)應(yīng)處的目標(biāo)Shard落恼,并將其遷移過去箩退,這對(duì)團(tuán)隊(duì)來說無疑是一個(gè)巨大的維護(hù)負(fù)擔(dān);而如果系統(tǒng)是按增量區(qū)間進(jìn)行路由(如每1千萬條數(shù)據(jù)或是每一個(gè)月的數(shù)據(jù)存放在一個(gè)節(jié)點(diǎn)上 )佳谦,雖然可以避免數(shù)據(jù)的遷移戴涝,卻有可能帶來“熱點(diǎn)”問題,也就是近期系統(tǒng)的讀寫都集中在最新創(chuàng)建的節(jié)點(diǎn)上(很多系統(tǒng)都有此類特點(diǎn):新生數(shù)據(jù)的讀寫頻率明顯高于舊有數(shù)據(jù)),從而影響了系統(tǒng)性能啥刻。面對(duì)這種兩難的處境奸鸯,Sharding擴(kuò)容顯得異常困難。

一般來說可帽,“理想”的擴(kuò)容方案應(yīng)該努力滿足以下幾個(gè)要求:

  • 最好不遷移數(shù)據(jù) (無論如何娄涩,數(shù)據(jù)遷移都是一個(gè)讓團(tuán)隊(duì)壓力山大的問題)
  • 允許根據(jù)硬件資源自由規(guī)劃擴(kuò)容規(guī)模和節(jié)點(diǎn)存儲(chǔ)負(fù)載
  • 能均勻的分布數(shù)據(jù)讀寫,避免“熱點(diǎn)”問題
  • 保證對(duì)已經(jīng)達(dá)到存儲(chǔ)上限的節(jié)點(diǎn)不再寫入數(shù)據(jù)

目前映跟,能夠避免數(shù)據(jù)遷移的優(yōu)秀方案并不多蓄拣,相對(duì)可行的有兩種,一種是維護(hù)一張記錄數(shù)據(jù)ID和目標(biāo)Shard對(duì)應(yīng)關(guān)系的映射表努隙,寫入時(shí)球恤,數(shù)據(jù)都寫入新擴(kuò)容的Shard,同時(shí)將ID和目標(biāo)節(jié)點(diǎn)寫入映射表荸镊,讀取時(shí)碎捺,先查映射表,找到目標(biāo)Shard后再執(zhí)行查詢贷洲。該方案簡(jiǎn)單有效,但是讀寫數(shù)據(jù)都需要訪問兩次數(shù)據(jù)庫(kù)晋柱,且映射表本身也極易成為性能瓶頸优构。為此系統(tǒng)不得不引入分布式緩存來緩存映射表數(shù)據(jù),但是這樣也無法避免在寫入時(shí)訪問兩次數(shù)據(jù)庫(kù)雁竞,同時(shí)大量映射數(shù)據(jù)對(duì)緩存資源的消耗以及專門為此而引入分布式緩存的代價(jià)都是需要權(quán)衡的問題钦椭。另一種方案來自淘寶綜合業(yè)務(wù)平臺(tái)團(tuán)隊(duì),它利用對(duì)2的倍數(shù)取余具有向前兼容的特性(如對(duì)4取余得1的數(shù)對(duì)2取余也是1)來分配數(shù)據(jù)碑诉,避免了行級(jí)別的數(shù)據(jù)遷移彪腔,但是依然需要進(jìn)行表級(jí)別的遷移,同時(shí)對(duì)擴(kuò)容規(guī)模和分表數(shù)量都有限制进栽〉抡酰總得來說,這些方案都不是十分的理想快毛,多多少少都存在一些缺點(diǎn)格嗅,這也從一個(gè)側(cè)面反映出了Sharding擴(kuò)容的難度。

一種理想的Sharding擴(kuò)容方案

先hash取模水平劃分到不同的shard唠帝,再在shard中采用范圍劃分到不同的區(qū)域范圍表

階段一:初始上線

假設(shè)某系統(tǒng)初始上線屯掖,規(guī)劃為某表提供4000W條記錄的存儲(chǔ)能力,若單表存儲(chǔ)上限為1000W條襟衰,單庫(kù)存儲(chǔ)上限為2000W條贴铜,共需2個(gè)Shard,每個(gè)Shard包含兩個(gè)分段表,ShardGroup增量區(qū)間為0-4000W绍坝,按2取余分散到2個(gè)Shard上徘意,具體規(guī)劃方案如下:



與之相適應(yīng),Sharding拓?fù)浣Y(jié)構(gòu)的元數(shù)據(jù)如下:


階段二:系統(tǒng)擴(kuò)容

經(jīng)過一段時(shí)間的運(yùn)行陷嘴,當(dāng)原表總數(shù)據(jù)逼近4000W條上限時(shí)映砖,系統(tǒng)就需要擴(kuò)容了。為了演示方案的靈活性灾挨,我們假設(shè)現(xiàn)在有三臺(tái)服務(wù)器Shard2邑退、Shard3、Shard4劳澄,其性能和存儲(chǔ)能力表現(xiàn)依次為Shard2<Shard3<Shard4地技,我們安排Shard2儲(chǔ)存1000W條記錄,Shard3儲(chǔ)存2000W條記錄秒拔,Shard4儲(chǔ)存3000W條記錄莫矗,這樣,該表的總存儲(chǔ)能力將由擴(kuò)容前的4000W條提升到10000W條砂缩,以下是詳細(xì)的規(guī)劃方案:


元數(shù)據(jù)表結(jié)構(gòu):


一種更帥氣的簡(jiǎn)單實(shí)用的擴(kuò)容方案:


再次看一眼擴(kuò)容前的架構(gòu)作谚,分兩個(gè)庫(kù),假設(shè)每個(gè)庫(kù)1億數(shù)據(jù)量庵芭,如何平滑擴(kuò)容妹懒,增加實(shí)例數(shù),降低單庫(kù)數(shù)據(jù)量呢双吆?三個(gè)簡(jiǎn)單步驟搞定眨唬。

  • 修改配置



    主要修改兩處:
    a)數(shù)據(jù)庫(kù)實(shí)例所在的機(jī)器做雙虛ip,原來%2=0的庫(kù)是虛ip0好乐,現(xiàn)在增加一個(gè)虛ip00匾竿,%2=1的另一個(gè)庫(kù)同理
    b)修改服務(wù)的配置(不管是在配置文件里,還是在配置中心)蔚万,將2個(gè)庫(kù)的數(shù)據(jù)庫(kù)配置岭妖,改為4個(gè)庫(kù)的數(shù)據(jù)庫(kù)配置,修改的時(shí)候要注意舊庫(kù)與辛苦的映射關(guān)系:
    %2=0的庫(kù)反璃,會(huì)變?yōu)?4=0與%4=2区转;
    %2=1的部分,會(huì)變?yōu)?4=1與%4=3版扩;
    這樣修改是為了保證废离,拆分后依然能夠路由到正確的數(shù)據(jù)。

  • reload配置礁芦,實(shí)例擴(kuò)容



    服務(wù)層reload配置蜻韭,reload可能是這么幾種方式:
    a)比較原始的悼尾,重啟服務(wù),讀新的配置文件
    b)高級(jí)一點(diǎn)的肖方,配置中心給服務(wù)發(fā)信號(hào)闺魏,重讀配置文件,重新初始化數(shù)據(jù)庫(kù)連接池

不管哪種方式俯画,reload之后析桥,數(shù)據(jù)庫(kù)的實(shí)例擴(kuò)容就完成了,原來是2個(gè)數(shù)據(jù)庫(kù)實(shí)例提供服務(wù)艰垂,現(xiàn)在變?yōu)?個(gè)數(shù)據(jù)庫(kù)實(shí)例提供服務(wù)泡仗,這個(gè)過程一般可以在秒級(jí)完成。

整個(gè)過程可以逐步重啟猜憎,對(duì)服務(wù)的正確性和可用性完全沒有影響:
a)即使%2尋庫(kù)和%4尋庫(kù)同時(shí)存在娩怎,也不影響數(shù)據(jù)的正確性,因?yàn)榇藭r(shí)仍然是雙主數(shù)據(jù)同步的
b)服務(wù)reload之前是不對(duì)外提供服務(wù)的胰柑,冗余的服務(wù)能夠保證高可用

完成了實(shí)例的擴(kuò)展截亦,會(huì)發(fā)現(xiàn)每個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)量依然沒有下降,所以第三個(gè)步驟還要做一些收尾工作柬讨。

  • 收尾工作崩瓤,數(shù)據(jù)收縮



    有這些一些收尾工作:
    a)把雙虛ip修改回單虛ip
    b)解除舊的雙主同步,讓成對(duì)庫(kù)的數(shù)據(jù)不再同步增加
    c)增加新的雙主同步踩官,保證高可用
    d)刪除掉冗余數(shù)據(jù)谷遂,例如:ip0里%4=2的數(shù)據(jù)全部干掉,只為%4=0的數(shù)據(jù)提供服務(wù)啦

這樣下來卖鲤,每個(gè)庫(kù)的數(shù)據(jù)量就降為原來的一半,數(shù)據(jù)收縮完成畴嘶。

  • 總結(jié)



    該帥氣方案能夠?qū)崿F(xiàn)n庫(kù)擴(kuò)2n庫(kù)的秒級(jí)蛋逾、平滑擴(kuò)容,增加數(shù)據(jù)庫(kù)服務(wù)能力窗悯,降低單庫(kù)一半的數(shù)據(jù)量区匣,其核心原理是:成倍擴(kuò)容,避免數(shù)據(jù)遷移蒋院。

Ref:
http://blog.csdn.net/bluishglc/article/details/6161475
http://blog.csdn.net/bluishglc/article/details/7696085
http://blog.csdn.net/bluishglc/article/details/7970268
http://mp.weixin.qq.com/s/BLOneOs-cPxP_9b5eH8oQA

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末亏钩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子欺旧,更是在濱河造成了極大的恐慌姑丑,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辞友,死亡現(xiàn)場(chǎng)離奇詭異栅哀,居然都是意外死亡震肮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門留拾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戳晌,“玉大人,你說我怎么就攤上這事痴柔÷儋耍” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵咳蔚,是天一觀的道長(zhǎng)豪嚎。 經(jīng)常有香客問我,道長(zhǎng)屹篓,這世上最難降的妖魔是什么疙渣? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮堆巧,結(jié)果婚禮上妄荔,老公的妹妹穿的比我還像新娘。我一直安慰自己谍肤,他們只是感情好啦租,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荒揣,像睡著了一般篷角。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上系任,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天恳蹲,我揣著相機(jī)與錄音,去河邊找鬼俩滥。 笑死嘉蕾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的霜旧。 我是一名探鬼主播错忱,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挂据!你這毒婦竟也來了以清?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤崎逃,失蹤者是張志新(化名)和其女友劉穎掷倔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體个绍,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡今魔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年勺像,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片错森。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吟宦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涩维,到底是詐尸還是另有隱情殃姓,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布瓦阐,位于F島的核電站蜗侈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏睡蟋。R本人自食惡果不足惜踏幻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一掏导、第九天 我趴在偏房一處隱蔽的房頂上張望重虑。 院中可真熱鬧须肆,春花似錦缰雇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹦赎。三九已至傍菇,卻和暖如春猾瘸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丢习。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工牵触, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咐低。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓揽思,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親渊鞋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容