10MySQL:MyCAT 分布式架构

Posted dy1an

tags:

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

写在前面的话

 

在学习的索引的时候,有提到,当数据表数据达到 800W 的时候,索引的性能就开始逐步下降。对于一个公司而言,主要业务数据表达到 1000W 都很容易。同时这张表一般都是业务常用的表,操作还比较频繁。所以为了提升用户体验,需要采用另外的方式对数据库进行优化,那就是分库分表。而 MyCAT 就是能够帮助我们管理分库分表的这样一个中间件。

 

 

MyCAT 环境基础架构准备

 

架构图 1:

技术图片

 

架构图 2:

 技术图片

 

【1】搭建基础环境:

1. 在 db01:192.168.100.111 上面安装数据库多实例:

# 创建基础目录
mkdir -p /data/data,logs,backup,conf/mysql-3307,08,09,10
mkdir -p /data/logs/mysql-3307,08,09,10/bin-log,slow-log,error-log,relay-log
mkdir -p /data/packages/mysql
mkdir -p /data/services

# 添加用户
useradd -s /sbin/nologin mysql

# 修改目录权限
chown -R mysql.mysql /data/logs/mysql-33*
chown -R mysql.mysql /data/data/mysql-33*

# 清理默认配置文件
mv /etc/my.cnf /etc/my.cnf_bak

# 解压包
cd /data/packages/mysql/
tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
cd /data/services/
mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql

# 配置环境变量并查看
echo export PATH=$PATH:/data/services/mysql/bin >> /etc/profile
source /etc/profile
mysql -V

 

2. 在 db01:192.168.100.111 上面初始化数据:

# 初始化数据
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3307
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3308
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3309
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3310

 

3. 在 db01:192.168.100.111 上面初始化配置:

# 3307
cat >/data/conf/mysql-3307/my.cnf<<EOF
[mysqld]
port=3307
basedir=/data/services/mysql
datadir=/data/data/mysql-3307
socket=/data/logs/mysql-3307/mysql.sock
log-error=/data/logs/mysql-3307/error-log/mysql.log
log_bin=/data/logs/mysql-3307/bin-log/mysql-bin
slow_query_log=1
slow_query_log_file=/data/logs/mysql-3307/slow-log/slow.log
long_query_time=2
log_queries_not_using_indexes=1
relay_log=/data/logs/mysql-3307/relay-log/relay-bin
binlog_format=row
skip-name-resolve
server-id=107
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

# 3308
cat >/data/conf/mysql-3308/my.cnf<<EOF
[mysqld]
port=3308
basedir=/data/services/mysql
datadir=/data/data/mysql-3308
socket=/data/logs/mysql-3308/mysql.sock
log-error=/data/logs/mysql-3308/error-log/mysql.log
log_bin=/data/logs/mysql-3308/bin-log/mysql-bin
slow_query_log=1
slow_query_log_file=/data/logs/mysql-3308/slow-log/slow.log
long_query_time=2
log_queries_not_using_indexes=1
relay_log=/data/logs/mysql-3308/relay-log/relay-bin
binlog_format=row
skip-name-resolve
server-id=108
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

# 3309
cat >/data/conf/mysql-3309/my.cnf<<EOF
[mysqld]
port=3309
basedir=/data/services/mysql
datadir=/data/data/mysql-3309
socket=/data/logs/mysql-3309/mysql.sock
log-error=/data/logs/mysql-3309/error-log/mysql.log
log_bin=/data/logs/mysql-3309/bin-log/mysql-bin
slow_query_log=1
slow_query_log_file=/data/logs/mysql-3309/slow-log/slow.log
long_query_time=2
log_queries_not_using_indexes=1
relay_log=/data/logs/mysql-3309/relay-log/relay-bin
binlog_format=row
skip-name-resolve
server-id=109
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

