概念
首先为什么要有MyCat
大家都知道,随着业务量的增加,数据库里面的数据是会越来越多的,在数据量到达一定的量级之后,传统的sql语句的优化方式已经很难再提高数据查询效率了。那么,既然数据库在数据量不大的时候查询效率很高而在数据量大了之后变慢,那我们能不能把一张表里的数据拆分成多个表以提高查询效率呢?所以这就引出了分库分表的概念。
以前有做过一个审批系统的系统升级项目,那会一张业务表的数据已经超过5000万条了,当然在系统整体升级之前已经做了分库分表,前辈的做法是分成了业务库和历史库,会定期把业务库的数据迁移到历史库中,以减轻业务库的压力,同时对于类似轨迹之类的表数据(数据量更是5000万的几倍十几倍),则采用按月份不同来插入不同的表。但是这样做的话,业务代码和管理数据源就会变得麻烦,那么有没有方法可以分库分表同时也不需要管理那么多的数据源呢?数据库中间件因此而诞生。而MyCat就是一个数据库中间件。
MyCat和其他数据库中间件的比较
数据库中间件不止MyCat一个产品,下面列举一些
Cobar:阿里开发,经受住了考验,但是已经停止维护
MyCat:在Cobar基础上进行了二次开发,解决了Cobar的一些问题,加入了新功能,社区活跃度很高
OneProxy:一款稳定的商业收费中间件
Vitess:Youtube在生产上使用的,但是不支持mysql原生协议
Kingshard:利用go语言开发的,目前在不断完善
使用MyCat
MyCat相关概念
schema:逻辑库,与MySQL中的Database(数据库)对应,一个逻辑库中定义了所包括的Table。
table:表,即物理数据库中存储的某一张表,与传统数据库不同,这里的表需要声明其所存储的逻辑数据节点DataNode,这是通过表格的分片规则定义来实现的,table可以定义其所属的“子表(childTable)”,子表的分片依赖于与“父表”的具体分片地址,简单的说,就是属于父表里某一条记录A的子表的所有记录都与A存储在同一个分片上。
分片规则:是一个字段与函数的捆绑定义,根据这个字段的取值来返回所在存储的分片(DataNode)的序号,每个表格可以定义一个分片规则,分片规则可以灵活扩展,默认提供了基于数字的分片规则,字符串的分片规则等。
dataNode:MyCAT的逻辑数据节点,是存放table的具体物理节点,也称之为分片节点,通过DataSource来关联到后端某个具体数据库上,一般来说,为了高可用性,每个DataNode都设置两个DataSource,一主一从,当主节点宕机,系统自动切换到从节点。
dataHost:定义某个物理库的访问地址,用于捆绑到dataNode上。
Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发 往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
MyCat通过配置文件来定义相关配置
MYCAT_HOME/conf/schema.xml中定义逻辑库,表、分片节点等内容; MYCAT_HOME/conf/rule.xml中定义分片规则;
MYCAT_HOME/conf/server.xml中定义用户以及系统相关变量,如端口等。
实现分库(垂直拆分)
分库的原则是把有紧密关联或业务类型相似的表放到同一个数据库,比如我之前做的审批系统,就分业务库,征信库以及流程库。PS:如果只是想做分库的话,实际上是可以不用引入MyCat的。
schema.xml文件:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<!-- schema逻辑数据库 -->
<schema name="buss" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<table name="table1" dataNode="dn1"/>
</schema>
<schema name="credit" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn2">
<table name="table2" dataNode="dn2"/>
</schema>
<schema name="flow" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn3">
<table name="table3" dataNode="dn3"/>
</schema>
<!--使用dataNode将实际数据库和逻辑数据库映射-->
<dataNode name="dn1" dataHost="host1" database="db1" />
<dataNode name="dn2" dataHost="host2" database="db2" />
<dataNode name="dn3" dataHost="host3" database="db3" />
<!--配置物理连接-->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<!--写上数据库链接信息-->
<writeHost host="hostM1" url="ip1:3306" user="root" password="123456" />
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="ip2:3306" user="root" password="123456" />
</dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM3" url="ip3:3306" user="root" password="123456" />
</dataHost>
</mycat:schema>
server.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://org.opencloudb/">
<system>
<property name="defaultSqlParser">druidparser</property>
</system>
<!--帐号密码以及所链接的逻辑库-->
<user name="test">
<property name="password">123456</property>
<property name="schemas">buss,credit,flow</property>
</user>
<!--只读的用户信息-->
<user name="user">
<property name="password">123456</property>
<property name="schemas">buss,credit,flow</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
实现分表(水平拆分)
schema.xml文件:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<!-- 将tb_user表分到dn1和dn2两个分片中 -->
<schema name="buss" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_user" dataNode="dn1,dn2" rule="rule1" primaryKey="id"/>
</schema>
<dataNode name="dn1" dataHost="mycat1" database="mycat1" />
<dataNode name="dn2" dataHost="mycat2" database="mycat2" />
<dataHost name="mycat1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="host1" url="ip1:3306" user="root" password="123456" />
</dataHost>
<dataHost name="mycat2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="host2" url="ip2:3306" user="root" password="123456" />
</dataHost>
</mycat:schema>
rule.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://org.opencloudb/">
<tableRule name="rule1">
<!--安装id规则,将id除于1024然后取余,如果余数落在0~512就将数据写到第一个数据库,如果是在512~1024就放到第二个数据库-->
<rule>
<columns>id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<!--分成两片,每片的区间是512,两个相乘必须是1024-->
<function name="func1" class="org.opencloudb.route.function.PartitionByLong">
<property name="partitionCount">2</property>
<property name="partitionLength">512</property>
</function>
</mycat:rule>
server.xml文件和分库差不多
使用MyCat后的优缺点
优点
- 管理多个数据库很容易
- 不存在单库大数据,高并发的性能瓶颈
- 提高了系统的稳定性跟负载能力
- 应用端改造较少
缺点
- 因为加入了中间件,系统高可用性变差
- MyCat非常耗内存和CPU资源
- 分片事务一致性难以解决
- 跨库 join 性能较差