分布式数据库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要能够拆分为三个数(X、Y和Z)的乘积。这个是选择分表数的第二个考虑点。而这个X和Y的选择都有讲究。
最后分表数目也不能太大,否则元数据管理成本会比较高,对稳定性和性能都有影响。这点不同产品能力不一样。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/