欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mysql分庫(kù)分表實(shí)現(xiàn)方式

 更新時(shí)間:2025年02月10日 16:44:45   作者:暴躁的魚  
這篇文章詳細(xì)介紹了分庫(kù)分表的概念,原因,如何實(shí)現(xiàn),以及不同中間件的優(yōu)缺點(diǎn),同時(shí),也介紹了如何進(jìn)行數(shù)據(jù)遷移和擴(kuò)容縮容,以及如何處理分庫(kù)分表后的ID和事務(wù)問題

1、背景

Mysql作為做流行的開源數(shù)據(jù)庫(kù),在各大互聯(lián)網(wǎng)公司被廣泛使用。通常我們用一個(gè)庫(kù)就可以滿足需求,但是隨著業(yè)務(wù)的增長(zhǎng),數(shù)據(jù)量和并發(fā)量迅速膨脹。

Mysql單表數(shù)據(jù)量到百萬以上的時(shí)候,查詢效率就會(huì)受到影響,另外Mysql單庫(kù)能承受的并發(fā)也有限。

這個(gè)時(shí)候我們需要做分庫(kù)分表,來提高數(shù)據(jù)庫(kù)的性能和擴(kuò)展性

2、為什么分庫(kù)分表

2.1 分表

單表數(shù)據(jù)量太大會(huì)極大的影響sql執(zhí)行效率,一般來說單表達(dá)到幾百萬的時(shí)候,性能就相對(duì)較差了,就需要分表了

2.2 分庫(kù)

單個(gè)庫(kù)一般最大支持到2000并發(fā),超過就需要分庫(kù)了,一個(gè)健康的單庫(kù)并發(fā)值最好控制在1000左右

#分庫(kù)分表前分庫(kù)分表后
并發(fā)支撐情況MySQL 單機(jī)部署,扛不住高并發(fā)MySQL 從單機(jī)到多機(jī),能承受的并發(fā)增加了多倍
磁盤使用情況MySQL 單機(jī)磁盤容量幾乎撐滿拆分為多個(gè)庫(kù),數(shù)據(jù)庫(kù)服務(wù)器磁盤使用率大大降低
SQL 執(zhí)行性能單表數(shù)據(jù)量太大,SQL 越跑越慢單表數(shù)據(jù)量減少,SQL 執(zhí)行效率明顯提升

數(shù)據(jù)量大,就分表;并發(fā)高,就分庫(kù)。

2.3 帶來的問題

  • join 操作 : 同一個(gè)數(shù)據(jù)庫(kù)中的表分布在了不同的數(shù)據(jù)庫(kù)中,導(dǎo)致無法使用 join 操作。這樣就導(dǎo)致我們需要手動(dòng)進(jìn)行數(shù)據(jù)的封裝,比如你在一個(gè)數(shù)據(jù)庫(kù)中查詢到一個(gè)數(shù)據(jù)之后,再根據(jù)這個(gè)數(shù)據(jù)去另外一個(gè)數(shù)據(jù)庫(kù)中找對(duì)應(yīng)的數(shù)據(jù)。
  • 事務(wù)問題 :同一個(gè)數(shù)據(jù)庫(kù)中的表分布在了不同的數(shù)據(jù)庫(kù)中,如果單個(gè)操作涉及到多個(gè)數(shù)據(jù)庫(kù),那么數(shù)據(jù)庫(kù)自帶的事務(wù)就無法滿足我們的要求了。
  • 分布式 id :分庫(kù)之后, 數(shù)據(jù)遍布在不同服務(wù)器上的數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)的自增主鍵已經(jīng)沒辦法滿足生成的主鍵唯一了。我們?nèi)绾螢椴煌臄?shù)據(jù)節(jié)點(diǎn)生成全局唯一主鍵呢?這個(gè)時(shí)候,我們就需要為我們的系統(tǒng)引入分布式 id 了。

3、不同分庫(kù)中間件的優(yōu)缺點(diǎn)

3.1 Sharding-jdbc

1、當(dāng)當(dāng)開源的,client層方案

2、支持分庫(kù)分表,讀寫分離,分布式ID生成,柔性事物(最大努力送達(dá)型事物,TCC事物)

3、社區(qū)比較活躍

  • 優(yōu)點(diǎn): 優(yōu)點(diǎn)在于不用部署,運(yùn)維成本低,不需要代理層的二次轉(zhuǎn)發(fā)請(qǐng)求,性能很高
  • 缺點(diǎn): 各個(gè)系統(tǒng)都需要耦合Sharding-jdbc依賴,如果需要升級(jí),各個(gè)系統(tǒng)需要重新部署

適合中小型公司

3.2 Mycat

1、proxy層方案

2、支持的功能完善

