写在后面

Mycat是基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优良的架构和性能以及泛滥成熟的应用案例使得Mycat一开始就领有一个很好的终点,站在伟人的肩膀上,咱们能看到更远。业界优良的开源我的项目和翻新思路被宽泛融入到Mycat的基因中,使得Mycat在很多方面都当先于目前其余一些同类的开源我的项目,甚至超过某些商业产品。——来自Mycat官网。

作为Mycat的外围开发者,怎能不来一波Mycat系列文章呢?

背景介绍

作为Mycat的外围开发者之一,明天,终于安顿到Mycat系列文章了。在Mycat系列文章中,咱们一起从一个利用Mycat实现分库分表的案例作为入门程序。后续会继续更新Mycat原理、架构和底层源码解析的文章。心愿Mycat系列文章可能帮忙小伙伴们彻底把握Mycat。

那么,明天,咱们就先来一波应用Mycat实现MySQL分库分表的文章。

注:案例中的MySQL服务器是装置在CentOS6.8服务器上,Mycat Server是装置在本机的Windows零碎上,装置在什么环境上无所谓,这里,我用的是VMWare虚拟机,装置的CentOS零碎,开启多个虚拟机,电脑切实是吃力,所以将Mycat Server装在了本机的Windows零碎上。

计划布局

如上表所示,在局域网的4台主机中,131——133的主机各装置有一台MySQL实例,130主机,也就是本机装置了Mycat Server。

当初假如零碎的数据库为messagedb,外面只有2张表,一张表为音讯表:message,一张示意消息来源的字典表:source,本案例实现的是按天然月分片的规定,因而上述3个mysql实例各自须要创立4个数据库,即


阐明:如果是刚接触Mycat的小伙伴对分片不太了解,简略地说,对于Mycat,一个分片示意某一个MySQL实例上的某一个数据库,即schema@host,于是当咱们原先的一张大表须要分片的时候,mycat就会依照咱们设定的规定,把这张大表中的数据扩散到各个分片上,即所谓的分表分库,因而咱们须要在每个对应的分片上创立雷同名称的数据库,雷同构造的表。

环境筹备

留神:这里,我就省略了MySQL的装置过程,小伙伴们可自行装置MySQL。我后续也会在MySQL相干的专题中给大家分享企业级MySQL装置、优化与部署过程。

创立数据库并建表导入数据

依据数据库实例和存储的数据库对应关系表创立所有的数据库,并在每个数据库里执行如下脚本:

create table source (        id int(11) not null auto_increment primary key comment 'pk',        name varchar(10) default '' comment 'source name');create table message (        id int(11) not null auto_increment primary key comment 'pk',        content varchar(255) default '' comment 'message content',        create_time date default null,        source_id int(11) not null,        foreign key(source_id) references source(id));insert into `source`(`id`,`name`) values(1,'weibo');insert into `source`(`id`,`name`) values(2,'weixin');insert into `source`(`id`,`name`) values(3,'qq');insert into `source`(`id`,`name`) values(4,'email');insert into `source`(`id`,`name`) values(5,'sms');

在message表中,总共有4个字段:

  • id:主键
  • content:音讯的内容
  • create_time:创立工夫,这也是mycat进行分片时的参考字段
  • source_id:source表的外键

另外,咱们在source表插入了5条记录,用于测试。到这里,后端数据库的环境就搭建实现了。

装置和配置Mycat

装置Mycat

装置Mycat的过程比较简单,在这个地址就能够下载安装包:https://github.com/MyCATApache/Mycat-download/tree/master/1.6-RELEASE。下载完之后,就进行解压到零碎相应目录,这里就不细说了。

Mycat安装包构造

装置完之后,简略地看一下mycat目录构造:

启动Mycat

WIndows下启动须要以管理员身份关上命令行窗口,cd 到Mycat的bin目录下,或者将Mycat的 装置目录退出零碎的环境变量path目录里,首先输出命令mycat install进行mycat服务的安装操作,而后 输出命令mycat start 启动Mycat Server。

