【10】MySQL:MyCAT 分布式架构

写在前面的话

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

MyCAT 环境基础架构准备

架构图 1:

架构图 2:

【1】搭建基础环境:

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

# 创建基础目录
mkdir -p /data/{data,logs,backup,conf}/mysql-33{07,08,09,10}
mkdir -p /data/logs/mysql-33{07,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 [email protected]‘localhost‘ identified by ‘123‘;"
mysql -S /data/logs/mysql-3308/mysql.sock -e "alter user [email protected]‘localhost‘ identified by ‘123‘;"
mysql -S /data/logs/mysql-3309/mysql.sock -e "alter user [email protected]‘localhost‘ identified by ‘123‘;"
mysql -S /data/logs/mysql-3310/mysql.sock -e "alter user [email protected]‘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 [email protected]‘192.168.100.%‘ identified by ‘123‘;"
mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "grant all on *.* to [email protected]‘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 为我们提供了一种更加全面的读写分离高可用方式,同时分库分表的应用为我们拓宽了数据库横向扩展的道路。

原文地址:https://www.cnblogs.com/Dy1an/p/11571605.html

时间: 2024-11-15 06:06:16

【10】MySQL:MyCAT 分布式架构的相关文章

CK21190-Mycat分布式架构之Mycat分布式架构实战解析

CK21190-Mycat分布式架构之Mycat分布式架构实战解析 Mycat是国内第一个卖电子书的开源软件,参与的作者们平生第一次分到了一笔开源收入的酬劳,虽然微不足道,但那一刻,他们都坚信,Mycat会越来越好.如今,Mycat的稳定参与者人数已经超过10人,包括很多美女,而第三代新生志愿者团队也正在形成中.Mycat已经有超过300个生产案例,从政府的项目.电信项目.电商项目.O2O项目.游戏到一些大数据分析的项目,Mycat的生态圈正在加速形成中,使用或者研究过Mycat的知名公司名单越

MySQL 部署分布式架构 MyCAT (三)

配置垂直分表 修改 schema.xml (db1) cd /data/mycat/conf cp schema.xml schema.xml.rwh # 修改配置 vi schema.xml <?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/">

MySQL 部署分布式架构 MyCAT (五)

分片(水平拆分) 4.全局表 业务使用场景: 如果你的业务中有些数据类似于数据字典,比如配置文件的配置, 常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大, 而且大部分的业务场景都会用到,那么这种表适合于Mycat全局表,无须对数据进行切分, 要在所有的分片上保存一份数据即可,Mycat 在Join操作中,业务表与全局表进行Join聚合会优先选择相同分片内的全局表join, 避免跨库Join,在进行数据插入操作时,mycat将把数据分发到全局表对应的所有分片执行,在进行数据读取时候

Mycat分布式架构之Mycat入门到精通

支持SQL92标准支持MySQL.Oracle.DB2.SQL Server.PostgreSQL等DB的常见SQL语法遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理.基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群.支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster基于Nio实现,有效管理线程,解决高并发问题.支持数据的多片自动路由与聚合,支持sum,count,max等常用

大型电商分布式网站架构设计与实践,Java分布式架构,Java事务分布式高并发-视频教程

15套java架构师.集群.高可用.高可扩 展.高性能.高并发.性能优化.Spring boot.Redis.ActiveMQ.Nginx.Mycat.Netty.Jvm大型分布 式项目实战视频教程 视频课程包含: 高级Java架构师包含:Spring boot.Spring  cloud.Dubbo.Redis.ActiveMQ.Nginx.Mycat. Spring.MongoDB.ZeroMQ.Git.Nosql.Jvm.Mecached.Netty.Nio.Mina.性能调优.高并发.

jeesz分布式架构之 mycat实现mysql读写分离实践

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] mycat是一个的数据库中间件,基于阿里开源的cobar产品而研发,由几个有志之士的牛人共同完成并开源.提供高可用性数据分片集群,自动故障切换,高可用性 ,支持读写分离,支持MySQL双主多从,以及一主多从的模式 ,支持全局表,数据自动分片到多个节点,用于高效表关联查询 ,支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询多平台支持,部署和实施简单. 今天来实践下用mycat实现mysql的读写分离,1.配置mys

分布式MySQL数据库TDSQL架构分析

摘要:腾讯计费平台部为了解决基于内存的NoSQL解决方式HOLD平台在应对多种业务接入时的不足.结合团队在MySQL领域多年应用和优化经验,终于在MySQL存储引擎基础上,打造一套分布式SQL系统TDSQL.本文是对该系统架构分析. 腾讯计费平台部托管着公司90%以上的虚拟账户.如QB.Q点.包月服务.游戏的二级账户等,为了保证能顺畅支撑公司各大业务的实时在线交易.而且在各种灾难场景下数据是一致而且可用的,对系统的可用性.一致性切换要求很高,因此计费团队历来都很重视高一致性存储系统的建设. 到眼

使用HAProxy、PHP、Redis和MySQL支撑10亿请求每周架构细节

[编者按]在公司的发展中,保证服务器的可扩展性对于扩大企业的市场需要具有重要作用,因此,这对架构师提出了一定的要求.Octivi联合创始人兼软件架构师Antoni Orfin将向你介绍一个非常简单的架构,使用HAProxy.PHP.Redis和MySQL就能支撑每周10亿请求.同时,你还能了解项目未来的横向扩展途径及常见的模式. 以下为译文: 在这篇文章中,我将展示一个非常简单的架构,使用HAProxy.PHP.Redis和MySQL支撑每周10亿请求.除此之外,我还将展示项目未来的横向扩展途径

分布式架构理解(云时代架构文章读后感10)

随着移动互联网的发展智能终端的普及,计算机系统早就从单机独立工作过渡到多机器协作工作.计算机以集群的方式存在,按照分布式理论的指导构建出庞大复杂的应用服务,也已经深入人心.本文力求从分布式基础理论,架构设计模式,工程应用,部署运维,业界方案这几大方面,介绍基于MSA(微服务架构)的分布式的知识体系大纲.从而对SOA到MSA进化有个立体的认识,从概念上和工具应用上更近一步了解微服务分布式的本质,身临其境的感受如何搭建全套微服务架构的过程. SOA面向服务架构 由于业务发展到一定层度后,需要对服务进