水平拆分

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了水平拆分相关的知识,希望对你有一定的参考价值。

参考技术A 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 taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create 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 taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create 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

1 zs 18 sh1
id addr aid
1001 bj 1
1002 sh 2

2 ls 19 sh2
id addr aid
1001 bj 1
1002 sh 2

t
id addr aid
1001 bj 1
1002 sh 2

使用场景:
如果你的业务中有些数据类似于数据字典,比如配置文件的配置,
常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大,
而且大部分的业务场景都会用到,那么这种表适合于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 taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create 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 1 sh1
1002 sh 2

1003 tj 3 sh2
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 taobao;create table a (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create 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"

网站平台架构演变史 - 水平拆分的查询

之前在讲表拆分的时候氛围垂直拆分和水平拆分

垂直拆分的查询其实不难,就是从单表变为了多表,而大部分情况下只是对主表的查询多,从表的查询会很少用到,这样的情况下关联查询不需要太多的考虑

水平拆分之前讲了大数据量的情况下根据历史时间来查询,那么今天来说另外一种,还有一只是根据主键id取模后根据这样的规则把数据均匀分布到不同的数据库表中,一般可以以2、5、10来做,那么分页的时候怎么做,用户在查询的时候是不知道你后台怎么查的,他只关心数据的显示,比如我分页显示10条,那么在后台进去查询的时候需要将"10/数据库数量=实际对应每页查询数",比如就用5好了,所有数据都是平均分布到5个不同的数据库中,那么10/5=2,分页的时候需要对这5个数据库查询,那么就是 ‘ limt row, 2 ‘,最后合并5次查询的数据来反馈给前端显示。

这是实时的做法,如果不实时,采用缓存或者搜索引擎的时候,可以分别查询一定的数据量来展示。举个栗子,哪怕分页有100多页,一般用户只看前10也,或者20页的数据,那就用20页,每页显示20条数据,20X20/5=80,那么分别同步5个库的80条数据,放入缓存或者搜索引擎中,来展示给用户,这样用户在做查询的时候就非常快,极少数情况下载20页后的数据再去数据库中查。

也许有人会问条件查询、以及排序,如果直接查询数据库的话呢么进行排序会比较难做,甚至不好做,而是用搜索引擎就能很好的解决这个问题。

其实还有一点没讲,会再写1-2篇来结束这次的架构内邀会的总结。近期实在很忙,手上两个产品都要做,抽空总结,公众号更新频率下降了十分抱歉;其中一个产品预期7月底上线,期待与大家见面!

以上是关于水平拆分的主要内容,如果未能解决你的问题,请参考以下文章

关于数据库表的水平拆分和垂直拆分

在 Vim 中快速从垂直拆分切换到水平拆分

MySQL水平无限拓展

数据库表的水平拆分和垂直拆分

Emacs 快捷方式一键从水平拆分切换到垂直拆分?

数据库优化-水平拆分 垂直拆分