MySQL分库分表实战

为什么要分库分表

在大型网站中,当用户量以及用户产生的业务数据量达到单库单表性能极限时,为了支撑业务可持续发展,对于重要的核心业务必然要进行分库分表来存储业务数据。

对于非核心业务产生的大量数据,例如爬虫爬取的信息,论坛产生的数据等,可以考虑把数据保存在像MongoDB这样的NoSQL存储里面,这些存储会自动分片存储业务数据,不需要业务逻辑进行干预。

分库分表的缺点

分库分表之后实际会产生一系列问题,对于每种问题我们需要针对性进行解决,保障系统稳定运行。

下面就分库分表会产生的问题进行列举:

  1. 数据的获取需要通过改写路由去多个分片获取数据,然后进行聚合。对于某些SQL需要全库表路由来获取数据,有的SQL甚至需要把SQL语句改写成笛卡尔积去获取分片数据,这中间会产生大量数据库连接造成数据库资源浪费。
  2. 分库分表之后需要分布式事务来保证数据一致性。对于不同业务可以采用不同的分布式事务实现方式来对数据一致性提供不同的保障级别,这其实是一种业务的权衡。
  3. 对于分页数据的获取,最好是采用异构数据到ElasticSearch或者其他分布式存储中,既能提供高性能的检索,也能避免由于分库分表导致分页数据获取困难的问题。当然是用汇总表对业务数据汇总,提供一个兜底方案也是很有必要的。

什么是分库分表

分库分表就是把用户数据进行拆分,存储到不同的数据库的不同数据表中。

分库分表主要是用来承载用户的写负载,用户数据在单库单表存储量太大,会导致用户读取阻塞,进而导致用户无法写入。

对于读负载可以通过读写分离,异构到ElasticSearch等方案进行很好的解决。

对于写负载只能通过分库分表的方案进行解决。

怎么进行分库分表

分库分库的第一个要点是如何拆分数据。

大体有以下几种拆分方案,每种方案都有优点也有缺点:

  1. 按时间段进行拆分
  2. 取模法
  3. 查表法

一般业务中使用的都是取模法,因为通过取模法,业务数据可以均匀分布在数据库中,用户请求也可以均匀的请求不同的数据库,可以避免热点表,但是对于不同用户的数据的交互或者联合查询就需要进行多次查询。

当然在某些业务场景下使用其他拆分方案可能会更好,例如历史日志,可以采用日志数据按照时间拆分,进行归档的方式来进行分库分表。

分库分表的第二个要点就是拆分之后SQL如何路由,如何执行。

对于这一点一般采用现有的框架来进行实现,如MyCAT,Sharding-Jdbc等,他们基于不同的模式为我们封装好了拆分之后SQL路由和执行的细节。

其中MyCAT是使用代理服务器的方式实现,Sharding-Jdbc是使用嵌入应用系统中直接调用数据库的方式实现的。

实践中可以根据不同项目组的情况使用不同的方案。

分库分表实践

下面介绍通过Sharding-Jdbc来实现分库分表。通过Sharding-Jdbc可以很方便地实现数据库的拆分,SQL自动改写,路由,请求结果归并等具体的数据处理细节。

下面介绍一个简单的分库分表的实现流程,更多实现细节和使用方案可以参考官方文档

  1. 引入Jar包

<dependency>

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

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

<version>4.1.1</version>

</dependency>

  1. 配置数据源

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

*// 配置第 1 个数据源*

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 个数据源*

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 表规则*

TableRuleConfiguration orderTableRuleConfig =

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

*// 配置分库策略*

orderTableRuleConfig.setDatabaseShardingStrategyConfig(

new StandardShardingStrategyConfiguration("user_id", databaseShardingAlgorithm));

*// 配置分表策略*

orderTableRuleConfig.setTableShardingStrategyConfig(

new StandardShardingStrategyConfiguration("user_id", tableShardingAlgorithm));

*// 配置业务主键ID生成方案*

orderTableRuleConfig.setKeyGeneratorConfig(

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

*// 配置分片规则*

ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();

shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);

*// 设置属性*

Properties properties = new Properties();

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

*// 创建 ShardingSphereDataSource*

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

  1. 基于业务进行不同的定制

对于不同业务的查询,有时需要使用Hint的方式进行分库分表。

最佳实践和好的资料

  1. MySQL存储海量数据的最后一招:分库分表

文章中说明什么情况下分库,什么情况下分表。

数据量大,就分表;并发高,就分库。

还详细比较了三种数据库拆分方案的细节。

  1. Hit分片方式的使用,有几篇文章写很不错
  1. 数据库优化方案(二):写入数据量增加时,如何实现分库分表?
  • 在这篇文章有使用查表法对于非分片key查询数据的支持,很值得借鉴。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容