MySQL分庫分表實戰(zhàn)

為什么要分庫分表

在大型網(wǎng)站中,當(dāng)用戶量以及用戶產(chǎn)生的業(yè)務(wù)數(shù)據(jù)量達(dá)到單庫單表性能極限時,為了支撐業(yè)務(wù)可持續(xù)發(fā)展,對于重要的核心業(yè)務(wù)必然要進(jìn)行分庫分表來存儲業(yè)務(wù)數(shù)據(jù)。

對于非核心業(yè)務(wù)產(chǎn)生的大量數(shù)據(jù),例如爬蟲爬取的信息,論壇產(chǎn)生的數(shù)據(jù)等,可以考慮把數(shù)據(jù)保存在像MongoDB這樣的NoSQL存儲里面,這些存儲會自動分片存儲業(yè)務(wù)數(shù)據(jù),不需要業(yè)務(wù)邏輯進(jìn)行干預(yù)。

分庫分表的缺點

分庫分表之后實際會產(chǎn)生一系列問題,對于每種問題我們需要針對性進(jìn)行解決,保障系統(tǒng)穩(wěn)定運行。

下面就分庫分表會產(chǎn)生的問題進(jìn)行列舉:

  1. 數(shù)據(jù)的獲取需要通過改寫路由去多個分片獲取數(shù)據(jù),然后進(jìn)行聚合。對于某些SQL需要全庫表路由來獲取數(shù)據(jù),有的SQL甚至需要把SQL語句改寫成笛卡爾積去獲取分片數(shù)據(jù),這中間會產(chǎn)生大量數(shù)據(jù)庫連接造成數(shù)據(jù)庫資源浪費。
  2. 分庫分表之后需要分布式事務(wù)來保證數(shù)據(jù)一致性。對于不同業(yè)務(wù)可以采用不同的分布式事務(wù)實現(xiàn)方式來對數(shù)據(jù)一致性提供不同的保障級別,這其實是一種業(yè)務(wù)的權(quán)衡。
  3. 對于分頁數(shù)據(jù)的獲取,最好是采用異構(gòu)數(shù)據(jù)到ElasticSearch或者其他分布式存儲中,既能提供高性能的檢索,也能避免由于分庫分表導(dǎo)致分頁數(shù)據(jù)獲取困難的問題。當(dāng)然是用匯總表對業(yè)務(wù)數(shù)據(jù)匯總,提供一個兜底方案也是很有必要的。

什么是分庫分表

分庫分表就是把用戶數(shù)據(jù)進(jìn)行拆分,存儲到不同的數(shù)據(jù)庫的不同數(shù)據(jù)表中。

分庫分表主要是用來承載用戶的寫負(fù)載,用戶數(shù)據(jù)在單庫單表存儲量太大,會導(dǎo)致用戶讀取阻塞,進(jìn)而導(dǎo)致用戶無法寫入。

對于讀負(fù)載可以通過讀寫分離,異構(gòu)到ElasticSearch等方案進(jìn)行很好的解決。

對于寫負(fù)載只能通過分庫分表的方案進(jìn)行解決。

怎么進(jìn)行分庫分表

分庫分庫的第一個要點是如何拆分?jǐn)?shù)據(jù)。

大體有以下幾種拆分方案,每種方案都有優(yōu)點也有缺點:

  1. 按時間段進(jìn)行拆分
  2. 取模法
  3. 查表法

一般業(yè)務(wù)中使用的都是取模法,因為通過取模法,業(yè)務(wù)數(shù)據(jù)可以均勻分布在數(shù)據(jù)庫中,用戶請求也可以均勻的請求不同的數(shù)據(jù)庫,可以避免熱點表,但是對于不同用戶的數(shù)據(jù)的交互或者聯(lián)合查詢就需要進(jìn)行多次查詢。

當(dāng)然在某些業(yè)務(wù)場景下使用其他拆分方案可能會更好,例如歷史日志,可以采用日志數(shù)據(jù)按照時間拆分,進(jìn)行歸檔的方式來進(jìn)行分庫分表。

分庫分表的第二個要點就是拆分之后SQL如何路由,如何執(zhí)行。

