面試官系列尼桶,深入數(shù)據(jù)庫分區(qū)分庫分表

一、為什么要分庫分表

軟件時代锯仪,傳統(tǒng)應(yīng)用都有這樣一個特點(diǎn):訪問量泵督、數(shù)據(jù)量都比較小,單庫單表都完全可以支撐整個業(yè)務(wù)庶喜。隨著互聯(lián)網(wǎng)的發(fā)展和用戶規(guī)模的迅速擴(kuò)大小腊,對系統(tǒng)的要求也越來越高。因此傳統(tǒng)的MySQL單庫單表架構(gòu)的性能問題就暴露出來了久窟。而有下面幾個因素會影響數(shù)據(jù)庫性能:

  • 數(shù)據(jù)量

MySQL單庫數(shù)據(jù)量在5000萬以內(nèi)性能比較好秩冈,超過閾值后性能會隨著數(shù)據(jù)量的增大而變?nèi)酢ySQL單表的數(shù)據(jù)量是500w-1000w之間性能比較好斥扛,超過1000w性能也會下降漩仙。

  • 磁盤

因為單個服務(wù)的磁盤空間是有限制的,如果并發(fā)壓力下,所有的請求都訪問同一個節(jié)點(diǎn)队他,肯定會對磁盤IO造成非常大的影響卷仑。

  • 數(shù)據(jù)庫連接

數(shù)據(jù)庫連接是非常稀少的資源,如果一個庫里既有用戶麸折、商品锡凝、訂單相關(guān)的數(shù)據(jù),當(dāng)海量用戶同時操作時垢啼,數(shù)據(jù)庫連接就很可能成為瓶頸窜锯。

為了提升性能,所以我們必須要解決上述幾個問題芭析,那就有必要引進(jìn)分庫分表锚扎,當(dāng)然除了分庫分表,還有別的解決方案馁启,就是NoSQL和NewSQL驾孔,NoSQL主要是MongoDB等,NewSQL則以TiDB為代表惯疙。

二翠勉、分區(qū)分庫分表的原理

1、什么是分區(qū)霉颠、分表对碌、分庫

(1)分區(qū)

就是把一張表的數(shù)據(jù)分成N個區(qū)塊,在邏輯上看最終只是一張表蒿偎,但底層是由N個物理區(qū)塊組成的朽们,分區(qū)實(shí)現(xiàn)比較簡單,數(shù)據(jù)庫mysql诉位、oracle等很容易就可支持华坦。

(2)分表

就是把一張表按一定的規(guī)則分解成N個具有獨(dú)立存儲空間的實(shí)體表。系統(tǒng)讀寫時需要根據(jù)定義好的規(guī)則得到對應(yīng)的字表明不从,然后操作它惜姐。

(3)分庫

一旦分表,一個庫中的表會越來越多椿息,將整個數(shù)據(jù)庫比作圖書館歹袁,一張表就是一本書。當(dāng)要在一本書中查找某項內(nèi)容時寝优,如果不分章節(jié)条舔,查找的效率將會下降。而同理乏矾,在數(shù)據(jù)庫中就是分區(qū)孟抗。

2迁杨、什么時候使用分區(qū)?

一張表的查詢速度已經(jīng)慢到影響使用的時候凄硼。

  • sql經(jīng)過優(yōu)化
  • 數(shù)據(jù)量大
  • 表中的數(shù)據(jù)是分段的
  • 對數(shù)據(jù)的操作往往只涉及一部分?jǐn)?shù)據(jù)铅协,而不是所有的數(shù)據(jù)

最常見的分區(qū)方法就是按照時間進(jìn)行分區(qū),分區(qū)一個最大的優(yōu)點(diǎn)就是可以非常高效的進(jìn)行歷史數(shù)據(jù)的清理摊沉。

(1)分區(qū)的實(shí)現(xiàn)方式

mysql5自5.1開始對分區(qū)(Partition)有支持狐史。

(2)分區(qū)類型

目前MySQL支持范圍分區(qū)(RANGE),列表分區(qū)(LIST)说墨,哈希分區(qū)(HASH)以及KEY分區(qū)四種骏全。

(3)RANGE分區(qū)實(shí)例