# 3310
cat >/data/conf/mysql-3310/my.cnf<<EOF
[mysqld]
port=3310
basedir=/data/services/mysql
datadir=/data/data/mysql-3310
socket=/data/logs/mysql-3310/mysql.sock
log-error=/data/logs/mysql-3310/error-log/mysql.log
log_bin=/data/logs/mysql-3310/bin-log/mysql-bin
slow_query_log=1
slow_query_log_file=/data/logs/mysql-3310/slow-log/slow.log
long_query_time=2
log_queries_not_using_indexes=1
relay_log=/data/logs/mysql-3310/relay-log/relay-bin
binlog_format=row
skip-name-resolve
server-id=110
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
EOF

 

4. 在 db01:192.168.100.111 上面配置启动脚本:

# 3307
cat >/etc/systemd/system/mysqld-3307.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3307/my.cnf
LimitNOFILE=5000
EOF

# 3308
cat >/etc/systemd/system/mysqld-3308.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3308/my.cnf
LimitNOFILE=5000
EOF

# 3309
cat >/etc/systemd/system/mysqld-3309.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3309/my.cnf
LimitNOFILE=5000
EOF

# 3310
cat >/etc/systemd/system/mysqld-3310.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3310/my.cnf
LimitNOFILE=5000
EOF

 

5. 在 db01:192.168.100.111 上面启动并查看:

# 启动 MySQL
systemctl start mysqld-3307.service 
systemctl start mysqld-3308.service 
systemctl start mysqld-3309.service 
systemctl start mysqld-3310.service 

# 查看 MySQL
mysql -S /data/logs/mysql-3307/mysql.sock -e "select @@server_id;"
mysql -S /data/logs/mysql-3308/mysql.sock -e "select @@server_id;"
mysql -S /data/logs/mysql-3309/mysql.sock -e "select @@server_id;"
mysql -S /data/logs/mysql-3310/mysql.sock -e "select @@server_id;"

# 添加 root 密码
mysql -S /data/logs/mysql-3307/mysql.sock -e "alter user root@‘localhost‘ identified by ‘123‘;"
mysql -S /data/logs/mysql-3308/mysql.sock -e "alter user root@‘localhost‘ identified by ‘123‘;"
mysql -S /data/logs/mysql-3309/mysql.sock -e "alter user root@‘localhost‘ identified by ‘123‘;"
mysql -S /data/logs/mysql-3310/mysql.sock -e "alter user root@‘localhost‘ identified by ‘123‘;"

 

6. 在 db02:192.168.100.112 上面执行相同的操作:注意修改配置文件中的 server-id,db02 可以改成 2 开头

# 步骤略

 

【2】配置 db01 和 db02 的 3307 互为主从关系:

1. 在 db02:192.168.100.112:3307 上面配置同步用户:

mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "grant replication slave on *.* to repl@‘192.168.100.%‘ identified by ‘123‘;"
mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "grant all on *.* to root@‘192.168.100.%‘ identified by ‘123‘ with grant option;"

 

2. 在 db01:192.168.100.111:3307 上面配置同步 db02:3307:

登录数据库:

mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock

执行 SQL:

-- 创建同步信息
CHANGE MASTER TO
  MASTER_HOST=192.168.100.112,
  MASTER_USER=repl,
  MASTER_PASSWORD=123,
  MASTER_PORT=3307,
  MASTER_AUTO_POSITION=1;

-- 启动 slave
start slave;

-- 查看状态
show slave status\\G

结果如图:

技术图片

 

3. 在 db02:192.168.100.112:3307 上面配置同步 db01:3307:

登录数据库:

mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock

执行 SQL:

-- 创建同步信息
CHANGE MASTER TO
  MASTER_HOST=192.168.100.111,
  MASTER_USER=repl,
  MASTER_PASSWORD=123,
  MASTER_PORT=3307,
  MASTER_AUTO_POSITION=1;

-- 启动 slave
start slave;

-- 查看状态
show slave status\\G

结果如下:

技术图片

此时,db01 的 3307 和 db02 的 3307 互为主从!

 

【3】配置 db01:3309 为 db01:3307 的从,db02:3309 为 db02:3307 的从:

1. db01 操作:

mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock

执行 SQL:

