浅谈mysql数据库分库分表那些事-亿级数据存储方案

浅谈mysql数据库分库分表那些事-亿级数据存储方案,第1张

mysql分库分表一般有如下场景

其中1,2相对较容易实现,本文重点讲讲水平拆表和水平拆库,以及基于mybatis插件方式实现水平拆分方案落地。

在 《聊一聊扩展字段设计》 一文中有讲解到基于KV水平存储扩展字段方案,这就是非常典型的可以水平分表的场景。主表和kv表是一对N关系,随着主表数据量增长,KV表最大N倍线性增长。

这里我们以分KV表水平拆分为场景

对于kv扩展字段查询,只会根据id + key 或者 id 为条件的方式查询,所以这里我们可以按照id 分片即可

分512张表(实际场景具体分多少表还得根据字段增加的频次而定)

分表后表名为kv_000 ~ kv_511

id % 512 = 1 .... 分到 kv_001,

id % 512 = 2 .... 分到 kv_002

依次类推!

水平分表相对比较容易,后面会讲到基于mybatis插件实现方案

场景:以下我们基于博客文章表分库场景来分析

目标:

表结构如下(节选部分字段):

按照user_id sharding

假如分1024个库,按照user_id % 1024 hash

user_id % 1024 = 1 分到db_001库

user_id % 1024 = 2 分到db_002库

依次类推

目前是2个节点,假如后期达到瓶颈,我们可以增加至4个节点

最多可以增加只1024个节点,性能线性增长

对于水平分表/分库后,非shardingKey查询首先得考虑到

基于mybatis分库分表,一般常用的一种是基于spring AOP方式, 另外一种基于mybatis插件。其实两种方式思路差不多。

为了比较直观解决这个问题,我分别在Executor 和StatementHandler阶段2个拦截器

实现动态数据源获取接口

测试结果如下

由此可知,我们需要在Executor阶段 切换数据源

对于分库:

原始sql:

目标sql:

其中定义了三个注解

@useMaster 是否强制读主

@shardingBy 分片标识

@DB 定义逻辑表名 库名以及分片策略

1)编写entity

Insert

select

以上顺利实现mysql分库,同样的道理实现同时分库分表也很容易实现。

此插件具体实现方案已开源: https://github.com/bytearch/mybatis-sharding

目录如下:

mysql分库分表,首先得找到瓶颈在哪里(IO or CPU),是分库还是分表,分多少?不能为了分库分表而拆分。

原则上是尽量先垂直拆分 后 水平拆分。

以上基于mybatis插件分库分表是一种实现思路,还有很多不完善的地方,

例如:

7.1 范围分片(range)

比如说t3表

(1)行数非常多,2000w(1-1000w:sh1 1000w01-2000w:sh2)

(2)访问非常频繁,用户顺序访问较多

cp schema.xml schema.xml.1

vim schema.xml

添加:

<table name="t3" dataNode="sh1,sh2" rule="auto-sharding-long" />

vim rule.xml

<tableRule name="auto-sharding-long">

<rule>

<columns>id</columns>

<algorithm>rang-long</algorithm>

</rule>

<function name="rang-long"

class="io.mycat.route.function.AutoPartitionByLong">

<property name="mapFile">autopartition-long.txt</property>

</function>

vim autopartition-long.txt

0-10=0

10-20=1

[root@db01 conf]# mysql -S /data/3308/mysql.sock -e "select * from taobao.t3"

[root@db01 conf]# mysql -S /data/3307/mysql.sock -e "select * from taobao.t3"

7.2 取模分片

1%3 1

2%3 2

3%3 0

4%3 1

5%3 2

任何正整数数字和N(正整数)取模,得的值永远都是 0~N-1

id % 分片数量取模

N % 5 = 0-4 idx

取余分片方式:分片键(一个列)与节点数量进行取余,得到余数,将数据写入对应节点

vim schema.xml

<table name="t4" dataNode="sh1,sh2" rule="mod-long" />

vim rule.xml

<property name="count">2</property>

创建测试表:

mysql -S /data/3307/mysql.sock -e "use taobaocreate table t4 (id int not null primary key auto_increment,name varchar(20) not null)"

mysql -S /data/3308/mysql.sock -e "use taobaocreate table t4 (id int not null primary key auto_increment,name varchar(20) not null)"

重启mycat

mycat restart

[root@db01 ~]# mysql -uroot -p123456 -h 10.0.0.52 -P8066 --default-auth=mysql_native_password

use TESTDB

insert into t4(id,name) values(1,'a')

insert into t4(id,name) values(2,'b')

insert into t4(id,name) values(3,'c')

insert into t4(id,name) values(4,'d')