基于屬于一個給定連續(xù)區(qū)間的列值,把多行分配給分區(qū)尼斧。最常見的是基于時間字段. 基于分區(qū)的列最好是整型姜贡,如果日期型的可以使用函數(shù)轉(zhuǎn)換為整型。本例中使用to_days函數(shù)棺棵。

CREATE TABLE my_range_datetime(
    id INT,
    hiredate DATETIME
) 
PARTITION BY RANGE (TO_DAYS(hiredate) ) (
    PARTITION p1 VALUES LESS THAN ( TO_DAYS('20171202') ),
    PARTITION p2 VALUES LESS THAN ( TO_DAYS('20171203') ),
    PARTITION p3 VALUES LESS THAN ( TO_DAYS('20171204') ),
    PARTITION p4 VALUES LESS THAN ( TO_DAYS('20171205') ),
    PARTITION p5 VALUES LESS THAN ( TO_DAYS('20171206') ),
    PARTITION p6 VALUES LESS THAN ( TO_DAYS('20171207') ),
    PARTITION p7 VALUES LESS THAN ( TO_DAYS('20171208') ),
    PARTITION p8 VALUES LESS THAN ( TO_DAYS('20171209') ),
    PARTITION p9 VALUES LESS THAN ( TO_DAYS('20171210') ),
    PARTITION p10 VALUES LESS THAN ( TO_DAYS('20171211') )楼咳,
    PARTITION p11 VALUES LESS THAN (MAXVALUE) 
);

3、什么時候分表律秃?

一張表的查詢速度已經(jīng)慢到影響使用的時候爬橡。

  • sql經(jīng)過優(yōu)化
  • 數(shù)據(jù)量大
  • 當(dāng)頻繁插入或者聯(lián)合查詢時治唤,速度變慢

分表后棒动,單表的并發(fā)能力提高了,磁盤I/O性能也提高了宾添,寫操作效率提高了

(1)分表的實(shí)現(xiàn)方式

需要結(jié)合相關(guān)中間件船惨,需要業(yè)務(wù)系統(tǒng)配合遷移升級,工作量較大缕陕。

三粱锐、分庫分表后引入的問題

1、分布式事務(wù)問題

如果我們做了垂直分庫或者水平分庫以后扛邑,就必然會涉及到跨庫執(zhí)行SQL的問題怜浅,這樣就引發(fā)了互聯(lián)網(wǎng)界的老大難問題-"分布式事務(wù)"。那要如何解決這個問題呢蔬崩?
1.使用分布式事務(wù)中間件 2.使用MySQL自帶的針對跨庫的事務(wù)一致性方案(XA)恶座,不過性能要比單庫的慢10倍左右。3.能否避免掉跨庫操作(比如將用戶和商品放在同一個庫中)

2沥阳、跨庫join的問題

分庫分表后表之間的關(guān)聯(lián)操作將受到限制跨琳,我們無法join位于不同分庫的表,也無法join分表粒度不同的表桐罕, 結(jié)果原本一次查詢能夠完成的業(yè)務(wù)脉让,可能需要多次查詢才能完成桂敛。粗略的解決方法: 全局表:基礎(chǔ)數(shù)據(jù),所有庫都拷貝一份溅潜。 字段冗余:這樣有些字段就不用join去查詢了术唬。 系統(tǒng)層組裝:分別查詢出所有,然后組裝起來伟恶,較復(fù)雜碴开。

3、橫向擴(kuò)容的問題

當(dāng)我們使用HASH取模做分表的時候博秫,針對數(shù)據(jù)量的遞增潦牛,可能需要動態(tài)的增加表,此時就需要考慮因為reHash導(dǎo)致數(shù)據(jù)遷移的問題挡育。

4巴碗、結(jié)果集合并、排序的問題

因為我們是將數(shù)據(jù)分散存儲到不同的庫即寒、表里的橡淆,當(dāng)我們查詢指定數(shù)據(jù)列表時,數(shù)據(jù)來源于不同的子庫或者子表母赵,就必然會引發(fā)結(jié)果集合并逸爵、排序的問題。如果每次查詢都需要排序凹嘲、合并等操作师倔,性能肯定會受非常大的影響。走緩存可能一條路!

