{eval=Array;=+count(Array);}
分庫分表是比較靠后的優(yōu)化手段,因?yàn)槌杀颈容^高。
遇到數(shù)據(jù)庫瓶頸:
- 首先考慮sql優(yōu)化,這是最簡單的方法。對現(xiàn)有系統(tǒng)基本沒有影響。
- 其次就是考慮數(shù)據(jù)庫的讀寫分離,這也是相對簡單的方法。在數(shù)據(jù)庫層面進(jìn)行配置,系統(tǒng)層面只需要調(diào)整一下獲取數(shù)據(jù)庫連接的邏輯。讀數(shù)據(jù)時即可以獲取主庫連接,也可以獲取從庫連接。寫數(shù)據(jù)時只獲取主庫連接。
- 再考慮增加緩存層。將數(shù)據(jù)緩存到緩存中,當(dāng)再次訪問時不再從數(shù)據(jù)庫獲取。一般緩存層對系統(tǒng)是透明的,基本對系統(tǒng)本身沒有影響。但是引入緩存,也引入了相應(yīng)的需要考慮的問題,比如雪崩,命中率,分布式緩存等
- 還有一種非技術(shù)手段,就是改需求。引起性能問題的原因是否是需求不合理?或者需求太復(fù)雜?是否可以簡化需求?此方法對系統(tǒng)的影響也相對較小。
- 最后才考慮分庫分表。優(yōu)先分庫,因?yàn)橄鄬Ψ直砀唵?。將對?yīng)的表移動到新庫,調(diào)整系統(tǒng)獲取數(shù)據(jù)庫連接的邏輯。這里需要考慮要移動哪些表,在提高性能的前提下,首先盡量避免分布式事務(wù)。
- 最最后,考慮分表。分表的主要原因是單表數(shù)據(jù)量太大。分表又分縱切和橫切??v切就是按列切,比如用戶表,常用信息為基本信息表,其它信息為詳情表。橫切就是按行切,比如一億數(shù)據(jù)量的表切分為十張一千萬的表。這里就涉及數(shù)據(jù)該存放到哪張表,或從哪張表里取。分表后又可以分庫,來進(jìn)一步優(yōu)化。
- 如果涉及到分布式事務(wù),又要考慮如何保證分布式事務(wù)。理論方面2pc,3pc,paxos,cap,base。對應(yīng)的中間件的使用。
對系統(tǒng)的設(shè)計(jì)和優(yōu)化不是人云亦云,需要根據(jù)實(shí)際的場景來進(jìn)行處理。
大部分的軟件架構(gòu)、組件或解決方案,都是在解決一些問題的同時,會帶來另外的問題。
數(shù)據(jù)庫的分庫分表,又可以分為垂直拆分和水平拆分(可能大家常說的分庫分表主要指的是后者):
垂直拆分:這是一種比較常見的數(shù)據(jù)庫設(shè)計(jì)方法,就是把一個字段比較多的大表,拆分成多個小表,特別是在現(xiàn)在分布式、微服務(wù)的架構(gòu)下,可以把各個小表按照業(yè)務(wù)模型,劃分到不同的數(shù)據(jù)庫中,這樣就可以利用多臺數(shù)據(jù)庫服務(wù)器的性能;但當(dāng)被拆分出來小表的數(shù)據(jù)量不斷增長,到了一個極限的時候,還是需要考慮水平拆分。
水平拆分:將表中的數(shù)據(jù),按照一定的規(guī)則分布到不同的數(shù)據(jù)庫中,比如對主鍵進(jìn)行Hash和取模操作后,按照結(jié)果把數(shù)據(jù)路由到對應(yīng)的數(shù)據(jù)庫上;水平分庫分表,可以降低每張表的數(shù)據(jù)量,這也是現(xiàn)在大部分公司所使用的方法。
上文中說到,水平拆分常用的手段是對主鍵進(jìn)行Hash和取模操作后,按照結(jié)果把數(shù)據(jù)路由到對應(yīng)的數(shù)據(jù)庫上;但如果被拆分的子表,數(shù)據(jù)量也達(dá)到極限值以后,就要面對數(shù)據(jù)庫擴(kuò)容的問題,比如開始規(guī)劃分成8個庫,現(xiàn)在要擴(kuò)到16個庫;
路由規(guī)則發(fā)生變化:hash(id)%8 變成了 hash(id)%16,那么歷史數(shù)據(jù)也就要面臨遷移的問題;這種情況,要么做數(shù)據(jù)遷移,要么增加分表算法的復(fù)雜性,讓算法可以兼容增加分表前后的數(shù)據(jù)路由。
在單庫時代,復(fù)雜的關(guān)聯(lián)查詢是很容易實(shí)現(xiàn)的,但是數(shù)據(jù)庫被拆分后,數(shù)據(jù)被保存在了不同的數(shù)據(jù)庫服務(wù)器上,那么夸庫的join就成了很大的問題。通常解決方案有:
如果是垂直拆分,那么可以考慮做一定程度的字段冗余,避免跨表關(guān)聯(lián);或者可以做數(shù)據(jù)同步,把需要的表同步到同一個庫中,進(jìn)行表關(guān)聯(lián);
代碼層面組裝,也就是把兩邊的數(shù)據(jù)都拿出來,然后在代碼里面關(guān)聯(lián)組裝;或者先獲取主表數(shù)據(jù),再把其余字段補(bǔ)齊;但是從實(shí)際情況來看,這個方案在大多數(shù)場景下,實(shí)現(xiàn)起來都比較困難;
現(xiàn)在一個比較主流的做法,是引入ES或ES+HBase或solr+HBase,把部分字段的全量數(shù)據(jù)保存在同一個地方。
在水平拆分的場景下,一單一張表被拆分成多張表部署在多個數(shù)據(jù)庫中,那么就不能使用數(shù)據(jù)庫自身的主鍵生成機(jī)制了;這時候就需要由我們自己來考慮主鍵生成策略:
主鍵生成中心:可以利用數(shù)據(jù)庫、Redis、MongoDB、zookeeper等組件實(shí)現(xiàn),需要生產(chǎn)主鍵的時候,調(diào)用主鍵生成中心的接口;缺點(diǎn)也很明顯,增加了網(wǎng)絡(luò)開銷,并且主鍵生成中心如果發(fā)生問題,后果會很嚴(yán)重。
UUID:本地生成,不需要第三方組件,生成比較簡單,性能好;不過缺點(diǎn)也不少,長度長,不利于存儲,并且沒有排序,是個字符串,不利于查詢。
一些唯一性ID的生成算法:比如Snowflake、UidGenerator、Leaf等等。
單庫的時候,解決事務(wù)問題很簡單,但是現(xiàn)在要保證跨庫的事務(wù)問題,需要額外的成本;
這種場景下(性能要求高,一致性要求不是那么的高),大部分公司會放棄事務(wù)的【實(shí)時】一致性,只要在一定的時間內(nèi),事務(wù)【最終】一致即可。
1.優(yōu)化SQL加索引
2.業(yè)務(wù)是否可以垂直拆分,業(yè)務(wù)拆分了可以分庫
3.業(yè)務(wù)單邊數(shù)據(jù)量還是大,是否可以把一些字段獨(dú)立出去,表垂直拆分。水平拆分表可以按時間,或者id的has值進(jìn)行拆分
4.分庫分表必然帶來很多問題,比如關(guān)聯(lián)查詢,聚合等操作,可以嘗試下NewSQL,業(yè)務(wù)不再關(guān)心分庫分表操作了。國內(nèi)開源實(shí)現(xiàn)有TiDB,可以了解下,NewSQL應(yīng)該是未來的趨勢。
可以關(guān)注我,后面分享一些存儲方面的文章。
不到萬不得已,不要分庫分表。
數(shù)據(jù)庫遇到瓶頸,應(yīng)該首先考慮優(yōu)化。sql服務(wù)器硬件優(yōu)化,sql語句優(yōu)化,索引優(yōu)化,讀寫分離,緩存層。
如果都不行,那就只能考慮分庫分表了,可以利用mycat,DBProxy等中間件。
一旦分庫分表,就會引出分布式事物,應(yīng)該盡量避免。關(guān)聯(lián)查詢,聚合統(tǒng)計(jì)等操作等地方也有坑,一定要注意!
個人建議:一般到了分庫分表的地步,都是因?yàn)閿?shù)據(jù)量到了一定級別,單臺服務(wù)器無法承受。一般都是某幾張表或者某個庫數(shù)據(jù)量過大。與其費(fèi)力分庫分表,倒不如考慮一些新興的數(shù)據(jù)庫,例如HBase或者TiDB等newSQL甚至ES。如果這些大表,不涉及復(fù)雜,需要考慮事物的業(yè)務(wù),完全可以頂上。
回答完畢,謝謝,希望對你有所幫助!!
本人專注互聯(lián)網(wǎng)前沿動態(tài),大數(shù)據(jù),數(shù)據(jù)采集,數(shù)據(jù)處理,數(shù)據(jù)治理,望交流!
0
回答0
回答1
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答