insert into t4(id,name) values(6,'x'),(8,'y'),(10,'z')

分别登录后端节点查询数据

mysql -S /data/3308/mysql.sock -e "select * from taobao.t4"

mysql -S /data/3307/mysql.sock -e "select * from taobao.t4"

7.3 枚举分片 (区域、zone)

t5 表

id name telnum

1 bj 1212

2 sh 22222

3 bj 3333

4 sh 44444

5 bj 5555

sharding-by-intfile

vim schema.xml

<table name="t5" dataNode="sh1,sh2" rule="sharding-by-intfile" />

vim rule.xml

<function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap">

<property name="mapFile">partition-hash-int.txt</property>

<property name="type">1</property>

</function>

vim partition-hash-int.txt 配置:

bj=0

sh=1

DEFAULT_NODE=1

mysql -S /data/3307/mysql.sock -e "use taobaocreate table t5 (id int not null primary key auto_increment,name varchar(20) not null)"

mysql -S /data/3308/mysql.sock -e "use taobaocreate table t5 (id int not null primary key auto_increment,name varchar(20) not null)"

重启mycat

mycat restart

mysql -uroot -p123456 -h10.0.0.52 -P8066 --default-auth=mysql_native_password

use TESTDB

insert into t5(id,name) values(1,'bj')

insert into t5(id,name) values(2,'sh')

insert into t5(id,name) values(3,'bj')

insert into t5(id,name) values(4,'sh')

insert into t5(id,name) values(5,'tj')

mysql -S /data/3308/mysql.sock -e "select * from taobao.t5"

mysql -S /data/3307/mysql.sock -e "select * from taobao.t5"

7.4 Mycat全局表

a b c d .....

join

t

a

id name age

1zs 18 sh1

idaddr aid

1001 bj1

1002 sh2

2ls 19 sh2

idaddr aid

1001 bj1

1002 sh2

t

idaddr aid

1001 bj1

1002 sh2

使用场景:

如果你的业务中有些数据类似于数据字典,比如配置文件的配置,

常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大,

而且大部分的业务场景都会用到,那么这种表适合于Mycat全局表,无须对数据进行切分,

要在所有的分片上保存一份数据即可,Mycat 在Join *** 作中,业务表与全局表进行Join聚合会优先选择相同分片内的全局表join,

避免跨库Join,在进行数据插入 *** 作时,mycat将把数据分发到全局表对应的所有分片执行,在进行数据读取时候将会随机获取一个节点读取数据。

vim schema.xml

<table name="t_area" primaryKey="id" type="global" dataNode="sh1,sh2" />

mysql -S /data/3307/mysql.sock -e "use taobaocreate table t_area (id int not null primary key auto_increment,name varchar(20) not null)"

mysql -S /data/3308/mysql.sock -e "use taobaocreate table t_area (id int not null primary key auto_increment,name varchar(20) not null)"

重启mycat

mycat restart

mysql -uroot -p123456 -h10.0.0.52 -P8066 --default-auth=mysql_native_password

mysql -S /data/3308/mysql.sock -e "select * from taobao.t_area"

mysql -S /data/3307/mysql.sock -e "select * from taobao.t_area"

7.5 E-R分片

a

join

b

on a.xx =b.yy

a

id name

1 a sh1

3 c

2 b sh2

4 d

b

id addr aid

1001 bj 1sh1

1002 sh 2

1003 tj 3sh2

1004 wh 4

为了防止跨分片join,可以使用E-R模式

<table name="a" dataNode="sh1,sh2" rule="mod-long">

<childTable name="b" joinKey="aid" parentKey="id" />

</table>

select * from a join b on a.id = b.aid

例子:

mysql -S /data/3308/mysql.sock -e "use taobaocreate table a (id int not null primary key auto_increment,name varchar(20) not null)"

mysql -S /data/3308/mysql.sock -e "use taobaocreate table b (id int not null primary key auto_increment,addr varchar(20) not null ,aid int )"

insert into b(id,addr,aid) values(1001,'bj',1)

insert into b(id,addr,aid) values(1002,'sj',3)

insert into b(id,addr,aid) values(1003,'sd',4)

insert into b(id,addr,aid) values(1004,'we',2)

insert into b(id,addr,aid) values(1005,'er',5)

========

后端数据节点数据分布:

mysql -S /data/3307/mysql.sock -e "select * from taobao.a"

mysql -S /data/3307/mysql.sock -e "select * from taobao.b"

mysql -S /data/3308/mysql.sock -e "select * from taobao.a"

mysql -S /data/3308/mysql.sock -e "select * from taobao.b"


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/6806705.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-28
下一篇2023-03-28

发表评论

登录后才能评论

评论列表(0条)

    保存