3、很流行,社區(qū)非常活躍

  • 優(yōu)點(diǎn): 對(duì)各個(gè)項(xiàng)目透明,升級(jí)只需要升級(jí)中間件
  • 缺點(diǎn): 需要部署,自己運(yùn)維一套中間件,運(yùn)維成本高

適合大型公司

3.3 如何選擇

推薦使用sharding-jdbc和mycat:

  • 小型公司選用sharding-jdbc,client層方案輕便,而且維護(hù)成本低,不需要額外增派人手,而且中小型公司系統(tǒng)復(fù)雜度會(huì)低一些,項(xiàng)目也沒那么多
  • 中大型公司最好還是選用mycat這類proxy層方案,因?yàn)榭赡艽蠊鞠到y(tǒng)和項(xiàng)目非常多,團(tuán)隊(duì)很大,人員充足,那么最好是專門弄個(gè)人來研究和維護(hù)mycat,然后大量項(xiàng)目直接透明使用即可

4、如何拆分

4.1、水平拆分(用的最多)

把一個(gè)表的數(shù)據(jù)拆分到多個(gè)表中,但是每個(gè)表的結(jié)構(gòu)都一樣,把數(shù)據(jù)均勻的放到不同的表里,用多個(gè)表來抗并發(fā)

根據(jù)特定字段來拆分:

比如訂單表根據(jù)訂單ID來拆分,分到32個(gè)庫(kù),每個(gè)庫(kù)32張表,那么orderID%32決定落在哪個(gè)庫(kù),orderID/32%32決定落在那個(gè)表。

而且這兒還有兩種分庫(kù)分表的方式:

  • 一種是按照 range 來分,就是每個(gè)庫(kù)一段連續(xù)的數(shù)據(jù),這個(gè)一般是按比如時(shí)間范圍來的,但是這種一般較少用,因?yàn)楹苋菀桩a(chǎn)生熱點(diǎn)問題,大量的流量都打在最新的數(shù)據(jù)上了。
  • 是按照某個(gè)字段 hash 一下均勻分散,這個(gè)較為常用。

各自優(yōu)缺點(diǎn):

  • range 來分,好處在于說,擴(kuò)容的時(shí)候很簡(jiǎn)單,因?yàn)槟阒灰A(yù)備好,給每個(gè)月都準(zhǔn)備一個(gè)庫(kù)就可以了,到了一個(gè)新的月份的時(shí)候,自然而然,就會(huì)寫新的庫(kù)了;缺點(diǎn),但是大部分的請(qǐng)求,都是訪問最新的數(shù)據(jù)。實(shí)際生產(chǎn)用 range,要看場(chǎng)景。
  • hash 分發(fā),好處在于說,可以平均分配每個(gè)庫(kù)的數(shù)據(jù)量和請(qǐng)求壓力;壞處在于說擴(kuò)容起來比較麻煩,會(huì)有一個(gè)數(shù)據(jù)遷移的過程,之前的數(shù)據(jù)需要重新計(jì)算 hash 值重新分配到不同的庫(kù)或表。

4.2、垂直拆分

把一個(gè)有很多字段的表拆分到多個(gè)表或者多個(gè)庫(kù)上去,把訪問頻率高的熱點(diǎn)字段和訪問頻率低的非熱點(diǎn)字段分開放到不同的表。因?yàn)閿?shù)據(jù)庫(kù)有緩存,熱點(diǎn)字段越少,緩存里可以存更多的行

5、分庫(kù)分表方案確定后,還需要解決以下問題

  • 如何實(shí)現(xiàn)數(shù)據(jù)從單庫(kù)單表到分庫(kù)分表的遷移?
  • 表和庫(kù)的數(shù)量又遇到瓶頸怎么辦,如何處理?
  • 分庫(kù)分表后的ID如何處理?
  • 分庫(kù)分表后的事務(wù)如何處理?

5.1 如何設(shè)計(jì)才可以讓系統(tǒng)從未分庫(kù)分表平滑的動(dòng)態(tài)切換到分庫(kù)分表上?

停機(jī)遷移

  • 一種方式是直接停機(jī)遷移,需要再深夜沒有流量的時(shí)候進(jìn)行
  • 把數(shù)據(jù)遷移到分庫(kù)分表數(shù)據(jù)庫(kù)上,然后重啟系統(tǒng)就可以,這種方式需要停機(jī),并不是平滑遷移

雙寫遷移方案

這種方案不用停機(jī)。

簡(jiǎn)單來說,就是在線上系統(tǒng)里面,之前所有寫庫(kù)的地方,增刪改操作,除了對(duì)老庫(kù)增刪改,都加上對(duì)新庫(kù)的增刪改,這就是所謂的雙寫,同時(shí)寫倆庫(kù),老庫(kù)和新庫(kù)。