四周蹭、分庫分表中間件設(shè)計

分表又分為單庫分表(表名不同)和多庫分表(表名相同)趋艘,不管使用哪種策略都還需要自己去實(shí)現(xiàn)路由,制定路由規(guī)則等凶朗,可以考慮使用開源的分庫分表中間件瓷胧,無侵入應(yīng)用設(shè)計,例如淘寶的tddl等棚愤。

分庫分表中間件全部可以歸結(jié)為兩大類型:

  • CLIENT模式搓萧;
  • PROXY模式;

CLIENT模式代表有阿里的TDDL宛畦,開源社區(qū)的sharding-jdbc(sharding-jdbc的3.x版本即sharding-sphere已經(jīng)支持了proxy模式)瘸洛。

架構(gòu)如下:

PROXY模式代表有阿里的cobar,民間組織的MyCAT刃永。架構(gòu)如下:

無論是CLIENT模式货矮,還是PROXY模式。幾個核心的步驟是一樣的:SQL解析斯够,重寫囚玫,路由喧锦,執(zhí)行,結(jié)果歸并抓督。

五燃少、分庫分表常用中間件

目前應(yīng)用比較多的基本有以下幾種,

  • TDDL
  • Sharding-jdbc
  • Mycat
  • Cobar

1铃在、TDDL

淘寶團(tuán)隊開發(fā)的阵具,屬于 client 層方案。支持基本的 crud 語法和讀寫分離定铜,但不支持 join阳液、多表查詢等語法。

2揣炕、Sharding-jdbc

當(dāng)當(dāng)開源的帘皿,屬于 client 層方案,目前已經(jīng)更名為 ShardingSphere畸陡。SQL 語法支持也比較多鹰溜,沒有太多限制,支持分庫分表丁恭、讀寫分離曹动、分布式 id 生成、柔性事務(wù)(最大努力送達(dá)型事務(wù)牲览、TCC 事務(wù))墓陈。

3、Cobar

阿里 b2b 團(tuán)隊開發(fā)和開源的竭恬,屬于 proxy 層方案跛蛋,就是介于應(yīng)用服務(wù)器和數(shù)據(jù)庫服務(wù)器之間熬的。應(yīng)用程序通過 JDBC 驅(qū)動訪問 Cobar 集群痊硕,Cobar 根據(jù) SQL 和分庫規(guī)則對 SQL 做分解,然后分發(fā)到 MySQL 集群不同的數(shù)據(jù)庫實(shí)例上執(zhí)行押框。

4岔绸、Mycat

基于 Cobar 改造的,屬于 proxy 層方案橡伞,支持的功能完善盒揉,社區(qū)活躍。

六兑徘、常見分表刚盈、分庫常用策略

  1. 平均進(jìn)行分配hash(object)%N(適用于簡單架構(gòu))。
  2. 按照權(quán)重進(jìn)行分配且均勻輪詢挂脑。
  3. 按照業(yè)務(wù)進(jìn)行分配藕漱。
  4. 按照一致性hash算法進(jìn)行分配(適用于集群架構(gòu)欲侮,在集群中節(jié)點(diǎn)的添加和刪除不會造成數(shù)據(jù)丟失,方便數(shù)據(jù)遷移)肋联。

七威蕉、全局ID生成策略

1、自動增長列

優(yōu)點(diǎn):數(shù)據(jù)庫自帶功能橄仍,有序韧涨,性能佳。
缺點(diǎn):單庫單表無妨侮繁,分庫分表時如果沒有規(guī)劃虑粥,ID可能重復(fù)。

解決方案宪哩,一個是設(shè)置自增偏移和步長舀奶。

  • 假設(shè)總共有 10 個分表
  • 級別可選: SESSION(會話級), GLOBAL(全局)
  • SET @@SESSION.auto_increment_offset = 1; ## 起始值, 分別取值為 1~10
  • SET @@SESSION.auto_increment_increment = 10; ## 步長增量

如果采用該方案,在擴(kuò)容時需要遷移已有數(shù)據(jù)至新的所屬分片斋射。

