1、前言
在互聯(lián)網(wǎng)還未崛起的時(shí)代,我們的傳統(tǒng)應(yīng)用都有這樣一個(gè)特點(diǎn):訪問量和數(shù)據(jù)量都比較小,單庫單表完全可以支撐整個(gè)業(yè)務(wù)。隨著互聯(lián)網(wǎng)的發(fā)展和用戶規(guī)模的迅速擴(kuò)大,對(duì)系統(tǒng)的要求也越來越高。因此傳統(tǒng)的MySQL單庫單表架構(gòu)的性能問題就暴露出來了。有下面幾個(gè)因素會(huì)影響數(shù)據(jù)庫性能:
(一)數(shù)據(jù)量
MySQL單庫數(shù)據(jù)量在5000萬以內(nèi)性能比較好,超過閾值后性能會(huì)隨著數(shù)據(jù)量的增大而變?nèi)?。MySQL單表的數(shù)據(jù)量是500w-1000w之間性能比較好,超過1000w性能也會(huì)下降。
(二)磁盤
因?yàn)閱蝹€(gè)服務(wù)的磁盤空間是有限制的,如果并發(fā)壓力下,所有的請(qǐng)求都訪問同一個(gè)節(jié)點(diǎn),肯定會(huì)對(duì)磁盤IO造成非常大的影響。
(三)數(shù)據(jù)庫連接
數(shù)據(jù)庫連接是非常稀少的資源,如果一個(gè)庫里既有用戶、商品、訂單相關(guān)的數(shù)據(jù),當(dāng)海量用戶同時(shí)操作時(shí),數(shù)據(jù)庫連接就很可能成為瓶頸。
為了提升性能,所以我們必須要解決上述幾個(gè)問題,那就有必要引進(jìn)分庫分表。
2、垂直拆分 or 水平拆分
當(dāng)我們單個(gè)庫太大時(shí),我們先要看一下是因?yàn)楸硖噙€是數(shù)據(jù)量太大,如果是表太多,則應(yīng)該將部分表進(jìn)行遷移(可以按業(yè)務(wù)區(qū)分),這就是所謂的垂直切分。如果是數(shù)據(jù)量太大,則需要將表拆成更多的小表,來減少單表的數(shù)據(jù)量,這就是所謂的水平拆分。
2.1、垂直拆分
(一)垂直分庫
垂直分庫針對(duì)的是一個(gè)系統(tǒng)中的不同業(yè)務(wù)進(jìn)行拆分,比如用戶一個(gè)庫,商品一個(gè)庫,訂單一個(gè)庫。 一個(gè)購物網(wǎng)站對(duì)外提供服務(wù)時(shí),會(huì)同時(shí)對(duì)用戶、商品、訂單表進(jìn)行操作。沒拆分之前, 全部都是落到單一的庫上的,這會(huì)讓數(shù)據(jù)庫的單庫處理能力成為瓶頸。如果垂直分庫后還是將用戶、商品、訂單放到同一個(gè)服務(wù)器上,只是分到了不同的庫,這樣雖然會(huì)減少單庫的壓力,但是隨著用戶量增大,這會(huì)讓整個(gè)數(shù)據(jù)庫的處理能力成為瓶頸,還有單個(gè)服務(wù)器的磁盤空間、內(nèi)存也會(huì)受非常大的影響。 所以我們要將其拆分到多個(gè)服務(wù)器上,這樣上面的問題都解決了,以后也不會(huì)面對(duì)單機(jī)資源問題。
(二)垂直分表
也就是“大表拆小表”,基于列字段進(jìn)行的。一般是表中的字段較多,將不常用的, 數(shù)據(jù)較大,長(zhǎng)度較長(zhǎng)(比如text類型字段)的拆分到“擴(kuò)展表”。一般是針對(duì)那種幾百列的大表,也避免查詢時(shí),數(shù)據(jù)量太大造成的“跨頁”問題。
2.2、水平拆分
(一)水平分表
和垂直分表有一點(diǎn)類似,不過垂直分表是基于列的,而水平分表是基于全表的。水平拆分可以大大減少單表數(shù)據(jù)量,提升查詢效率。
(二)水平分庫分表
將單張表的數(shù)據(jù)切分到多個(gè)服務(wù)器上去,每個(gè)服務(wù)器具有相應(yīng)的庫與表,只是表中數(shù)據(jù)集合不同。 水平分庫分表能夠有效的緩解單機(jī)和單庫的性能瓶頸和壓力,突破IO、連接數(shù)、硬件資源等的瓶頸。
3、幾種常用的分庫分表的策略
(一)HASH取模
假設(shè)有用戶表user,將其分成3個(gè)表user0,user1,user2。路由規(guī)則是對(duì)3取模,當(dāng)uid=1時(shí),對(duì)應(yīng)到的是user1,uid=2時(shí),對(duì)應(yīng)的是user2。
(二)范圍分片
從1-10000一個(gè)表,0001-20000一個(gè)表。
(三)地理位置分片
華南區(qū)一個(gè)表,華北一個(gè)表。
(四)時(shí)間分片
按月分片,按季度分片等等,可以做到冷熱數(shù)據(jù)。
4、分庫分表后引入的問題
(一)分布式事務(wù)問題
如果我們做了垂直分庫或者水平分庫以后,就必然會(huì)涉及到跨庫執(zhí)行SQL的問題,這樣就引發(fā)了互聯(lián)網(wǎng)界的老大難問題——分布式事務(wù)。那要如何解決這個(gè)問題呢?
1) 使用分布式事務(wù)中間件。
2) 使用MySQL自帶的針對(duì)跨庫的事務(wù)一致性方案(XA),不過性能要比單庫的慢10倍左右。
3) 能否避免掉跨庫操作(比如將用戶和商品放在同一個(gè)庫中)。
(二)跨庫join的問題
分庫分表后表之間的關(guān)聯(lián)操作將受到限制,我們無法join位于不同分庫的表,也無法join分表粒度不同的表, 結(jié)果原本一次查詢能夠完成的業(yè)務(wù),可能需要多次查詢才能完成。粗略的解決方法:
1) 全局表:基礎(chǔ)數(shù)據(jù),所有庫都拷貝一份。
2) 字段冗余:這樣有些字段就不用join去查詢了。
3) 系統(tǒng)層組裝:分別查詢出所有,然后組裝起來,較復(fù)雜。
(三)橫向擴(kuò)容的問題
當(dāng)我們使用HASH取模做分表的時(shí)候,針對(duì)數(shù)據(jù)量的遞增,可能需要?jiǎng)討B(tài)的增加表,此時(shí)就需要考慮因?yàn)閞eHash導(dǎo)致數(shù)據(jù)遷移的問題。
(四)結(jié)果集合并/排序的問題
因?yàn)槲覀兪菍?shù)據(jù)分散存儲(chǔ)到不同的庫、表里的,當(dāng)我們查詢指定數(shù)據(jù)列表時(shí),數(shù)據(jù)來源于不同的子庫或者子表,就必然會(huì)引發(fā)結(jié)果集合并/排序的問題。如果每次查詢都需要排序、合并等操作,性能肯定會(huì)受非常大的影響。走緩存可能是一條路。
5、使用分庫分表中間件
(一)Mycat
Mycat發(fā)展到現(xiàn)在,適用的場(chǎng)景已經(jīng)很豐富,而且不斷有新用戶給出新的創(chuàng)新性的方案,以下是幾個(gè)典型的應(yīng)用場(chǎng)景:
1) 單純的讀寫分離,此時(shí)配置最為簡(jiǎn)單,支持讀寫分離,主從切換。
2) 分表分庫,對(duì)于超過1000萬的表進(jìn)行分片,最大支持1000億的單表分片。
3) 多租戶應(yīng)用,每個(gè)應(yīng)用一個(gè)庫,但應(yīng)用程序只連接Mycat,從而不改造程序本身,實(shí)現(xiàn)多租戶化報(bào)表系統(tǒng),借助于Mycat的分表能力,處理大規(guī)模報(bào)表的統(tǒng)計(jì)。
4) 替代Hbase,分析大數(shù)據(jù)作為海量數(shù)據(jù)實(shí)時(shí)查詢的一種簡(jiǎn)單有效方案,比如100億條頻繁查詢的記錄需要在3秒內(nèi)查詢出來結(jié)果,除了基于主鍵的查詢,還可能存在范圍查詢或其他屬性查詢,此時(shí)Mycat可能是最簡(jiǎn)單有效的選擇。
(二)Sharding-JDBC
當(dāng)當(dāng)網(wǎng)開發(fā)的簡(jiǎn)單易用、輕量級(jí)的中間件。
此外還有淘寶的TDDL,支付寶的OneProxy,360的Atlas等。
轉(zhuǎn)自:http://www.itdecent.cn/p/7aec260ca1a2