然后系統(tǒng)部署之后,新庫(kù)數(shù)據(jù)差太遠(yuǎn),用之前說的導(dǎo)數(shù)工具,跑起來讀老庫(kù)數(shù)據(jù)寫新庫(kù),寫的時(shí)候要根據(jù) gmt_modified 這類字段判斷這條數(shù)據(jù)最后修改的時(shí)間,除非是讀出來的數(shù)據(jù)在新庫(kù)里沒有,或者是比新庫(kù)的數(shù)據(jù)新才會(huì)寫。簡(jiǎn)單來說,就是不允許用老數(shù)據(jù)覆蓋新數(shù)據(jù)。

導(dǎo)完一輪之后,有可能數(shù)據(jù)還是存在不一致,那么就程序自動(dòng)做一輪校驗(yàn),比對(duì)新老庫(kù)每個(gè)表的每條數(shù)據(jù),接著如果有不一樣的,就針對(duì)那些不一樣的,從老庫(kù)讀數(shù)據(jù)再次寫。反復(fù)循環(huán),直到兩個(gè)庫(kù)每個(gè)表的數(shù)據(jù)都完全一致為止。

接著當(dāng)數(shù)據(jù)完全一致了,就 ok 了,基于僅僅使用分庫(kù)分表的最新代碼,重新部署一次,不就僅僅基于分庫(kù)分表在操作了么,還沒有幾個(gè)小時(shí)的停機(jī)時(shí)間,很穩(wěn)。所以現(xiàn)在基本玩兒數(shù)據(jù)遷移之類的,都是這么干的。

這個(gè)方法的缺點(diǎn)就是代碼里需要同時(shí)支持兩個(gè)庫(kù)的過度階段,稍微麻煩一點(diǎn),但是不需要停機(jī),可以平滑遷移。

5.2 動(dòng)態(tài)擴(kuò)容縮容的分庫(kù)分表方案?

分庫(kù)分表完成后,如果數(shù)據(jù)繼續(xù)增加,原來的方案不能滿足業(yè)務(wù)了,需要繼續(xù)擴(kuò)大更多庫(kù)更多表,那么還要再來一次分庫(kù)分表嗎?

這樣處理會(huì)很麻煩,因?yàn)楹罄m(xù)可能還不夠,分庫(kù)分表數(shù)據(jù)遷移非常費(fèi)勁。那么我們可以采取一次性分足夠多的庫(kù)和表,這樣避免了后續(xù)遷移數(shù)據(jù)的問題。

一開始分庫(kù)一次性分夠,32庫(kù)*32表,一共1024張表,根據(jù)某個(gè) id 先根據(jù) 32 取模路由到庫(kù),再根據(jù) 32 取模路由到庫(kù)里的表。

orderIdid % 32 (庫(kù))id / 32 % 32 (表)
25938
118955
352011
45931715

剛開始的時(shí)候,這個(gè)庫(kù)可能就是邏輯庫(kù),建在一個(gè)數(shù)據(jù)庫(kù)上的,就是一個(gè) MySQL 服務(wù)器可能建了 n 個(gè)庫(kù),比如 32 個(gè)庫(kù)。后面如果要拆分,就是不斷在庫(kù)和 MySQL 服務(wù)器之間做遷移就可以了。然后系統(tǒng)配合改一下配置即可。

比如說最多可以擴(kuò)展到 32 個(gè)數(shù)據(jù)庫(kù)服務(wù)器,每個(gè)數(shù)據(jù)庫(kù)服務(wù)器是一個(gè)庫(kù)。如果還是不夠?最多可以擴(kuò)展到 1024 個(gè)數(shù)據(jù)庫(kù)服務(wù)器,每個(gè)數(shù)據(jù)庫(kù)服務(wù)器上面一個(gè)庫(kù)一個(gè)表。因?yàn)樽疃嗍?1024 個(gè)表。

這么搞,是不用自己寫代碼做數(shù)據(jù)遷移的,都交給 DBA 來搞好了,但是 DBA 確實(shí)是需要做一些庫(kù)表遷移的工作,但是總比你自己寫代碼,然后抽數(shù)據(jù)導(dǎo)數(shù)據(jù)來的效率高得多吧。