另一個是全局ID映射表育勺。

  • 在全局 Redis 中為每張數(shù)據(jù)表創(chuàng)建一個 ID 的鍵,記錄該表當(dāng)前最大 ID罗岖;
  • 每次申請 ID 時涧至,都自增 1 并返回給應(yīng)用;
  • Redis 要定期持久至全局?jǐn)?shù)據(jù)庫桑包。

2南蓬、UUID(128位)

在一臺機(jī)器上生成的數(shù)字,它保證對在同一時空中的所有機(jī)器都是唯一的哑了。通常平臺會提供生成UUID的API赘方。

UUID 由4個連字號(-)將32個字節(jié)長的字符串分隔后生成的字符串,總共36個字節(jié)長弱左。形如:550e8400-e29b-41d4-a716-446655440000窄陡。

UUID 的計算因子包括:以太網(wǎng)卡地址、納秒級時間拆火、芯片ID碼和許多可能的數(shù)字跳夭。
UUID 是個標(biāo)準(zhǔn),其實(shí)現(xiàn)有幾種们镜,最常用的是微軟的 GUID(Globals Unique Identifiers)币叹。

  • 優(yōu)點(diǎn):簡單,全球唯一模狭;
  • 缺點(diǎn):存儲和傳輸空間大颈抚,無序,性能欠佳嚼鹉。

3贩汉、COMB(組合)

組合 GUID(10字節(jié)) 和時間(6字節(jié))九妈,達(dá)到有序的效果,提高索引性能雾鬼。

4萌朱、Snowflake(雪花) 算法

Snowflake 是 Twitter 開源的分布式 ID 生成算法,其結(jié)果為 long(64bit) 的數(shù)值策菜。
其特性是各節(jié)點(diǎn)無需協(xié)調(diào)晶疼、按時間大致有序、且整個集群各節(jié)點(diǎn)單不重復(fù)又憨。
該數(shù)值的默認(rèn)組成如下(符號位之外的三部分允許個性化調(diào)整):

  • 1bit: 符號位翠霍,總是 0(為了保證數(shù)值是正數(shù))。
  • 41bit: 毫秒數(shù)(可用 69 年)蠢莺;
  • 10bit: 節(jié)點(diǎn)ID(5bit數(shù)據(jù)中心 + 5bit節(jié)點(diǎn)ID寒匙,支持 32 * 32 = 1024 個節(jié)點(diǎn))
  • 12bit: 流水號(每個節(jié)點(diǎn)每毫秒內(nèi)支持 4096 個 ID,相當(dāng)于 409萬的 QPS躏将,相同時間內(nèi)如 ID 遇翻轉(zhuǎn)锄弱,則等待至下一毫秒)

八、優(yōu)雅實(shí)現(xiàn)分庫分表的動態(tài)擴(kuò)容

優(yōu)雅的設(shè)計擴(kuò)容縮容的意思就是 進(jìn)行擴(kuò)容縮容的代價要小祸憋,遷移數(shù)據(jù)要快会宪。

可以采用邏輯分庫分表的方式來代替物理分庫分表的方式,要擴(kuò)容縮容時蚯窥,只需要將邏輯上的數(shù)據(jù)庫掸鹅、表改為物理上的數(shù)據(jù)庫、表拦赠。

第一次進(jìn)行分庫分表時就多分幾個庫巍沙,一個實(shí)踐是利用32 * 32來分庫分表,即分為32個庫荷鼠,每個庫32張表句携,一共就是1024張表,根據(jù)某個id先根據(jù)先根據(jù)數(shù)據(jù)庫數(shù)量32取模路由到庫颊咬,再根據(jù)一個庫的表數(shù)量32取模路由到表里面务甥。

剛開始的時候牡辽,這個庫可能就是邏輯庫喳篇,建在一個mysql服務(wù)上面,比如一個mysql服務(wù)器建了16個數(shù)據(jù)庫态辛。

如果后面要進(jìn)行拆分麸澜,就是不斷的在庫和mysql實(shí)例之間遷移就行了。將mysql服務(wù)器的庫搬到另外的一個服務(wù)器上面去奏黑,比如每個服務(wù)器創(chuàng)建8個庫炊邦,這樣就由兩臺mysql服務(wù)器變成了4臺mysql服務(wù)器编矾。我們系統(tǒng)只需要配置一下新增的兩臺服務(wù)器即可。