-- 创建同步信息
CHANGE MASTER TO
  MASTER_HOST=192.168.100.111,
  MASTER_USER=repl,
  MASTER_PASSWORD=123,
  MASTER_PORT=3307,
  MASTER_AUTO_POSITION=1;

-- 启动 slave
start slave;

-- 查看状态
show slave status\\G

结果如下:

技术图片

 

2. db02 操作:

mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock

执行 SQL:

-- 创建同步信息
CHANGE MASTER TO
  MASTER_HOST=192.168.100.112,
  MASTER_USER=repl,
  MASTER_PASSWORD=123,
  MASTER_PORT=3307,
  MASTER_AUTO_POSITION=1;

-- 启动 slave
start slave;

-- 查看状态
show slave status\\G

结果如下:

技术图片

 

【4】同理配置另外一组:3308 和 3310,方法类似,注意 IP 端口就行。步骤略

 

【5】检查主从状态:

mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "show slave status\\G" | grep "Yes"
mysql -uroot -p123 -S /data/logs/mysql-3308/mysql.sock -e "show slave status\\G" | grep "Yes"
mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock -e "show slave status\\G" | grep "Yes"
mysql -uroot -p123 -S /data/logs/mysql-3310/mysql.sock -e "show slave status\\G" | grep "Yes"

结果如图:

技术图片

至此,简单的基础架构搭建完成!

 

 

分布式架构演进

 

举一个例子,假如淘宝服务,在公司创建的时候,由于业务量很小,然后久都存在一个数据库里面。但是随着后后期数据量的增加,发现如果都存在一个库,那么数据库的性能有些吃不消,于是为了分担性能压力,将某些数据量大并且访问频繁的表单独抽出来放到单独的机器上面去。这就是垂直拆分(分库分表)。但是随着时间的推移,可能某个表的数据越来越大,达到了上亿数据量,虽然我们见他放在单独的库中,但是性能依旧跟不上了,于是想出了一个办法,能不能将这个表分成一组一组的数据,放到不同的数据库中,这就是水平拆分(分片),如图所示:

技术图片

实现的方式有以下这些:

1. 360 的 Atlas-sharding

2. Alibaba 的 Cobar / TDDL

3. Aliyun 的 DRDS

4. MyCAT 等

 

 

部署 MyCAT

 

部署 MyCAT 非常简单,由于 MyCAT 是 Java 开发的,所以得先准备 Java 环境,我这里使用JDK 8:

可以前往 MyCAT 的 FTP 地址下载相关的包:

http://dl.mycat.io/

1. 新准备一台机器,安装 MySQL 但是不用初始化:

# 创建必要用户和目录
useradd -s /sbin/nologin mysql
mkdir -p /data/data,logs,backup,packages/mysql
mkdir -p /data/services
chown mysql.mysql /data/logs/mysql/
chown mysql.mysql /data/data/mysql/

# 安装 MySQL
cd /data/packages/mysql/
tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
cd /data/services/
mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql

# 配置环境变量
echo export PATH=$PATH:/data/services/mysql/bin >> /etc/profile
source /etc/profile

# 查看安装结果
mysql -V

 

2. 安装 JDK:

# 解压 jdk
tar -zxf jdk-8u45-linux-x64.tar.gz -C /data/services/
cd /data/services/
mv jdk1.8.0_45/ jdk8

# 配置环境变量
echo export JAVA_HOME=/data/services/jdk8
export CLASSPATH=$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
export JRE_HOME=$JAVA_HOME/jre >> /etc/profile

# 生效和查看
source /etc/profile
java -version

 

3. 安装 MyCAT:

# 解压安装
cd /data/packages/mycat/
tar -zxf Mycat-server-1.6.7.3-release-20190828135747-linux.tar.gz -C /data/services/

# 配置环境变量
echo export PATH=$PATH:/data/services/mycat/bin >> /etc/profile

# 生效和查看
source /etc/profile

# 启动 MyCAT
mycat start

此时默认访问端口:8066,用户名:root,密码:123456,配置文件:server.xml

<user name="root" defaultAccount="true">
    <property name="password">123456</property>
    <property name="schemas">TESTDB</property>
    ....