Linux下进入Mycat的bin目录间接输出./mycat start 启动Mycat Server。

Mycat提供了两个端口,其中,9066端口是治理端口,提供查看以后零碎节点的状况,报告心跳状态等相干系统监控的性能,8066是数据端口,相当于数据库的拜访端口。咱们能够应用mysql命令拜访这里两个端口

mysql -h[mycat_host] -u[mycat_user] -p[mycat_passwd] -P [8066|9066]

同时,咱们也能够批改这两个端口。

那么mycat_user和mycat_passwd是如何配置呢,上面就须要介绍mycat中最次要的3个配置文件:server.xml,schema.xml和rule.xml。

server.xml

该配置文件是用于配置mycat的零碎信息,次要有两个标签:system和user。这里的user就是上述拜访mycat服务的用户,不是后端数据库的用户。如果咱们应用默认的配置,server.xml大略是这样的:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mycat:server SYSTEM "server.dtd"><mycat:server xmlns:mycat="http://io.mycat/">        <system>                <property name="useSqlStat">0</property>                  <property name="useGlobleTableCheck">0</property>                 <property name="sequnceHandlerType">2</property>                <property name="processorBufferPoolType">0</property>                <property name="useOffHeapForMerge">1</property>                <property name="memoryPageSize">1m</property>                <property name="spillsFileBufferSize">1k</property>                <property name="useStreamOutput">0</property>                <property name="systemReserveMemorySize">384m</property>        </system>         <user name="admin">                <property name="password">admin123</property>                <property name="schemas">messagedb</property>        </user></mycat:server>

user标签下schemas属性示意该用户能够拜访的数据库,能够定义多个数据库,用英文逗号隔开。schemas定义的数据库,肯定要配置在前面的schema.xml文件对应的逻辑库,否则会提醒无法访问。

schema.xml

schema配置文件比较复杂,也是最要害的一个配置文件,定义了mycat中的逻辑库、逻辑表,和分片的相干信息。配置如下:

<?xml version="1.0"?><!DOCTYPE mycat:schema SYSTEM "schema.dtd"><mycat:schema xmlns:mycat="http://io.mycat/">         <schema name="messagedb" checkSQLschema="false" sqlMaxLimit="100">                <table name="message" dataNode="dn1,dn2,dn3,dn4,dn5,dn6,dn7,dn8,dn9,dn10,dn11,dn12" rule="sharding-by-month" />                <table name="source" primaryKey="id" type="global" dataNode="dn1,dn2,dn3,dn4,dn5,dn6,dn7,dn8,dn9,dn10,dn11,dn12" />        </schema>        <dataNode name="dn1" dataHost="mysql-01" database="message202001" />        <dataNode name="dn2" dataHost="mysql-01" database="message202002" />        <dataNode name="dn3" dataHost="mysql-01" database="message202003" />        <dataNode name="dn4" dataHost="mysql-01" database="message202004" />        <dataNode name="dn5" dataHost="mysql-02" database="message202005" />        <dataNode name="dn6" dataHost="mysql-02" database="message202006" />        <dataNode name="dn7" dataHost="mysql-02" database="message202007" />        <dataNode name="dn8" dataHost="mysql-02" database="message202008" />        <dataNode name="dn9" dataHost="mysql-03" database="message202009" />        <dataNode name="dn10" dataHost="mysql-03" database="message202010" />        <dataNode name="dn11" dataHost="mysql-03" database="message202011" />        <dataNode name="dn12" dataHost="mysql-03" database="message202012" />         <dataHost name="mysql-01" maxCon="1000" minCon="10" balance="0"                          writeType="0" dbType="mysql" dbDriver="native" switchType="-1">                <heartbeat>select user()</heartbeat>                <writeHost host="hostM1" url="192.168.81.131:3306" user="root"                                   password="root">                </writeHost>        </dataHost>         <dataHost name="mysql-02" maxCon="1000" minCon="10" balance="0"                          writeType="0" dbType="mysql" dbDriver="native" switchType="-1">                <heartbeat>select user()</heartbeat>                <writeHost host="hostM2" url="192.168.81.132:3306" user="root"                                   password="root">                </writeHost>        </dataHost>         <dataHost name="mysql-03" maxCon="1000" minCon="10" balance="0"                          writeType="0" dbType="mysql" dbDriver="native" switchType="-1">                <heartbeat>select user()</heartbeat>                <writeHost host="hostM3" url="192.168.81.133:3306" user="root"                                   password="root">                </writeHost>        </dataHost></mycat:schema>