比如說最多可以擴(kuò)展到32個數(shù)據(jù)庫服務(wù)器馁害,每個數(shù)據(jù)庫服務(wù)器是一個庫窄俏。如果還是不夠?最多可以擴(kuò)展到1024個數(shù)據(jù)庫服務(wù)器碘菜,每個數(shù)據(jù)庫服務(wù)器上面一個庫一個表凹蜈。因為最多是1024個表么。

這么搞忍啸,是不用自己寫代碼做數(shù)據(jù)遷移的仰坦,都交給dba來搞好了,但是dba確實(shí)是需要做一些庫表遷移的工作计雌,但是總比你自己寫代碼悄晃,抽數(shù)據(jù)導(dǎo)數(shù)據(jù)來的效率高得多了。

哪怕是要減少庫的數(shù)量凿滤,也很簡單妈橄,其實(shí)說白了就是按倍數(shù)縮容就可以了,然后修改一下路由規(guī)則翁脆。

參考文檔

shardingsphere.apache.org
深度認(rèn)識 Sharding-JDBC

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眷细,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鹃祖,更是在濱河造成了極大的恐慌溪椎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恬口,死亡現(xiàn)場離奇詭異校读,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祖能,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門歉秫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人养铸,你說我怎么就攤上這事雁芙。” “怎么了钞螟?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵兔甘,是天一觀的道長。 經(jīng)常有香客問我鳞滨,道長洞焙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮澡匪,結(jié)果婚禮上熔任,老公的妹妹穿的比我還像新娘。我一直安慰自己唁情,他們只是感情好疑苔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甸鸟,像睡著了一般夯巷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哀墓,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天趁餐,我揣著相機(jī)與錄音,去河邊找鬼后雷。 笑死,一個胖子當(dāng)著我的面吹牛吠各,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贾漏,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼纵散!你這毒婦竟也來了梳码?” 一聲冷哼從身側(cè)響起伍掀,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜜笤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體把兔,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沪伙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了县好。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片围橡。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖聘惦,靈堂內(nèi)的尸體忽然破棺而出某饰,到底是詐尸還是另有隱情儒恋,我是刑警寧澤善绎,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布黔漂,位于F島的核電站,受9級特大地震影響禀酱,放射性物質(zhì)發(fā)生泄漏炬守。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一剂跟、第九天 我趴在偏房一處隱蔽的房頂上張望减途。 院中可真熱鬧,春花似錦曹洽、人聲如沸鳍置。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽税产。三九已至,卻和暖如春偷崩,著一層夾襖步出監(jiān)牢的瞬間辟拷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工阐斜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衫冻,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓谒出,卻偏偏與公主長得像隅俘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笤喳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

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

  • 分區(qū):對業(yè)務(wù)透明考赛,分區(qū)只不過把存放數(shù)據(jù)的文件分成了許多小塊,例如mysql中的一張表對應(yīng)三個文件.MYD,MYI,...
    yangfhit閱讀 1,397評論 0 2
  • 歡迎關(guān)注筆者的公眾號:【阿飛的博客】莉测,首發(fā)都在這里Q罩琛!捣卤! 每個優(yōu)秀的程序員和架構(gòu)師都應(yīng)該掌握分庫分表忍抽,這是我的觀點(diǎn)...
    阿飛的博客閱讀 7,700評論 9 206
  • 扎根水下泥, 冉冉躍瑤池董朝, 不喝瓊漿酒鸠项, 青青池中萍。
    利創(chuàng)天閱讀 357評論 0 7
  • 五月二十七日凌晨祟绊,驚雷滾滾擾我夢境,想起離家北上數(shù)月之久牧抽,不免難眠。家中人事實(shí)在甚為思念阐肤。 ――周大柱 ...
    周大柱閱讀 158評論 0 4
  • 上周的某天孕惜,天已轉(zhuǎn)涼,但兒子還是把床頭的微型吊扇開了整夜衫画。第二天便開始發(fā)燒瓮栗,腹瀉。後來趨於好轉(zhuǎn)遵馆,大家便沒放在心上,...
    如心1976閱讀 212評論 2 0