</user>

 

4. 访问测试:

登录 MyCAT 数据库:

mysql -uroot -p123456 -h 127.0.0.1 -P 8066

这都是默认的方式,执行  SQL:

技术图片

至此,MyCAT 安装完成,具体目录结构:

日志路径:/data/services/mycat/logs

配置路径:/data/services/mycat/conf

 

 

MyCAT 实现读写分离

 

1. 事先创建 taobao 库,修改配置文件:schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">  
<mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="DATANODE01"></schema>  
    <dataNode name="DATANODE01" dataHost="DATAHOST01" database= "taobao" />         
    <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">    
        <heartbeat>select user()</heartbeat>  
        <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123"> 
            <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" /> 
        </writeHost> 
    </dataHost>  
</mycat:schema>

注意,命名不能有下划线这些,否则有问题!

 

2. 重启 MyCAT 测试读写:

mycat restart

测试读写:

mysql -uroot -p123456 -h 127.0.0.1 -P8066

查看结果:

技术图片

该读写分离最终实现主库宕机,从库也无法使用。 

 

 

MyCAT 配置读写分离高可用

 

1. 修改上面的配置,增加另外一组主从:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="DATANODE01"></schema>
    <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
    <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
        <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123">
            <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" />
        </writeHost>
        <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
            <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
        </writeHost>
    </dataHost>
</mycat:schema>

 

2. 重启 MyCAT 测试:

写操作:

技术图片

读操作:

技术图片

可以发现,写操作都是在第一个 write host 上面,其余 3 个尽管有一个也是 write host,但是它由于是 standby write host 的原因,它也只提供读操作。

 

3. 此时关闭 db01 的 3307 数据库:

写操作:

技术图片

读操作:

技术图片

可以发现,当主停掉之后,其附带的从库也跟着停止了服务,最终只剩下一个节点读,一个节点写。

当我们重启恢复 db01 的 3307 时,需要重启 db01 的 3309 的同步服务,否则会出现同步失败。SQL 线程一直 Connecting 状态。

 

 

MyCAT schema.xml 参数简单说明

 

1. dataHost 中的 balance,有三个值:0,1,2:

当值为 0 时,不开启读写分离,所有操作都在 writehost。

当值为 1 时,全部 write host,readhost,standby writehost 都参与负载均衡,也就是一写多读。

当值为 2 时,所有机器都能够执行读操作。

 

2.  dataHost 中的 writeType,有两个值:0,1:

当值为 0 时,所有写操作都放到一个 writehost 上面。

当值为 1 时,所有写操作都随机分配到所有 writehost 上面,不推荐,容易数据混乱。

 

3. dataHost 中的 switchType,值有三个:-1,1,2:

当值为 -1 时,不自动切换。

当值为 1 时,自动切换,默认。

当值为 2 时,基于 MySQL 主从状态决定是否切换。

 

4. dataHost 中的 maxCon,最大连接数。

5. dataHost 中的 minCon,MyCAT 启动后,会在后端数据库开这么多个线程,用于处理请求。

6. heartbeat 心跳检测。

 

 

MyCAT 垂直分表

 

1. 在 3307 组的 tabao 库创建 t1 表:

技术图片

 

2. 在 3308 组的 tabao 库创建 t2 表:

技术图片

 

3. 配置 schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="DATANODE01">
        <table name="t1" dataNode="DATANODE01"/>
        <table name="t2" dataNode="DATANODE02"/>
    </schema>
    <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
    <dataNode name="DATANODE02" dataHost="DATAHOST02" database="taobao" />
    <!-- node 1 -->
    <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
        <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123">
            <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" />
        </writeHost>
        <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
            <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
        </writeHost>
    </dataHost>
    <!-- node 2 --> 
    <dataHost name="DATAHOST02" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
        <writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="123">
            <readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="123" />
        </writeHost>
        <writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="123">
            <readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="123" />
        </writeHost>
    </dataHost>
</mycat:schema>

 

4. 重启测试:

