写在前面的话

在学习的索引的时候,有提到,当数据表数据达到 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 上面初始化配置:

#
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 #
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 #
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 #
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 上面配置启动脚本:

#
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 #
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 #
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 #
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='',
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='',
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='',
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='',
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="" dataNode="DATANODE01"></schema>
<dataNode name="DATANODE01" dataHost="DATAHOST01" database= "taobao" />
<dataHost name="DATAHOST01" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
<heartbeat>select user()</heartbeat>
<writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
<readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
</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="" dataNode="DATANODE01"></schema>
<dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
<dataHost name="DATAHOST01" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
<heartbeat>select user()</heartbeat>
<writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
<readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
</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="" 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="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
<heartbeat>select user()</heartbeat>
<writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
<readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
</writeHost>
<writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="">
<readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="" />
</writeHost>
</dataHost>
<!-- node 2 -->
<dataHost name="DATAHOST02" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
<heartbeat>select user()</heartbeat>
<writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="">
<readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="" />
</writeHost>
<writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="">
<readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="" />
</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="" 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="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
<heartbeat>select user()</heartbeat>
<writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
<readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
</writeHost>
<writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="">
<readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="" />
</writeHost>
</dataHost>
<!-- node 2 -->
<dataHost name="DATAHOST02" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
<heartbeat>select user()</heartbeat>
<writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="">
<readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="" />
</writeHost>
<writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="">
<readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="" />
</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 为我们提供了一种更加全面的读写分离高可用方式,同时分库分表的应用为我们拓宽了数据库横向扩展的道路。

MySQL for OPS 10:MyCAT 分布式架构的更多相关文章

  1. [待完善]mycat分布式架构部署

    mycat介绍:http://mycat.org.cn/ mycat分布式架构部署

  2. MySQL之九---分布式架构(Mycat/DBLE)

    MyCAT基础架构图 双主双从结构 MyCAT基础架构准备 准备环境  环境准备: 两台虚拟机 db01 db02 每台创建四个mysql实例:3307 3308 3309 3310 删除历史环境 p ...

  3. 分享 : 警惕MySQL运维陷阱:基于MyCat的伪分布式架构

    分布式数据库已经进入了全面快速发展阶段.这种发展是与时俱进的,与人的需求分不开,因为现在信息时代的高速发展,导致数据量和交易量越来越大.这种现象首先导致的就是存储瓶颈,因为MySQL数据库实质上还是一 ...

  4. 转:三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构

    在微信公众号看到一篇关于mycat的文章,觉得分析的很不错,给大家分享一下 三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构 原文链接:https://mp.weixin.qq.com/s ...

  5. Mysql 高可用(MHA)-读写分离(Atlas)-分布式架构(Mycat)

    Mysql 高可用(MHA)-读写分离(Atlas) 1. 搭建主从复制(一主两从) 1.1 准备环境 1 主库:10.0.0.51/db01 2 从库:10.0.0.52/db02,10.0.0.5 ...

  6. Mycat分布式数据库架构解决方案--Mycat实现读写分离

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 安装完 ...

  7. Mycat分布式数据库架构解决方案--Mycat实现数据库分表

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 准备工 ...

  8. Mycat分布式数据库架构解决方案--schema.xml详解

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文件 ...

  9. 安排:《蚂蚁花呗1234面:Redis+分布式架构+MySQL+linux+红黑树》

    前言: 大厂面试机会难得,为了提高面试通关率,建议朋友们在面试前先复盘自己的知识栈,依据掌握程度划分重要.优先级,系统地去学习!如果不准备充分就去参加面试,既会失去进入大厂的机会,更是对自己的不负责. ...

随机推荐

  1. IT兄弟连 HTML5教程 CSS3揭秘 CSS3属性5

    9  透明属性 元素透明也是我们常用的样式,在CSS2中使用滤镜属性opacity实现透明效果.现在有了CSS3的rgba属性,就不用这么麻烦了,当然这也得要浏览器支持才行.通常我们定义颜色都是用十六 ...

  2. jQuery 源码解析(二十二) DOM操作模块 复制元素 详解

    本节说一下DOM操作模块里的复制元素子模块,该模块可以复制一个DOM节点,并且可选择的设置是否复制其数据缓存对象(包含事件信息)和是否深度复制(子孙节点等),API如下: $.clone(elem, ...

  3. Spring中,关于IOC和AOP的那些事

    一.spring 的优点? 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很 ...

  4. Spring Boot可执行Jar包运行原理

    目录 1. 打可执行Jar包 2. 可执行Jar包内部结构 3. JarLauncher 4. 简单总结 5. 远程调试 Spring Boot有一个很方便的功能就是可以将应用打成可执行的Jar.那么 ...

  5. sql server多表关联update

    一般都是写的单表update语句,很少写多表关联的update,但是事实上,在SQL Server中,update的多表连接更新和select的多表连接查询在使用的方法上其实并没有多大区别. 直接上一 ...

  6. ASP.NET Core SignalR:基础概述

    一.简介 ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实时 Web 功能使服务器端代码能够即时将内容推送到客户端. SignalR 的适用 ...

  7. 如何使用SpringBoot封装自己的Starter

    作者:Sans_ juejin.im/post/5cb880c2f265da03981fc031 一.说明 我们在使用SpringBoot的时候常常要引入一些Starter,例如spring-boot ...

  8. 初识VEH链(用户异常派发的进一步探究)

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 初识VEH链(用户异常派发的进一步探究)  VEH链是进程处理异常 ...

  9. Winform中怎样在工具类中对窗体中多个控件进行操作(赋值)

    场景 需求是在窗体加载完成后掉用工具类的方法,工具类中获取窗体的多个控件对象进行赋值. 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 ...

  10. MVC邮箱验证

    post请求 [HttpPost] public void Email(Models.Email m,string Txt) { if (Txt!= Session["yzm"]. ...