这里,有几点要阐明一下:

  • schema标签定义逻辑库,其下table子标签定义逻辑表,datanode属性定义该逻辑表须要散布到哪几个分片上,rule属性示意应用何种分片规定,这里咱们抉择sharding-by-month,这个规定的名称是自定义的,只有和前面的rule.xml对应起来即可
  • source表是一张全局表,这里须要应用type=”global”来定义,这样mycat就能够帮咱们在指定的分片上克隆雷同的数据,这对join查问是十分有益处的。
  • datanode标签定义了分片,datahost是主机名,对应dataHost标签的name属性值,database定义该主机数据库实例上的具体数据库名。
  • dataHost标签定义数据库实例,其下heartbeart标签示意心跳检测所应用的办法,writeHost标签定义写数据的实例,另外还有readHost标签能够定义读数据的实例,这里不思考读写拆散,仅应用写实例,因而须要把balance属性设置为0
  • 出于标准和平安思考,最好不应用数据库的root用户,而是另外再创立一个用于mycat拜访的用户。

rule.xml

rule.xml中定义了很多分片的规定,具体规定的算法能够参考官网权威指南,这里咱们间接应用默认的就能够了,其中按天然月的分片规定配置如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mycat:rule SYSTEM "rule.dtd"><mycat:rule xmlns:mycat="http://io.mycat/">     <tableRule name="sharding-by-month">                <rule>                        <columns>create_time</columns>                        <algorithm>partbymonth</algorithm>                </rule>        </tableRule>        <function name="partbymonth"                class="io.mycat.route.function.PartitionByMonth">                <property name="dateFormat">yyyy-MM-dd</property>                <property name="sBeginDate">2020-01-01</property>        </function></mycat:rule>
  • tableRule标签定义分片规定的,其下columns标签示意对数据库表中的哪个字段利用规定,algorithm指定实现算法的名称,对应的是function标签中的name属性值
  • function标签定义对应的实现类,以及参数,包含dateFormat(日期格局)和sBeginDate(起始日期)

阐明:起始日期是用来计算数据所在的分片地位,例如2020年1月的message就会找到第1个分片,即dn1,2020年12月的message就会找到第12个分片,即dn12,然而如果呈现了2018年1月的message,mycat就会去找第13个分片,然而配置文件中又没有对应的配置,那么就会抛出无奈找到分片的谬误。

综上:server.xml定义了拜访mycat服务的用户,以及该用户受权的数据库(逻辑库),schema.xml定义了具体的逻辑库,逻辑表,以及分片和数据库实例的信息,rule.xml分片规定和实现类

测试

到这里曾经实现了mycat的配置文件,但先不急着往里面灌数据,咱们先拜访治理端口9066,看一下运行状况:

