vlambda博客
学习文章列表

分布式数据库MyCat综合实战


分布式数据库MyCat综合实战

一、分布式数据库基本概述

分布式数据库已经流行好多年,产品非常众多,其中分布式数据库中间件使用场景最广。

MyCat在MySQL数据库前面部署了一个中间件。这个中间件接管并响应应用的SQL请求。所以它的基础必备能力就是解析SQL,做分库分表路由,到底层MySQL数据库里取数据并可能做一些计算(排序聚合等)然后返回给应用。这个中间件对应用屏蔽了表被拆分的细节。

Server层:由一组DRDS Server(后简称Server)组成,Server节点是部署在ECS上的一个Java进程,ECS的资源规格(CPU和内存)就是Server节点的主要能力。用户购买的DRDS实例实际上就是购买一组Server节点。每个DRDS实例至少会包含2个Server节点(因为要高可用,其次是负载均衡),规格很大的实例,会有4或8个Server节点组成(负载均衡是主要目的)。DRDS实例的规格决定了它的主要计算能力。

物理实例:由一组MySQL实例组成,不同的实例其包含的数据都是全部数据的子集(广播表的数据会在多个实例内部冗余这个例外)。每个实例有自己的Slave实例,不是重点后面都忽略它。每个实例代表了一定的资源能力(CPU、内存和空间)。

物理分库:在MySQL里就是数据库,分库说的是这个数据库是总体数据的子集,一个MySQL实例会包含多个分库,在RDS里默认是8个(外部实例默认不让改,这个设定导致了DRDS的拆分设计思路在内部业务和外部业务上呈现不同的特点,其中有一个比较难理解)。

物理分表:在MySQL每个数据库下的普通表(非分区表),分表说的是它的数据是总数据的子集,并且在所有实例里有很多结构相同的表(只是可能表名后面的编号不同)。每个物理分库下可以有1个或多个分表,不同产品特点不一。

物理QPS:所有MySQL实例的QPS总和,衡量数据库层压力的一个指标。TPS同理。

逻辑QPS:所有Server节点的QPS总和,衡量DRDS实例压力的一个指标。TPS同理。

分布式数据库实例:


1.1为什么要实现分库分表

  • 集中式数据库的连接数瓶颈 :应用是无状态的,可以水平扩容,但数据库是集中的。数据库的实际连接数越来越高,逐步消耗数据库性能以及达到连接数设置上限。

  • 存储容量瓶颈:业务数据量越来越大,单机硬盘扩容达到上限,或者存储扩容成本越来越高。

  • QPS瓶颈:集中式数据库的业务QPS上不去,数据库主机资源利用率到达瓶颈(CPU瓶颈或者IO瓶颈等)。


1.2分多少个表合适

分表是存在于分库中,分库在分实例里,多个实例组成了全部的业务数据。关于分表数这里倒是有个简单万能的公式:

总分表数(N) = 总物理实例数(X)* 每个实例下的分库数(Y)* 每个分库下的分表数(Z)

所以,当你定一个总的分表数N时,这个N要能够拆分为三个数(XYZ)的乘积。这个是选择分表数的第二个考虑点。而这个XY的选择都有讲究。

最后分表数目也不能太大,否则元数据管理成本会比较高,对稳定性和性能都有影响。这点不同产品能力不一样。DRDS的内部案例里分表数最多到4096。


1.3分多少个库合适

如果1个实例的分库数是2或2的倍数,那拆分为两个实例还是比较方便的,简单说把分库对半分。具体就是搭建一个Slave实例,数据同步追上后断开同步,分别去掉一半分库。

如果1个实例只有1个分库,那这个方法就行不通。还要继续看有多少个分表,然后对分表集合进行对半分。但总体操作上没有对分库集合对半分要方便。


这种对半拆的方案是最简单的,但并不是唯一的选择。DRDS有能力通过精卫对数据全量进行重分布,从而突破不可继续对半分的限制,只是要消耗更多资源和更多时间。通常运维会选择对半拆。所以分库数量决定了实例可以分拆(扩容)的次数。

二、使用MyCat进行分库分表

项目环境:

192.168.1.15 mycat

192.168.1.16 gongfu1

192.168.1.17 gongfu2

192.168.1.18 gongfu3

三个节点MySQL均为单实例

2.1创建测试库

gongfu1


create database testdb01;

create database testdb02;

create database testdb03;

gongfu2


create database testdb13;

create database testdb14;

create database testdb15;

gongfu3


create database testdb25;

create database testdb26;

create database testdb27;


2.2配置schema.xml

<?xml version="1.0"?>

<!DOCTYPE mycat:schema SYSTEM "schema.dtd">

<mycat:schema xmlns:mycat="http://io.mycat/">

<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="100">

<table name="user03" dataNode="dn$1-3,dn$13-15,dn$25-27" rule="auto-sharding-long"></table>

</schema>

<!-- <dataNode name="dn1$0-745" dataHost="localhost1" database="db$0-745"

/> -->

<dataNode name="dn1" dataHost="gongfu1" database="testdb01" />

<dataNode name="dn2" dataHost="gongfu1" database="testdb02" />

<dataNode name="dn3" dataHost="gongfu1" database="testdb03" />

<dataNode name="dn4" dataHost="gongfu1" database="testdb04" />