mysql -uroot -p123456 -h 127.0.0.1 -P8066

查看:

技术图片

可以看到,这样就把分布在各个库的表集中到了一个数据库,而且后端还是高可用读写分离的。

 

 

MyCAT 水平拆分 - 范围 range

 

当某个单表数据量实在太大了,就得想办法将其放到不同的库上面,以此来提升查询性能。常用的水平拆分表的方法:范围,取模,枚举,哈希,时间等。

比如对于一张表而言,数据量达到 800 - 1000 万就有个瓶颈了,这时候可能就得想办法对其进行优化了。

假如此时 tabao 库有一张表叫做 t3,我们希望根据他的 ID  1 - 10 存放在数据库集群 1,11 - 20 存放到集群 2。 

1. 在 3307 和 3308 的 tabao 库都创建 t3 表:

use taobao;
create table t3(id int, name varchar(10));

 

2. 修改 mycat 的配置 schema.xml:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="DATANODE01">
        <table name="t3" dataNode="DATANODE01,DATANODE02" rule="auto-sharding-long" />
    </schema>
    <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
    <dataNode name="DATANODE02" dataHost="DATAHOST02" database="taobao" />
    <!-- node 1 -->
    <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
        <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123">
            <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" />
        </writeHost>
        <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
            <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
        </writeHost>
    </dataHost>
    <!-- node 2 --> 
    <dataHost name="DATAHOST02" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
        <heartbeat>select user()</heartbeat>
        <writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="123">
            <readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="123" />
        </writeHost>
        <writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="123">
            <readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="123" />
        </writeHost>
    </dataHost>
</mycat:schema>

和之前的配置不一样的就是 table 定义的部分,因为我们只有一个表,最后我们选择 rule 就是普通的范围方式。

该配置 rule 的配置可以查看 mycat 的配置 rule.xml 中:

<!-- 配置按照哪个字段分 -->
<tableRule name="auto-sharding-long">
    <rule>
        <columns>id</columns>
        <algorithm>rang-long</algorithm>
    </rule>
</tableRule>

<!-- 分配规则的文件 -->
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">autopartition-long.txt</property>
</function>

 

2. 由于我们本身就是使用 id 字段,所有直接修改 autopartition-long.txt 文件:

0-10=0
11-20=1

表示 id 0 - 10 存储到 0 节点,11 - 20 存储到 1 节点。节点计数从 0 开始,如果超出限制 id,是无法插入的,找不到节点。

 

3. 重启 MyCAT 在  MyCAT 插入数据:

mysql -uroot -p123456 -h 127.0.0.1 -P 8066

执行 SQL:

insert into t3(id,name) values(1,"a");
insert into t3(id,name) values(2,"b");
insert into t3(id,name) values(3,"c");
insert into t3(id,name) values(11,"aa");
insert into t3(id,name) values(12,"bb");
insert into t3(id,name) values(13,"cc");

结果:

技术图片

 

4. 去节点查看:

3307 节点:

技术图片

 

3308 节点:

技术图片

可以发现数据被成功分开存储,但是对于 MyCAT 而言,他们还是在一个表。

 

 

MyCAT 水平拆分 - 取模 mod

 

现在准备 tabao 库中准备一个 t4 表,我们希望最终的数据平均的分配到两个节点上面,这时候就用到了取模。

create table t4(id int, name varchar(10));

 

1. 修改 schema.xml:

<table name="t4" dataNode="DATANODE01,DATANODE02" rule="mod-long" />

和之前的配置只需要修改 rule 的方式为:mod-long

 

2. 修改 rule.xml

<!-- 配置按照哪个字段取模 -->
<tableRule name="mod-long">
    <rule>
        <columns>id</columns>
        <algorithm>mod-long</algorithm>
    </rule>
</tableRule>

<!-- 分配节点数 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <!-- how many data nodes -->
    <property name="count">2</property>
</function>

配置有多少个节点参与进来。由于我们只有两个集群,所有改为 2。

 

3. 重启 MyCAT 测试:

连接:

mysql -uroot -p123456 -h 127.0.0.1 -P 8066