C:\Users\binghe>mysql -uadmin -padmin123 -P9066Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 7Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (monitor)Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> show @@datanode;+------+------------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+| NAME | DATHOST                | INDEX | TYPE  | ACTIVE | IDLE | SIZE | EXECUTE | TOTAL_TIME | MAX_TIME | MAX_SQL | RECOVERY_TIME |+------+------------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+| dn1  | mysql-01/message202001 |     0 | mysql |      0 |    4 | 1000 |     412 |          0 |        0 |       0 |            -1 || dn10 | mysql-03/message202010 |     0 | mysql |      0 |    0 | 1000 |      11 |          0 |        0 |       0 |            -1 || dn11 | mysql-03/message202011 |     0 | mysql |      0 |    8 | 1000 |      16 |          0 |        0 |       0 |            -1 || dn12 | mysql-03/message202012 |     0 | mysql |      0 |    1 | 1000 |     412 |          0 |        0 |       0 |            -1 || dn2  | mysql-01/message202002 |     0 | mysql |      0 |    2 | 1000 |       9 |          0 |        0 |       0 |            -1 || dn3  | mysql-01/message202003 |     0 | mysql |      0 |    4 | 1000 |      11 |          0 |        0 |       0 |            -1 || dn4  | mysql-01/message202004 |     0 | mysql |      0 |    2 | 1000 |       9 |          0 |        0 |       0 |            -1 || dn5  | mysql-02/message202005 |     0 | mysql |      0 |    4 | 1000 |     413 |          0 |        0 |       0 |            -1 || dn6  | mysql-02/message202006 |     0 | mysql |      0 |    2 | 1000 |       9 |          0 |        0 |       0 |            -1 || dn7  | mysql-02/message202007 |     0 | mysql |      0 |    4 | 1000 |      11 |          0 |        0 |       0 |            -1 || dn8  | mysql-02/message202008 |     0 | mysql |      0 |    2 | 1000 |       9 |          0 |        0 |       0 |            -1 || dn9  | mysql-03/message202009 |     0 | mysql |      0 |    0 | 1000 |      11 |          0 |        0 |       0 |            -1 |+------+------------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+12 rows in set (0.00 sec)mysql> show @@heartbeat;+--------+-------+----------------+------+---------+-------+--------+---------+--------------+---------------------+-------+| NAME   | TYPE  | HOST           | PORT | RS_CODE | RETRY | STATUS | TIMEOUT | EXECUTE_TIME | LAST_ACTIVE_TIME    | STOP  |+--------+-------+----------------+------+---------+-------+--------+---------+--------------+---------------------+-------+| hostM2 | mysql | 192.168.81.132 | 3306 |       1 |     0 | idle   |       0 | 1,1,1        | 2020-03-04 14:22:59 | false || hostM1 | mysql | 192.168.81.131 | 3306 |       1 |     0 | idle   |       0 | 1,1,1        | 2020-03-04 14:22:59 | false || hostM3 | mysql | 192.168.81.133 | 3306 |       1 |     0 | idle   |       0 | 2,1,1        | 2020-03-04 14:22:59 | false |+--------+-------+----------------+------+---------+-------+--------+---------+--------------+---------------------+-------+3 rows in set (0.00 sec)mysql>

如果看到各个节点都曾经呈现,并且心跳状态RS_CODE=1,则示意后端数据库连贯失常。

当初咱们用JDBC的形式批量插入1000万数据:

package com.mycat.test; import java.sql.Connection;import java.sql.Date;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;import java.util.Calendar;import java.util.Random; import org.junit.Test; /** * 测试Mycat * @author binghe */public class TestMycat {    private static final String driver = "com.mysql.jdbc.Driver";    private static final String url = "jdbc:mysql://127.0.0.1:8066/messagedb?useServerPrepStmts=false&rewriteBatchedStatements=true";    private static final String username = "admin";    private static final String password = "admin123";     @Test    public void test() throws SQLException {        Calendar calendar = Calendar.getInstance();        Random random = new Random();        calendar.set(2020, 0, 1, 0, 0, 0);            Connection connection = null;        PreparedStatement ps = null;        try {            Class.forName(driver);            connection = (Connection) DriverManager.getConnection(url, username, password);            connection.setAutoCommit(false);            String sql = "insert into message(`content`, `create_time`, `source_id`) values(?,?,?)";            ps = connection.prepareStatement(sql);            long start = System.currentTimeMillis();            for (int i = 0; i < 10000000; i++) {                ps.setString(1, System.currentTimeMillis() + "");                long randomtime = calendar.getTimeInMillis() + (random.nextInt(365) + 1) * 86400 * 1000l;                Date date = new Date(randomtime);                int source_id = random.nextInt(5) + 1;                ps.setDate(2, date);                ps.setInt(3, source_id);                ps.addBatch();                if (i != 0 && i % 10000 == 0) {                    System.out.println("execute batch : " + i);                    ps.executeBatch();                }            }            ps.executeBatch();            connection.commit();            System.out.println(System.currentTimeMillis() - start);        } catch (SQLException | ClassNotFoundException e) {            e.printStackTrace();        } finally {            if (ps != null)                ps.close();            if (connection != null)                connection.close();        }    } }