對于這一點一般采用現(xiàn)有的框架來進(jìn)行實現(xiàn),如MyCAT,Sharding-Jdbc等,他們基于不同的模式為我們封裝好了拆分之后SQL路由和執(zhí)行的細(xì)節(jié)。

其中MyCAT是使用代理服務(wù)器的方式實現(xiàn),Sharding-Jdbc是使用嵌入應(yīng)用系統(tǒng)中直接調(diào)用數(shù)據(jù)庫的方式實現(xiàn)的。

實踐中可以根據(jù)不同項目組的情況使用不同的方案。

分庫分表實踐

下面介紹通過Sharding-Jdbc來實現(xiàn)分庫分表。通過Sharding-Jdbc可以很方便地實現(xiàn)數(shù)據(jù)庫的拆分,SQL自動改寫,路由,請求結(jié)果歸并等具體的數(shù)據(jù)處理細(xì)節(jié)。

下面介紹一個簡單的分庫分表的實現(xiàn)流程,更多實現(xiàn)細(xì)節(jié)和使用方案可以參考官方文檔。

  1. 引入Jar包

<dependency>

<groupId>org.apache.shardingsphere</groupId>

<artifactId>sharding-jdbc-core</artifactId>

<version>4.1.1</version>

</dependency>

  1. 配置數(shù)據(jù)源

Map<String, DataSource> dataSourceMap = new HashMap<>();

*// 配置第 1 個數(shù)據(jù)源*

DruidDataSource dataSource1 = new DruidDataSource();

dataSource1.setDriverClassName("com.mysql.cj.jdbc.Driver");

dataSource1.setUrl("jdbc:mysql://localhost:3306/continuous?useUnicode=true&characterEncoding=utf-8&useSSL=false");

dataSource1.setUsername("root");

dataSource1.setPassword("12345678");

dataSourceMap.put("ds0", dataSource1);

*// 配置第 2 個數(shù)據(jù)源*

DruidDataSource dataSource2 = new DruidDataSource();

dataSource2.setDriverClassName("com.mysql.cj.jdbc.Driver");

dataSource2.setUrl("jdbc:mysql://localhost:3306/continuous2?useUnicode=true&characterEncoding=utf-8&useSSL=false");

dataSource2.setUsername("root");

dataSource2.setPassword("12345678");

dataSourceMap.put("ds1", dataSource2);

  1. 配置分庫分表的方案

*// 配置 t_order 表規(guī)則*

TableRuleConfiguration orderTableRuleConfig =

new TableRuleConfiguration("t_order", "ds0.order0, ds1.order1");

*// 配置分庫策略*

orderTableRuleConfig.setDatabaseShardingStrategyConfig(

new StandardShardingStrategyConfiguration("user_id", databaseShardingAlgorithm));

*// 配置分表策略*

orderTableRuleConfig.setTableShardingStrategyConfig(

new StandardShardingStrategyConfiguration("user_id", tableShardingAlgorithm));

*// 配置業(yè)務(wù)主鍵ID生成方案*

orderTableRuleConfig.setKeyGeneratorConfig(

new KeyGeneratorConfiguration("SNOWFLAKE", "user_id"));

*// 配置分片規(guī)則*

ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();

shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);

*// 設(shè)置屬性*

Properties properties = new Properties();

properties.put("sql.show", true);

*// 創(chuàng)建 ShardingSphereDataSource*

return ShardingDataSourceFactory.*createDataSource*(dataSourceMap, shardingRuleConfig, properties);

  1. 基于業(yè)務(wù)進(jìn)行不同的定制

對于不同業(yè)務(wù)的查詢,有時需要使用Hint的方式進(jìn)行分庫分表。

最佳實踐和好的資料

  1. MySQL存儲海量數(shù)據(jù)的最后一招:分庫分表

文章中說明什么情況下分庫,什么情況下分表。

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

還詳細(xì)比較了三種數(shù)據(jù)庫拆分方案的細(xì)節(jié)。

  1. Hit分片方式的使用,有幾篇文章寫很不錯
  1. 數(shù)據(jù)庫優(yōu)化方案(二):寫入數(shù)據(jù)量增加時,如何實現(xiàn)分庫分表?
  • 在這篇文章有使用查表法對于非分片key查詢數(shù)據(jù)的支持,很值得借鑒。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容