执行 SQL:

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,"x");
insert into t4(id,name) values(5,"d");
insert into t4(id,name) values(6,"e");
insert into t4(id,name) values(7,"f");
insert into t4(id,name) values(8,"g");
insert into t4(id,name) values(11,"g");
insert into t4(id,name) values(13,"g");

结果:

技术图片

 

4. 去单独的节点查看:

3307 节点:

技术图片

 

3308 节点:

技术图片

两个节点取模分配刚好能够实现奇数偶数 id 分开存放。

 

 

MyCAT 水平拆分 - 枚举

 

在某些特殊情况下,例如按照地区进行分配的时候,用前面的方式可能就不合适,所有就有了枚举。可以按照某些规定的值进行分配。

1. 创建一张包含地区的表 t5:

create table t5(id int, name varchar(10), city varchar(10)) charset utf8;

 

2. 修改 schema.xml:

<table name="t5" dataNode="DATANODE01,DATANODE02" rule="sharding-by-intfile" />

修改 rule 方法为:sharding-by-intfile

 

3. 修改 rule.xml 配置:

<!-- 配置按照哪个字段枚举 -->
<tableRule name="sharding-by-intfile">
    <rule>
        <columns>city</columns>
        <algorithm>hash-int</algorithm>
    </rule>
</tableRule>

<!-- 指定配置文件,类型支持中文,默认节点 -->
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
    <property name="mapFile">partition-hash-int.txt</property>
    <property name="type">1</property>
    <property name="defaultNode">0</property>
</function>

 

4. 配置 partition-hash-int.txt

北京=0
深圳=1

 

5. 重启 MyCAT 查看:

mysql -uroot -p123456 -h 127.0.0.1 -P 8066

执行 SQL:

insert into t5(id,name,city) values(1,"a","北京");
insert into t5(id,name,city) values(2,"b","深圳");
insert into t5(id,name,city) values(3,"c","深圳");
insert into t5(id,name,city) values(4,"x","上海");
insert into t5(id,name,city) values(5,"d","天津");
insert into t5(id,name,city) values(6,"d","北京");
insert into t5(id,name,city) values(7,"d","深圳");

结果:

技术图片

 

6. 去节点查看:

3307 节点:

技术图片

 

3308 节点:

技术图片

此时发现,北京被保存到了集群 0,深圳保存到了集群 1,其它默认保存到集群 0。

更复杂的按照时间切分可以下去自己了解一下。

 

 

全局表和 E-R 分片

 

我们可以想象这样一个现象,数据库中有很多表,但是这些表分布在不同的数据库,这时候需要将他们 join 查询,会发现他们会有很多不应该存在的开销,而且这个被 join 的表还是那种数据比较稳定,数据量不大,而且不容易更新,例如省市区这种表。这个时候就适合用于全局表,让他在所有节点都保存一份,这样在 join 的适合就职于一用自己主机上面磁盘分区上面的该表,由此节约计算成本,跨库 join 的出现。

只需要在 schema.xml 中将 table 改写为:

<table name="t_area" primaryKey="id"  type="global" ataNode="DATANODE01,DATANODE02" /> 

这就是全局表。

 

至于 E- R 分片,例如在使用 SQL:

A join B
on a.xx=b.yy
join C
on A.id=C.id

可以增加配置:

<table name="A" dataNode="sh1,sh2" rule="mod-long"> 
       <childTable name="B" joinKey="yy" parentKey="xx" /> 
</table> 

以此来避免跨分片 join 操作。

 

 

小结

 

MyCAT 为我们提供了一种更加全面的读写分离高可用方式,同时分库分表的应用为我们拓宽了数据库横向扩展的道路。

以上是关于10MySQL:MyCAT 分布式架构的主要内容,如果未能解决你的问题,请参考以下文章

MySQL-MyCAT分布式架构

MySQL Mycat 分布式架构

mysql分布式架构mycat

MySQL 部署分布式架构 MyCAT

数据库 | 跟郭导学MySQL:分布式架构-MyCAT

Mycat分布式架构之Mycat精通