如果运行的时候报错: Multi-statement transaction required more than ‘max_binlog_cache_size’ bytes of storage; 能够适当调大一下my.cnf下的max_binlog_cache_size参数。

验证

最初咱们来测验一下分片的后果,其中message表中的数据依据create_time的值按月进行了分片,而source表作为全局表,则其数据呈现在了每个分片上,上面贴出局部后果

mysql -h192.168.81.131 -uroot -proot -P3306 -e "select min(create_time),max(create_time) from message202002.message;": +------------------+------------------+| min(create_time) | max(create_time) |+------------------+------------------+| 2020-02-01       | 2020-02-28       |+------------------+------------------+ mysql -h192.168.81.132 -uroot -proot -P3306 -e "select min(create_time),max(create_time) from message202005.message;": +------------------+------------------+| min(create_time) | max(create_time) |+------------------+------------------+| 2020-05-01       | 2020-05-31       |+------------------+------------------+ mysql -h192.168.81.133 -uroot -proot -P3306 -e "select min(create_time),max(create_time) from message202009.message;": +------------------+------------------+| min(create_time) | max(create_time) |+------------------+------------------+| 2020-09-01       | 2020-09-30       |+------------------+------------------+
mysql -h192.168.81.131 -uroot -proot -P3306 -e "select * from message202001.source"+----+--------+| id | name   |+----+--------+|  1 | weibo  ||  2 | weixin ||  3 | qq     ||  4 | email  ||  5 | sms    |+----+--------+ mysql -h192.168.81.132 -uroot -proot -P3306 -e "select * from message202007.source"+----+--------+| id | name   |+----+--------+|  1 | weibo  ||  2 | weixin ||  3 | qq     ||  4 | email  ||  5 | sms    |+----+--------+ mysql -h192.168.81.133 -uroot -proot -P3306 -e "select * from message202011.source"+----+--------+| id | name   |+----+--------+|  1 | weibo  ||  2 | weixin ||  3 | qq     ||  4 | email  ||  5 | sms    |+----+--------+

总结

本文就mycat分片的个性进行一次实战操作,实现了部署mycat-server以及后端mysql数据库,并以按天然月为分片规定进行了相干的配置,最初做了一个小的测试来验证分片性能的正确性。

好了,明天Mycat系列文章的入门案例就到这儿吧,大家有啥好的意见或倡议都能够在文末留言,我是冰河,咱们下期见!!

重磅福利

微信搜一搜【冰河技术】微信公众号,关注这个有深度的程序员,每天浏览超硬核技术干货,公众号内回复【PDF】有我筹备的一线大厂面试材料和我原创的超硬核PDF技术文档,以及我为大家精心筹备的多套简历模板(不断更新中),心愿大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过致力胜利进入到了心仪的公司,肯定不要懈怠放松,职场成长和新技术学习一样,逆水行舟。如果有幸咱们江湖再见!

另外,我开源的各个PDF,后续我都会继续更新和保护,感激大家长期以来对冰河的反对!!

写在最初

如果你感觉冰河写的还不错,请微信搜寻并关注「 冰河技术 」微信公众号,跟冰河学习高并发、分布式、微服务、大数据、互联网和云原生技术,「 冰河技术 」微信公众号更新了大量技术专题,每一篇技术文章干货满满!不少读者曾经通过浏览「 冰河技术 」微信公众号文章,吊打面试官,胜利跳槽到大厂;也有不少读者实现了技术上的飞跃,成为公司的技术骨干!如果你也想像他们一样晋升本人的能力,实现技术能力的飞跃,进大厂,升职加薪,那就关注「 冰河技术 」微信公众号吧,每天更新超硬核技术干货,让你对如何晋升技术能力不再迷茫!