這里對(duì)步驟做一個(gè)總結(jié):

  1. 設(shè)定好幾臺(tái)數(shù)據(jù)庫(kù)服務(wù)器,每臺(tái)服務(wù)器上幾個(gè)庫(kù),每個(gè)庫(kù)多少個(gè)表,推薦是 32 庫(kù) * 32 表,對(duì)于大部分公司來說,可能幾年都?jí)蛄恕?/li>
  2. 路由的規(guī)則,orderId 模 32 = 庫(kù),orderId / 32 模 32 = 表
  3. 擴(kuò)容的時(shí)候,申請(qǐng)?jiān)黾痈嗟臄?shù)據(jù)庫(kù)服務(wù)器,裝好 MySQL,呈倍數(shù)擴(kuò)容,4 臺(tái)服務(wù)器,擴(kuò)到 8 臺(tái)服務(wù)器,再到 16 臺(tái)服務(wù)器。
  4. 由 DBA 負(fù)責(zé)將原先數(shù)據(jù)庫(kù)服務(wù)器的庫(kù),遷移到新的數(shù)據(jù)庫(kù)服務(wù)器上去,庫(kù)遷移是有一些便捷的工具的。
  5. 我們這邊就是修改一下配置,調(diào)整遷移的庫(kù)所在數(shù)據(jù)庫(kù)服務(wù)器的地址。
  6. 重新發(fā)布系統(tǒng),上線,原先的路由規(guī)則變都不用變,直接可以基于 n 倍的數(shù)據(jù)庫(kù)服務(wù)器的資源,繼續(xù)進(jìn)行線上系統(tǒng)的提供服務(wù)。

6、分庫(kù)分表之后,id 主鍵如何處理?

6.1、設(shè)置數(shù)據(jù)庫(kù) sequence 或者表自增字段步長(zhǎng)

適合的場(chǎng)景:

  • 在用戶防止產(chǎn)生的 ID 重復(fù)時(shí),這種方案實(shí)現(xiàn)起來比較簡(jiǎn)單,也能達(dá)到性能目標(biāo)。
  • 但是服務(wù)節(jié)點(diǎn)固定,步長(zhǎng)也固定,將來如果還要增加服務(wù)節(jié)點(diǎn),就不好搞了。

6.2、UUID

不具有有序性,作為ID對(duì)索引不友好,會(huì)導(dǎo)致 B+ 樹索引在寫的時(shí)候有過多的隨機(jī)寫操作(連續(xù)的 ID 可以產(chǎn)生部分順序?qū)懀?,不適合做主鍵。

適合的場(chǎng)景:

  • 如果你是要隨機(jī)生成個(gè)什么文件名、編號(hào)之類的
  • 你可以用 UUID,但是作為主鍵是不能用 UUID 的

6.3、獲取當(dāng)前系統(tǒng)時(shí)間, 并發(fā)高的時(shí)候可能會(huì)重復(fù)

適合的場(chǎng)景:

  • 一般如果用這個(gè)方案,是將當(dāng)前時(shí)間跟很多其他的業(yè)務(wù)字段拼接起來,作為一個(gè) id,如果業(yè)務(wù)上你覺得可以接受,那么也是可以的。
  • 你可以將別的業(yè)務(wù)字段值跟當(dāng)前時(shí)間拼接起來,組成一個(gè)全局唯一的編號(hào)

6.4、snowflake 算法

  • snowflake 算法是 twitter 開源的分布式 id 生成算法,采用 Scala 語言實(shí)現(xiàn),
  • 是把一個(gè) 64 位的 long 型的 id,1 個(gè) bit 是不用的,用其中的 41 bits 作為毫秒數(shù),用 10 bits 作為工作機(jī)器 id,12 bits 作為序列號(hào)。

7、分庫(kù)分表后,事務(wù)如何處理?

分庫(kù)分表以后,可能會(huì)出現(xiàn)跨庫(kù)事務(wù),這種事務(wù)怎么處理呢?

7.1 優(yōu)化方案避免出現(xiàn)跨庫(kù)事務(wù)

  • 首先我們做分庫(kù)分表的時(shí)候,盡量避免出現(xiàn)跨庫(kù)的事務(wù)的場(chǎng)景,
  • 比如訂單表,分庫(kù)的時(shí)候根據(jù)訂單ID開拆分,那么跟訂單相關(guān)的其他表也按訂單ID來拆分,這樣針對(duì)一個(gè)訂單的事務(wù)就可以控制在一個(gè)庫(kù)中,避免了跨庫(kù)事務(wù)。

7.2 跨庫(kù)事務(wù)的處理

  • 如果無法避免,分庫(kù)分表一般是單系統(tǒng)對(duì)應(yīng)多個(gè)庫(kù),那么數(shù)據(jù)庫(kù)的XA事務(wù)正好可以處理這種場(chǎng)景,
  • sharding-jdbc可以支持?jǐn)?shù)據(jù)庫(kù)的XA事務(wù),通過@DSTransactional注解就可以實(shí)現(xiàn)跨庫(kù)事務(wù)。

Mycat也能支持XA事務(wù)。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論