<dataNode name="dn5" dataHost="gongfu1" database="testdb05" />

<dataNode name="dn6" dataHost="gongfu1" database="testdb06" />

<dataNode name="dn7" dataHost="gongfu1" database="testdb07" />

<dataNode name="dn8" dataHost="gongfu1" database="testdb08" />

<dataNode name="dn9" dataHost="gongfu1" database="testdb09" />

<dataNode name="dn10" dataHost="gongfu1" database="testdb10" />

<dataNode name="dn11" dataHost="gongfu1" database="testdb11" />

<dataNode name="dn12" dataHost="gongfu1" database="testdb12" />

<dataNode name="dn13" dataHost="gongfu1" database="testdb13" />

<dataNode name="dn14" dataHost="gongfu2" database="testdb14" />

<dataNode name="dn15" dataHost="gongfu2" database="testdb15" />

<dataNode name="dn16" dataHost="gongfu2" database="testdb16" />

<dataNode name="dn17" dataHost="gongfu2" database="testdb17" />

<dataNode name="dn18" dataHost="gongfu2" database="testdb18" />

<dataNode name="dn19" dataHost="gongfu2" database="testdb19" />

<dataNode name="dn20" dataHost="gongfu2" database="testdb20" />

<dataNode name="dn21" dataHost="gongfu2" database="testdb21" />

<dataNode name="dn22" dataHost="gongfu2" database="testdb22" />

<dataNode name="dn23" dataHost="gongfu2" database="testdb23" />

<dataNode name="dn24" dataHost="gongfu2" database="testdb24" />

<dataNode name="dn25" dataHost="gongfu3" database="testdb25" />

<dataNode name="dn26" dataHost="gongfu3" database="testdb26" />

<dataNode name="dn27" dataHost="gongfu3" database="testdb27" />

<dataNode name="dn28" dataHost="gongfu3" database="testdb28" />

<dataNode name="dn29" dataHost="gongfu3" database="testdb29" />

<dataNode name="dn30" dataHost="gongfu3" database="testdb30" />

<dataNode name="dn31" dataHost="gongfu3" database="testdb31" />

<dataNode name="dn32" dataHost="gongfu3" database="testdb32" />

<dataNode name="dn33" dataHost="gongfu3" database="testdb33" />

<dataNode name="dn34" dataHost="gongfu3" database="testdb34" />

<dataNode name="dn35" dataHost="gongfu3" database="testdb35" />

<!--<dataNode name="dn4" dataHost="gongfu3" database="SAMPLE" />

<dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />

<dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />

<dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->

<dataHost name="node1" maxCon="1000" minCon="10" balance="1"

writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">

<heartbeat>select user()</heartbeat>

<!-- can have multi write hosts -->

<writeHost host="192.168.8.31" url="192.168.8.31:3306" user="root" password="mysql"></writeHost>

</dataHost>

<dataHost name="node2" maxCon="1000" minCon="10" balance="1"

writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">

<heartbeat>select user()</heartbeat>

<!-- can have multi write hosts -->

<writeHost host="192.168.1.15" url="192.168.1.15:3306" user="root" password="mysql"></writeHost>

</dataHost>

<dataHost name="gongfu3" maxCon="1000" minCon="10" balance="1"

writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">

<heartbeat>select user()</heartbeat>

<!-- can have multi write hosts -->

<writeHost host="192.168.1.18" url="192.168.1.18:3306" user="root" password="mysql"></writeHost>

</dataHost>

</mycat:schema>

2.3配置rule.xml

<mycat:rule xmlns:mycat="http://io.mycat/">

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

<rule>

<columns>id</columns>

<algorithm>autopartition-long-user03</algorithm>

</rule>

</tableRule>

<function name="autopartition-long-user03" class="io.mycat.route.function.AutoPartitionByLong">

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

<property name="defaultNode">0</property>

</function>

</mycat:rule>

2.4配置autopartition-long-user03.txt

1-10=0

11-20=1

21-30=2

31-40=3

41-50=4

51-60=5

61-70=6

71-80=7

81-10000=8

2.5配置server.xml

<user name="root" defaultAccount="true">

<property name="password">mysql</property>

<property name="schemas">mycatdb</property>

</user>

2.6启动MyCat

/usr/local/mycat/bin/mycat start

2.7查看结果

三个node只在testdb01-03,testdb13-15,testdb25-27,所以除了这9个物理库之外,其他库查不到分片。


下面在三个node分别验证出分片信息:


gongfu1

mysql> select count(*) from testdb01.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

mysql> select count(*) from testdb02.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

mysql> select count(*) from testdb03.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

gongfu2:

mysql> select count(*) from testdb13.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

mysql> select count(*) from testdb14.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

mysql> select count(*) from testdb15.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

gongfu3:

mysql> select count(*) from testdb25.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

mysql> select count(*) from testdb26.user03;

+----------+

| count(*) |

+----------+

| 5 |

+----------+

1 row in set (0.00 sec)

mysql> select count(*) from testdb27.user03;

+----------+

| count(*) |

+----------+

| 10 |

+----------+

1 row in set (0.00 sec)

以上就是MyCat分库分表的知识,详细MyCat实现主从复制可查看笔者博文
:https://www.toutiao.com/i6970231461404328485/