1-MySQL - Mycat

MySQL分布式架构介绍

备份恢复 主从复制 MHA Atlas

分布式架构演变
如下图,最开始我们的所有数据库都存到一个MySQL实例中,然后这个MySQL实例单独存放到一个物理机上。
但随着业务的增上,这些核心库慢慢的变大,访问也越来越频繁,导致单机单实例这样的架构不堪重负。
这架构要升级啊!简单,将多个核心库分开,一个核心库一个物理机,完美,解决了一些问题。

image

主从复制篇介绍MySQL的架构演变时,说到了一些具有代表性的产品来构建分布式的架构:DBLE、Alibaba TDDL、百度 Heisenberg、58同城 Oceanus、Google Vitess、OneProxy、DRDS、InnoDB Cluster。

而分布式架构通常应用于大型或者巨型企业来管理海量的数据。

如上图,一个分片可以有多个MySQL实例组成,这些实例可以单机单实例也可以单机多实例搭配。且多个实例组成两组主从架构,且两组主节点又组成互为主从架构,提高可用性。

当然,上面架构中的分片还有些问题,比如一个分片如果同时存储在一个物理机上的话,也是有风险的。所以,我们应该交叉分布:

image

通过交叉分布,一个物理机宕掉,通过配置高可用,前端业务也不会受影响。虽然一个分片的节点分布到了不同的物理硬件上,但它逻辑上还是一个分片。

而本篇这里使用的到实现分布式架构的中间件软件就是Mycat,当然本篇也是MySQL MHA架构的最后一篇,主要通过Mycat了解上述架构实现的一些细节。

mycat前世今生

https://github.com/MyCATApache/Mycat-Server/wiki

2013年阿里的Cobar在社区使用过程中发现存在一些比较严重的问题,及其使用限制,经过Mycat发起人第一次改良,第一代改良版——Mycat诞生。 Mycat开源以后,一些Cobar的用户参与了Mycat的开发,最终Mycat发展成为一个由众多软件公司的实力派架构师和资深开发人员维护的社区型开源软件。

2014年Mycat首次在上海的《中华架构师》大会上对外宣讲,更多的人参与进来,随后越来越多的项目采用了Mycat。

2015年5月,由核心参与者们一起编写的第一本官方权威指南《Mycat权威指南》电子版发布,累计超过500本,成为开源项目中的首创。

2015年10月为止,Mycat项目总共有16个Committer。

截至2015年11月,超过300个项目采用Mycat,涵盖银行、电信、电子商务、物流、移动应用、O2O的众多领域和公司。

截至2015年12月,超过4000名用户加群或研究讨论或测试或使用Mycat。

Mycat是基于开源cobar演变而来,我们对cobar的代码进行了彻底的重构,使用NIO重构了网络模块,并且优化了Buffer内核,增强了聚合,Join等基本特性,同时兼容绝大多数数据库成为通用的数据库中间件。1.4 版本以后 完全的脱离基本cobar内核,结合Mycat集群管理、自动扩容、智能优化,成为高性能的中间件。我们致力于开发高性能数据库中间而努力。永不收费,永不闭源,持续推动开源社区的发展。

Mycat吸引和聚集了一大批业内大数据和云计算方面的资深工程师,Mycat的发展壮大基于开源社区志愿者的持续努力,感谢社区志愿者的努力让Mycat更加强大,同时我们也欢迎社区更多的志愿者,特别是公司能够参与进来,参与Mycat的开发,一起推动社区的发展,为社区提供更好的开源中间件。

Mycat还不够强大,Mycat还有很多不足,欢迎社区志愿者的持续优化改进。

核心特性

支持SQL92标准

遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理。

基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群。

支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster

基于Nio实现,有效管理线程,高并发问题。

支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数。

支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join。

支持通过全局表,ER关系的分片策略,实现了高效的多表join查询。

支持多租户方案。

支持分布式事务(弱xa)。

支持全局序列号,解决分布式下的主键生成问题。

分片规则丰富,插件化开发,易于扩展。

强大的web,命令行监控。

支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨杉。

支持密码加密

支持服务降级

支持IP白名单

支持SQL黑名单、sql注入攻击拦截

支持分表(1.6)

集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版)。

环境准备

要是按照上面的分片规划,搞三个分片的话,比较麻烦,这里偷懒,搞俩意思一下就完了,经过我深思熟虑之后,搞成这样的架构(如果是虚拟机的话,建议4核4G):

image

这个架构学习起来比较方便,基本上所有的操作都在db01上。

主从和分片规划

节点间的主从复制规划:

# 被箭头指向的是主库
10.0.0.204:3307	<---> 10.0.0.205:3307    # 两个3307互为主从
10.0.0.204:3309 ----> 10.0.0.204:3307
10.0.0.205:3309 ----> 10.0.0.205:3307

10.0.0.204:3308	<---> 10.0.0.205:3308    # 两个3308互为主从
10.0.0.204:3310 ----> 10.0.0.204:3308
10.0.0.205:3310 ----> 10.0.0.205:3308

分片规划:

# shard1
Master: 		10.0.0.204:3307		Slave: 10.0.0.204:3309
Standby Master: 10.0.0.205:3307		Slave: 10.0.0.205:3309

# shard2
Master: 		10.0.0.204:3308		Slave: 10.0.0.204:3310
Standby Master: 10.0.0.205:3308		Slave: 10.0.0.205:3310

MySQL多实例安装

本篇的环境依赖单机多实例环境

1. 单机多实例配置

后续操作依赖单机多实例环境,配置单机多实例参考:https://www.cnblogs.com/Neeo/articles/13527500.html

2. 重置多实例配置

如果你的多实例环境刚配置好,就跳过这一步。

如果你的多实例已经使用,就把对应的端口号下面的所有目录都删除了,然后停止当前正在运行的MySQL实例。

以下配置步骤,需要在两台虚拟机上都要配置。

# 停止正在运行的实例
pkill mysqld
netstat -lnp|grep 33
mv /etc/my.cnf /etc/my.cnf.bak

# 清空3307、3308、3309、3310的数据目录
rm -rf /data/mysql/33{07..10}/*

# 删了再创建回来,环境就干净了
mkdir -p /data/mysql/33{07..10}/{data,logs,backup}
mkdir -p /data/mysql/33{07..10}/logs/{errorlog,slowlog,binlog}
chown -R mysql:mysql /data/mysql/*

3. 初始化

以下配置步骤,需要在两台虚拟机上都要配置。

mysqld --initialize-insecure  --user=mysql --datadir=/data/mysql/3307/data --basedir=/opt/software/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/mysql/3308/data --basedir=/opt/software/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/mysql/3309/data --basedir=/opt/software/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/mysql/3310/data --basedir=/opt/software/mysql

4. 创建配置文件和service文件

这一步需要在两个节点中分别执行。

db01节点:

# -------------- 配置文件 ------------
cat > /data/mysql/3307/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3307/data
server_id=7
port=3307
socket=/data/mysql/3307/mysql.sock
log-error=/data/mysql/3307/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3307/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3307/mysql.sock
prompt="[\\d]> "
EOF

cat > /data/mysql/3308/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3308/data
server_id=8
port=3308
socket=/data/mysql/3308/mysql.sock
log-error=/data/mysql/3308/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3308/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3308/mysql
prompt="[\\d]> "
EOF

cat > /data/mysql/3309/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3309/data
server_id=9
port=3309
socket=/data/mysql/3309/mysql.sock
log-error=/data/mysql/3309/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3309/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3309/mysql.sock
prompt="[\\d]> "
EOF

cat > /data/mysql/3310/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3310/data
server_id=10
port=3310
socket=/data/mysql/3310/mysql.sock
log-error=/data/mysql/3310/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3310/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3310/mysql.sock
prompt="[\\d]> "
EOF


# -------------- service文件 ------------
cat  > /etc/systemd/system/mysqld3307.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3307/my.cnf
LimitNOFILE = 5000
EOF

cat  > /etc/systemd/system/mysqld3308.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3308/my.cnf
LimitNOFILE = 5000
EOF

cat  > /etc/systemd/system/mysqld3309.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3309/my.cnf
LimitNOFILE = 5000
EOF

cat  > /etc/systemd/system/mysqld3310.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3310/my.cnf
LimitNOFILE = 5000
EOF

systemctl daemon-reload

db02节点:

# -------------- 配置文件 ------------
cat > /data/mysql/3307/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3307/data
server_id=70
port=3307
socket=/data/mysql/3307/mysql.sock
log-error=/data/mysql/3307/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3307/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3307/mysql.sock
prompt="[\\d]> "
EOF

cat > /data/mysql/3308/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3308/data
server_id=80
port=3308
socket=/data/mysql/3308/mysql.sock
log-error=/data/mysql/3308/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3308/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3308/mysql.sock
prompt="[\\d]> "
EOF

cat > /data/mysql/3309/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3309/data
server_id=90
port=3309
socket=/data/mysql/3309/mysql.sock
log-error=/data/mysql/3309/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3309/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3309/mysql.sock
prompt="[\\d]> "
EOF

cat > /data/mysql/3310/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/opt/software/mysql
datadir=/data/mysql/3310/data
server_id=100
port=3310
socket=/data/mysql/3310/mysql.sock
log-error=/data/mysql/3310/logs/errorlog/mysql.log
secure-file-priv=/tmp
log_bin=/data/mysql/3310/logs/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

[mysql]
socket=/data/mysql/3310/mysql.sock
prompt="[\\d]> "
EOF

# -------------- service文件 ------------
cat  > /etc/systemd/system/mysqld3307.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3307/my.cnf
LimitNOFILE = 5000
EOF

cat  > /etc/systemd/system/mysqld3308.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3308/my.cnf
LimitNOFILE = 5000
EOF

cat  > /etc/systemd/system/mysqld3309.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3309/my.cnf
LimitNOFILE = 5000
EOF

cat  > /etc/systemd/system/mysqld3310.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=/opt/software/mysql/bin/mysqld --defaults-file=/data/mysql/3310/my.cnf
LimitNOFILE = 5000
EOF

systemctl daemon-reload

5. 启动实例

分别在两个节点启动实例。

db01:

chown -R mysql:mysql /data/mysql/*
systemctl start mysqld3307.service
systemctl start mysqld3308.service
systemctl start mysqld3309.service
systemctl start mysqld3310.service
netstat -lnp|grep 33
tcp6       0      0 :::3307                 :::*                    LISTEN      125406/mysqld       
tcp6       0      0 :::3308                 :::*                    LISTEN      125413/mysqld       
tcp6       0      0 :::3309                 :::*                    LISTEN      125420/mysqld       
tcp6       0      0 :::3310                 :::*                    LISTEN      125427/mysqld       
unix  2      [ ACC ]     STREAM     LISTENING     496928   125406/mysqld        /data/mysql/3307/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     496931   125420/mysqld        /data/mysql/3309/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     496934   125413/mysqld        /data/mysql/3308/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     496937   125427/mysqld        /data/mysql/3310/mysql.sock

db02:

chown -R mysql:mysql /data/mysql/*
systemctl start mysqld3307.service
systemctl start mysqld3308.service
systemctl start mysqld3309.service
systemctl start mysqld3310.service
netstat -lnp|grep 33
tcp6       0      0 :::3307                 :::*                    LISTEN      2220/mysqld         
tcp6       0      0 :::3308                 :::*                    LISTEN      2227/mysqld         
tcp6       0      0 :::3309                 :::*                    LISTEN      2332/mysqld         
tcp6       0      0 :::3310                 :::*                    LISTEN      2416/mysqld         
unix  2      [ ACC ]     STREAM     LISTENING     67174    2416/mysqld          /data/mysql/3310/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     66709    2332/mysqld          /data/mysql/3309/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     66620    2220/mysqld          /data/mysql/3307/mysql.sock
unix  2      [ ACC ]     STREAM     LISTENING     66313    2227/mysqld          /data/mysql/3308/mysql.sock

6. 创建密码

默认的初始的root@'localhost'的密码为空,我们给每个实例都创建一个默认的密码,下面的命令在两个节点中都要执行:

mysql -S /data/mysql/3307/mysql.sock -e "grant all on *.* to root@'%' identified by '123' with grant option;"
mysql -S /data/mysql/3308/mysql.sock -e "grant all on *.* to root@'%' identified by '123' with grant option;"
mysql -S /data/mysql/3309/mysql.sock -e "grant all on *.* to root@'%' identified by '123' with grant option;"
mysql -S /data/mysql/3310/mysql.sock -e "grant all on *.* to root@'%' identified by '123' with grant option;"

7. 测试

db01:

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "select @@server_id"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "select @@server_id"
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "select @@server_id"
mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "select @@server_id"

[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "select @@server_id"
3310/mysql.sock -e "select @@server_id"mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           8 |
+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          10 |
+-------------+

db02:

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "select @@server_id"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "select @@server_id"
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "select @@server_id"
mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "select @@server_id"

[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "select @@server_id"
3310/mysql.sock -e "select @@server_id"mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          70 |
+-------------+
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          80 |
+-------------+
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          90 |
+-------------+
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "select @@server_id"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|         100 |
+-------------+

8. 恢复3306的配置文件

每个节点共有5个实例,但我们这个章节中,只会用到3307、3308、3309、3310四个实例。而3306实例停机待命。

两个节点都执行:

mv /etc/my.cnf.bak /etc/my.cnf

OK了,两个节点,共8个实例已成功运行。

主从环境搭建

现在两个节点8个实例准备到位了。

我们开始着手建立主从关系。

1. 主从和分片规划

节点间的主从复制规划:

# 被箭头指向的是主库
10.0.0.204:3307	<---> 10.0.0.205:3307    # 两个3307互为主从
10.0.0.204:3309 ----> 10.0.0.204:3307
10.0.0.205:3309 ----> 10.0.0.205:3307

10.0.0.204:3308	<---> 10.0.0.205:3308    # 两个3308互为主从
10.0.0.204:3310 ----> 10.0.0.204:3308
10.0.0.205:3310 ----> 10.0.0.205:3308

分片规划:

# shard1
Master: 		10.0.0.204:3307		Slave: 10.0.0.204:3309
Standby Master: 10.0.0.205:3307		Slave: 10.0.0.205:3309

# shard2
Master: 		10.0.0.204:3308		Slave: 10.0.0.204:3310
Standby Master: 10.0.0.205:3308		Slave: 10.0.0.205:3310

2. 主库创建专用复制用户

分别在两个节点的3307实例创建专用的复制用户。

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"

3. 按照之前的主从规划,进行主从关系构建

先来处理shard1分片。这个分片中,我们只需要做:

# 将两个从库分别指向自己的主库
10.0.0.204:3309 ----> 10.0.0.204:3307
10.0.0.204:3310 ----> 10.0.0.204:3308

# db01的两个主库和db02的两个主库是互为主从关系,这里也要进行主从关系绑定
10.0.0.204:3307	----> 10.0.0.205:3307
10.0.0.204:3308	----> 10.0.0.205:3308

# 下面操作在db01中执行
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.204', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "show slave status\G"

mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.204', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "show slave status\G"

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.205', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave status\G"

mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.205', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "show slave status\G"

再来处理shard2,也就是db02中,需要做这些操作:

# 将两个从库分别指向自己的主库
10.0.0.205:3309 ----> 10.0.0.205:3307
10.0.0.205:3310 ----> 10.0.0.205:3308

# 将db02的两个主库和db01的主库建立主从关系
10.0.0.205:3307 ----> 10.0.0.204:3307
10.0.0.205:3308 ----> 10.0.0.204:3308

# 下面操作在db02中执行
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.205', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "show slave status\G"

mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.205', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "show slave status\G"

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.204', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave status\G"

mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.204', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "start slave;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "show slave status\G"

4. 确认主从状态是否构建成功

db01中操作:

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


[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave hosts;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|         9 |      | 3309 |         7 | 77f7db1c-ba09-11eb-a16e-000c298ffc47 |
|        70 |      | 3307 |         7 | dddf3daa-ba09-11eb-9f49-000c294bb55c |
+-----------+------+------+-----------+--------------------------------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "show slave hosts;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|        10 |      | 3310 |         8 | 815e5440-ba09-11eb-a345-000c298ffc47 |
|        80 |      | 3308 |         8 | df7fef58-ba09-11eb-9fa4-000c294bb55c |
+-----------+------+------+-----------+--------------------------------------+

[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

db02中操作:

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


[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave hosts;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|         7 |      | 3307 |        70 | 75735936-ba09-11eb-9d61-000c298ffc47 |
|        90 |      | 3309 |        70 | e12f1b40-ba09-11eb-a02a-000c294bb55c |
+-----------+------+------+-----------+--------------------------------------+
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "show slave hosts;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|         8 |      | 3308 |        80 | 76b5e615-ba09-11eb-9f45-000c298ffc47 |
|       100 |      | 3310 |        80 | e38aeec8-ba09-11eb-a191-000c294bb55c |
+-----------+------+------+-----------+--------------------------------------+

[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3309/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
[root@db02 ~]# mysql -uroot -p123 -S /data/mysql/3310/mysql.sock -e "show slave status\G"|grep Yes
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

OK,确认完毕,主从关系都正常。

数据准备

https://dev.mysql.com/doc/index-other.html

world.sql链接:https://pan.baidu.com/s/1D5KT5AWPlrn9gyPiCtyCSQ 提取码:bo4w

练习用数据库导入

为了后续方便练习,这里需要提前导入world数据库。

由于我们的主从环境已经搭建成功,所以,只需要在两个master节点导入数据即可。

db01执行:

wget https://downloads.mysql.com/docs/world.sql.zip
unzip world.sql
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock <world.sql
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock <world.sql

OK,数据有了。

Mycat安装

https://github.com/MyCATApache/Mycat-Server/releases

Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz 链接:https://pan.baidu.com/s/1-Yj6xteieuW90O-Imshk-g 提取码:eyjl

这里,我将mycat安装到db01节点上,当然,你也可以将mycat单独安装到一个节点上。

安装Java环境

参考:https://www.cnblogs.com/Neeo/articles/11954283.html

sudo yum install java-1.8.0-openjdk-devel -y

安装Mycat

下载安装:

wget https://github.com/MyCATApache/Mycat-Server/releases/download/Mycat-server-1675-release/Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz
tar xf Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz
rm -rf Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz

[root@db01 software]# wget https://github.com/MyCATApache/Mycat-Server/releases/download/Mycat-server-1675-release/Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz
[root@db01 software]# tar xf Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz
[root@db01 software]# rm -rf Mycat-server-1.6.7.5-release-20200422133810-linux.tar.gz && ls
mycat mysql
[root@db01 software]# cd mycat/
[root@db01 mycat]# ll
total 12
drwxr-xr-x. 2 root root  190 May 28 14:51 bin
drwxrwxrwx. 2 root root    6 Apr 15  2020 catlet
drwxrwxrwx. 4 root root 4096 May 28 14:51 conf
drwxr-xr-x. 2 root root 4096 May 28 14:51 lib
-rwxrwxrwx. 1 root root  227 Apr 22  2020 version.txt
[root@db03 mycat]# mkdir -p /opt/software/mycat/logs   # 安装目录中需要有个logs目录,如果没有就手动创建一个,避免后续报错,这里你也可以不创建,后面遇到报错再创键

解压后自动命名成mycat,这个目录就是mycat的安装目录,其中所有的命令都在bin目录下,所以,为了后续方便调用,我们将bin目录添加到环境变量:

[root@db01 mycat]# cd bin/
[root@db01 bin]# pwd
/opt/software/mycat/bin
[root@db01 bin]# vim /etc/profile

export PATH=/opt/software/mycat/bin:$PATH

[root@db01 bin]# source /etc/profile

有了环境变量,就可以在任意目录管理mycat了:

mycat start 启动
mycat stop 停止
mycat console 前台运行
mycat install 添加到系统自动启动(暂未实现)
mycat remove 取消随系统自动启动(暂未实现)
mycat restart 重启服务
mycat pause 暂停
mycat status 查看启动状态

启动Mycat

这里我们可以使用mycat console命令来看启动时,是否会遇到报错:

[root@db01 bin]# mycat console
Running Mycat-server...
wrapper  | ERROR: Could not write pid file /opt/software/mycat/logs/mycat.pid: No such file or directory

果然报错了,原因是在启动时,mycat需要在安装目录下的logs目录中创建mycat.pid文件,但很明显,我们这里是没有logs目录的,那就手动给它创建一个呗:

[root@db01 bin]# mkdir -p /opt/software/mycat/logs
[root@db01 bin]# mycat console
Running Mycat-server...
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
jvm 1    |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
jvm 1    | 
jvm 1    | MyCAT Server startup successfully. see logs in logs/mycat.log

OK,可以了,现在ctrl+C关闭了,然后我们后续都是用后台管理命令:

[root@db01 bin]# mycat start
Starting Mycat-server...
[root@db01 bin]# mycat status
Mycat-server is running (7179).
[root@db01 bin]# netstat -lnp|grep 8066
tcp6       0      0 :::8066                 :::*                    LISTEN      7181/java           
[root@db01 bin]# netstat -lnp|grep 9066
tcp6       0      0 :::9066                 :::*                    LISTEN      7181/java   

mycat对外提供服务的端口是8066;管理端口是9066。

Mycat目录结构说明

mycat/
	-- bin
		- mycat  管理命令:启动/关闭/重启
    -- conf
    	- schema.xml	主配置文件,节点...
    	- rule.xml		分片策略相关
    	- server.xml	mycat相关配置文件
    -- logs
    	- mycat.log		日志文件
    	- wrapper.log	专门用于记录启动的日志文件

Mycat连接

Mycat提供了8066端口用于外部连接,而连接则可以通过MySQL的客户端mysql工具进行连接,也可以通过Navicat等远程工具进行连接。

MySQL客户端进行连接,这也是我将Mycat和MySQL多实例部署到一起的原因,因为如果Mycat单独不部署的话,还要在单独安装个MySQL(其实使用的自带的mysql客户端),这无疑多费事儿......

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "show databases;" 
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+

Navicat进行连接:

image

是不是很方便!!!

初始基础配置文件

后续的关于mycat的管理基本上都是对于配置文件的处理,所以,我们首先将原配置文件备份一下,避免直接修改,导致最后改的面目全非。

db04中执行:

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.bak

[root@db01 ~]# mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.bak

然后我这里手动写个最简单的配置:

cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "world" />  
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    </dataHost>  
</mycat:schema>
EOF
mycat restart

其中:

  • schemaTESTDB是逻辑库,当请求访问TESTDB时,会默认将请求转发到dataNode节点RedShard
  • dataNode指向的是world数据库(这个库必须真实存在才行),同时对dataHost做了进一步的定义。
  • dataHost中定义了读写分离交给具体的数据库实例来处理。

通过上面层层定义和嵌套的结构,方便后续的扩展配置。另外,具体的参数,后续再慢慢展开聊。

读写分离+MHA

有了配置文件,我们可以尝试连接到mycat了。

# 借助mysql的客户端工具mysql,通过mycat默认的账号和密码,连接到mycat
# TESTDB这个逻辑库,相当于我们的world数据库
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "show databases;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+

# 可以use进去然后show命令确认
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;show tables;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------------+
| Tables_in_world |
+-----------------+
| city            |
| country         |
| countrylanguage |
+-----------------+

来做个读写分离测试,按照我们的schema.xml文件的配置,读应该交给3309来处理,而写应该交给3307来处理:

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+

结果符合预期。

当然,只想使用读写分离的话,atlas就够了。

我们再来聊聊配置文件中的一些细节。

写节点宕掉,读节点也完了

<?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="RedShard"> 
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "world" />  
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    </dataHost>  
</mycat:schema>

如上配置,读节点readHost的配置是在写节点writeHost配置中的。这意味着当写节点宕掉了,读节点也不能用了。

来做个测试:

# 现在,读写都正常

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+

# 我们将写实例宕掉(等会再测试),然后再测试,发现读写都不行了
[root@db01 ~]# systemctl stop mysqld3307
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1184 (HY000) at line 1: java.net.ConnectException: Connection refused
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1184 (HY000) at line 1: java.net.ConnectException: Connection refused
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1184 (HY000) at line 1: java.net.ConnectException: Connection refused

# 现在,我们再重启写实例,然后再测试,又都恢复正常了
[root@db01 ~]# systemctl start mysqld3307.service 
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+

现在,演示效果符合预期,但是问题来了, 宕掉不能不管啊!我们之前也说过不是可以搞什么MHA么,那么能不能让MHA和Mycat结合起来。

答案是可以的, 那么这个架构长这样:

image

当写实例宕了之后,MHA会自动进行故障转移。

当然,上述架构维护成本大,需要管理两套MHA环境。

有没有更简单的实现呢?答案也是有的,Mycat也想到了这些,那就是按照我们之前那个主从规划部分的那个架构图来操作,将Standby Master给它利用上。

怎么搞呢?其实还是在配置文件中实现:

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.rw
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "world" />  
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost> 
    </dataHost>  
</mycat:schema>
EOF
mycat restart


经过如上配置,我们将之前主从复制架构图的红色部分都利用了,且是一主三从的架构,也就是一个write,三个read,来测试下:

# 写操作会交给master
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"

# 读操作会被三个slave轮询分担,多重复几次就会看到效果了
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          70 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          90 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+

效果符合预期。

我们再来探讨一些当前架构的关于MHA的细节,按照此时的配置文件来说:

  • db01的3307是master,负责write,当该master宕掉后,它的slave3309也会"宕"掉。
  • 如果此时的master宕掉,mycat会自动的将db02的standby master3307升级为master,负责write,它的slave3309负责read,此时实现了高可用。
  • 当db01的3307故障排除后,重新加入到这个架构中去后,mycat会把它设定为standby master,db01的3309成为它的slave。

来做个测试,就是将db01的3307节点宕掉,预期:db02的3307节点负责write,3309负责read。

# 宕掉db01的3307
[root@db01 ~]# systemctl stop mysqld3307

# 等会再测试,给mycat一点故障切换时间
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          90 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          70 |
+-------------+

符合预期。

当db01的3307恢复正常后,预期:db02的3307节点负责write不变,由db02的3309和db01的3307、3309三个节点轮询负责read。

# 重启db01的3307
[root@db01 ~]# systemctl start mysqld3307.service 

# 等会再测试,给mycat一点故障切换时间
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "begin;select @@server_id;commit;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          70 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          90 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "select @@server_id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           9 |
+-------------+

符合预期。

再探配置文件

通过上面的基础配置文件和一些示例操作之后,我们对mycat的配置文件有了大致的了解,这里再来介绍一下配置文件中的一些属性。

<?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="RedShard"> 
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "world" />  
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost> 
    </dataHost>  
</mycat:schema>

其中:

  • schema.dataNode,如果配置了多个dataNode话,那这里的dataNode就是默认的,也就是没有进行配置的表,走默认的dataNode
  • balance,读操作的负载均衡配置:
    • balance="0",不开启读写分离机制,所有的读操作都发送到当前可用的writeHost节点上。
    • balance="1",默认值,全部的readHost和Standby Master轮询负载read操作。
    • balance="2",所有读操作都随机在writeHost和readHost上分发。适用于读多写少的业务场景。
  • writeType,写操作的负载均衡配置:
    • writeType="0",所有的写操作都发送到配置的第一个writeHost节点。当第一个writeHost挂了,切换到第二个writeHost上。
    • writeType="1",所有的写操作随机的发送到每一个writeHost上。不推荐使用,性能提升不大,反而会带来一些问题,比如写的主键冲突。
  • switchType,MHA切换配置:
    • switchType="-1",表示不自动切换。
    • switchType="1",默认值,自动切换。
    • switchType="2",根据MySQL的主从复制状态决定是否切换,心跳语句为show slave status
  • maxCon,最大的并发连接数。
  • minCon,mycat为read节点默认设置的连接池的数量。
  • tempReadHostAvailable="1",这个参数我们上面的配置文件中没有设置,它是应用于一主一从的架构,当主库宕了,从库临时负责读和写。但我们的此时的架构可以使用更好的MHA来做切换,所以这个参数对我们当前架构,没有啥用。
  • <heartbeat>select user()</heartbeat>,监测心跳。
  • sqlMaxLimit="100",在分表配置中,用于结果的分页,暂时我们没有用到。

垂直分表

垂直分表通常适用于将原来多个繁忙的表从一个数据库中,拆分到不同的服务器的MySQL中,从而减轻服务器压力。当然,虽然表被拆分到不同的数据库中,但它们逻辑上还是处于一个数据库中。

image

如上图,核心库core中的两个核心表user和order表,由于太繁忙而导致MySQL压力太大,从而要进行架构的重新设计,那就是将这两个表分别拆分到不同的数据库中,即db01中的3307分片存储user,3308分片存储order表,同时又可以使用mycat对其分别作读写分离和MHA。

来看看如何进行配置。

1. 调整mycat的schema.xml配置文件

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.ha
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
    <table name="user_t" dataNode="RedShard" />
    <table name="order_t" dataNode="GreenShard" />
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "core" /> 
    <dataNode name="GreenShard" dataHost="green" database= "core" /> 
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost>
    </dataHost>
    <dataHost name="green" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="green_master" url="10.0.0.204:3308" user="root" password="123"> 
            <readHost host="green_slave" url="10.0.0.204:3310" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="green_standby_master" url="10.0.0.205:3308" user="root" password="123"> 
            <readHost host="green_standby_slave" url="10.0.0.205:3310" user="root" password="123" /> 
    </writeHost>
    </dataHost> 
</mycat:schema>
EOF
mycat restart

如上配置:红色分片存储user表('user_t');绿色分片存储order表('order_t'),但它们同属于逻辑上的数据库core。

2. 创建测试库和测试表

如果是拆分已存在的表,需要手动通过备份恢复的方式将表分别恢复到不同的分片中,这里呢,由于环境是新的,我们手动的在不同的分片上进行创建即可。

# 在红色分片创建数据库core和user_t
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create database core;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.user_t(id int, name varchar(32)) charset utf8;"

# 在蓝色分片创建数据库core和order_t
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create database core;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.order_t(id int, name varchar(32)) charset utf8;"

3. 通过连接mycat进行测试

# order和user这两张表,在业务层面还是同属于一个数据库,但其实它们已经分布在了不同的shard上了
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;show tables;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------+
| Tables_in_core |
+----------------+
| order_t        |
| user_t         |
+----------------+


mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into user_t values(1, 'zhangkai'), (2, 'likai');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into order_t values(1, 'zhangkai'), (2, 'likai');"

注意,TESTDB相当于是core这个数据库。插入语句都一样,但是它们已经被分别插入到不同的shard上了。

4. 查询测试

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from user_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangkai |
|    2 | likai    |
+------+----------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from order_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangkai |
|    2 | likai    |
+------+----------+

查询语句也没问题。

垂直分表在一定程度上解决了MySQL的性能瓶颈问题,但是它仍然解决不了所有的问题。

比如,对于某个特大、热点表来说,操作起来的仍然比较慢,针对这种数据表,我们就要考虑再次对其拆分了——水平拆分。

水平拆分

水平拆分是Mycat的核心功能,针对的是记录级别的,也就是单表记录:

  • 记录行数非常多。大约800W-1000W就要进行分表了,当然了也要根据具体的业务来决定。
  • 访问非常频繁。

对于这样的表来说,要进行分片,其目的:

  • 将记录进行分布存储。
  • 提供均衡的访问路由。

那如何对表进行分片?Mycat提供了几种分片策略来适用于不同的业务场景:

  • range分片,按照范围分片,1-500W,500-1000W。
  • 取模分片,对id对分片总数进行取模运算,得到结果就是改记录要存储的分片。
  • 枚举,比如按照性别进行分片,男性存储到分片1上,女性存储到分片2上,不祥的也要处理,那就是走默认配置;同样也适用于手机号,比如按照归属地进行分片。
  • 按照哈希进行分片。
  • 按照时间进行分片,适用于流水相关的业务。

上面都是针对单表的分片,对于有join需求的,还提供了:

  • 全局表。
  • E-R分片。

一起来看看常用的分片策略怎么配置的吧!

范围分片(auto-sharding-long)

1. 准备表

我们需要在两个分片上将演示用的表提前创建出来,因为core已经存在,这里直接在其内创建goods表即可。

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.goods_t(id int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.goods_t(id int primary key auto_increment, name varchar(32)) charset utf8;"

2. mycat配置

配置schema.xml

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.ve
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
    <table name="user_t" dataNode="RedShard" />
    <table name="order_t" dataNode="GreenShard" />
    <!-- 其他的配置不变,就添加下面一行配置即可 -->
    <table name="goods_t" dataNode="RedShard,GreenShard" rule="auto-sharding-long" />
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "core" /> 
    <dataNode name="GreenShard" dataHost="green" database= "core" /> 
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost>
    </dataHost>
    <dataHost name="green" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="green_master" url="10.0.0.204:3308" user="root" password="123"> 
            <readHost host="green_slave" url="10.0.0.204:3310" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="green_standby_master" url="10.0.0.205:3308" user="root" password="123"> 
            <readHost host="green_standby_slave" url="10.0.0.205:3310" user="root" password="123" /> 
    </writeHost>
    </dataHost> 
</mycat:schema>
EOF

dataNode="RedShard,GreenShard"表示将数据按照rule="auto-sharding-long"规则分布在红绿两个分片上,红色分片的序号是0,因为它在配置文件中的位置比绿色分片高,所有绿色分片的序号是1,依此类推.........

配置rule.xml,由于我们这里还是按照id来做范围分片,所以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>

配置autopartition-long.txt,创建几千万的数据耗时太长,这里仅作演示,指定小范围即可:

mv /opt/software/mycat/conf/autopartition-long.txt /opt/software/mycat/conf/autopartition-long.txt.bak
cat > /opt/software/mycat/conf/autopartition-long.txt <<EOF
0-10=0
11-20=1
EOF

mycat restart

我们在range分片的规则中设定记录的范围0-10在红色分片上;11-20在绿色分片上。

3. 添加记录

添加记录的话,可以直接通过mycat进行添加:

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into goods_t(id, name) values
(1, 'zhangkai1'), 
(3, 'zhangkkai3'), 
(5, 'zhangkkai5'), 
(7, 'zhangkkai7'), 
(10, 'zhangkkai10'), 
(11, 'zhangkkai11'), 
(13, 'zhangkkai13'), 
(15, 'zhangkkai15');"

4. 查看结果

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from goods_t;"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from goods_t order by id;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from goods_t;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from goods_t;"


# 查询结果是两个分片的聚合后的结果
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from goods_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-------------+
| id | name        |
+----+-------------+
| 11 | zhangkkai11 |
| 13 | zhangkkai13 |
| 15 | zhangkkai15 |
|  1 | zhangkai1   |
|  3 | zhangkkai3  |
|  5 | zhangkkai5  |
|  7 | zhangkkai7  |
| 10 | zhangkkai10 |
+----+-------------+

# 排下序就跟单表操作是一摸一样的了
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from goods_t order by id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-------------+
| id | name        |
+----+-------------+
|  1 | zhangkai1   |
|  3 | zhangkkai3  |
|  5 | zhangkkai5  |
|  7 | zhangkkai7  |
| 10 | zhangkkai10 |
| 11 | zhangkkai11 |
| 13 | zhangkkai13 |
| 15 | zhangkkai15 |
+----+-------------+

# 从mycat中查看跟单表操作一样,但实际上goods表已经被按照范围存储到不同的分片上了
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from goods_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-------------+
| id | name        |
+----+-------------+
|  1 | zhangkai1   |
|  3 | zhangkkai3  |
|  5 | zhangkkai5  |
|  7 | zhangkkai7  |
| 10 | zhangkkai10 |
+----+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from goods_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-------------+
| id | name        |
+----+-------------+
| 11 | zhangkkai11 |
| 13 | zhangkkai13 |
| 15 | zhangkkai15 |
+----+-------------+

结果符合预期。

取模分片(mod-long)

取模分片其实很好理解,那就是根据记录的id对分片的总数进行取模(取余数)运算,运算结果就是该记录要存储的分片,比如我们当前的环境是是2个分片,那么:

id	  分片总数	该记录将被存储到的分片
1	%	2	=	1
16	%	2	=	0
31	%	2	=	1
46	%	2	=	0
61	%	2	=	1
76	%	2	=	0
91	%	2	=	1
106	%	2	=	0
121	%	2	=	1
136	%	2	=	0
151	%	2	=	1

比如要将下面的数据插入到我们当前的mycat环境中:

insert into mod_long_t(id, name) values
(1, "zhangkai1"), (16, "zhangkai16"),
(31, "zhangkai31"), (46, "zhangkai46"),
(61, "zhangkai61"), (76, "zhangkai61"),
(91, "zhangkai91"), (106, "zhangkai106"),
(121, "zhangkai121"), (136, "zhangkai136"),
(151, "zhangkai151");

这些记录的分布如下图所示:

image

来看配置过程。

1. 创建表

还是在core库中先将表创建出来:

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.mod_long_t(id int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.mod_long_t(id int primary key auto_increment, name varchar(32)) charset utf8;"

2. mycat配置

配置schema.xml

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.range_lang
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
    <table name="user_t" dataNode="RedShard" />
    <table name="order_t" dataNode="GreenShard" />
    <!-- 其他的配置不变,就添加下面一行配置即可 -->
    <table name="mod_long_t" dataNode="RedShard,GreenShard" rule="mod-long" />
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "core" /> 
    <dataNode name="GreenShard" dataHost="green" database= "core" /> 
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost>
    </dataHost>
    <dataHost name="green" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="green_master" url="10.0.0.204:3308" user="root" password="123"> 
            <readHost host="green_slave" url="10.0.0.204:3310" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="green_standby_master" url="10.0.0.205:3308" user="root" password="123"> 
            <readHost host="green_standby_slave" url="10.0.0.205:3310" user="root" password="123" /> 
    </writeHost>
    </dataHost> 
</mycat:schema>
EOF

然后,配置rule.xml

vim /opt/software/mycat/conf/rule.xml

<!-- mod-long规则,也是根据id进行分片,这里都无需改动 -->
<tableRule name="mod-long">
	<rule>
		<columns>id</columns>
		<algorithm>mod-long</algorithm>
	</rule>
</tableRule>

<!-- 根据上面的规则,下拉找到要修改mod-long函数 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
	<!-- how many data nodes,我们当前有两个分片,所以写2 -->
	<property name="count">2</property>
</function>

<!-- 修改完毕,重启mycat -->
mycat restart

3. 插入记录

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e 'use TESTDB;insert into mod_long_t(id, name) values
(1, "zhangkai1"), (16, "zhangkai16"),
(31, "zhangkai31"), (46, "zhangkai46"),
(61, "zhangkai61"), (76, "zhangkai61"),
(91, "zhangkai91"), (106, "zhangkai106"),
(121, "zhangkai121"), (136, "zhangkai136"),
(151, "zhangkai151");'

4. 查看结果

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from mod_long_t;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from mod_long_t;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from mod_long_t;"

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from mod_long_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+-------------+
| id  | name        |
+-----+-------------+
|   1 | zhangkai1   |
|  31 | zhangkai31  |
|  61 | zhangkai61  |
|  91 | zhangkai91  |
| 121 | zhangkai121 |
| 151 | zhangkai151 |
|  16 | zhangkai16  |
|  46 | zhangkai46  |
|  76 | zhangkai61  |
| 106 | zhangkai106 |
| 136 | zhangkai136 |
+-----+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from mod_long_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+-------------+
| id  | name        |
+-----+-------------+
|  16 | zhangkai16  |
|  46 | zhangkai46  |
|  76 | zhangkai61  |
| 106 | zhangkai106 |
| 136 | zhangkai136 |
+-----+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from mod_long_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+-------------+
| id  | name        |
+-----+-------------+
|   1 | zhangkai1   |
|  31 | zhangkai31  |
|  61 | zhangkai61  |
|  91 | zhangkai91  |
| 121 | zhangkai121 |
| 151 | zhangkai151 |
+-----+-------------+

结果符合预期。

枚举分片

枚举也非常简单,就是根据枚举类型来存储,比如一张关于手机号的表,其中不同的手机号有不同的归属地,那么就可以根据归属地来进行分片。

insert into phone_t(id, location, tel) values
(1, 'beijing', '18144830318'),
(2, 'shanghai', '14767801068'),
(3, 'beijing', '18228896265'),
(4, 'shanghai', '14570778582'),
(5, 'henan', '15704338402');

这些记录根据枚举分片后的分布如下图所示:

image

这里有要注意的地方,就是红色分片除了要要存储归属地是北京的之外,也是默认的存储分片,在当前环境中,绿色分片只存储归属地是上海的,其他的都要存储到红色分片上去,后续在配置中可以进行配置。

来看配置过程。

1. 创建表

还是在core中创建表:

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.phone_t(id int primary key auto_increment, location varchar(32), tel varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.phone_t(id int primary key auto_increment, location varchar(32), tel varchar(32)) charset utf8;"

2. mycat配置

schema.xml

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.mod_lang
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
    <table name="user_t" dataNode="RedShard" />
    <table name="order_t" dataNode="GreenShard" />
    <!-- 其他的配置不变,就添加下面一行配置即可 -->
    <table name="phone_t" dataNode="RedShard,GreenShard" rule="sharding-by-intfile" />
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "core" /> 
    <dataNode name="GreenShard" dataHost="green" database= "core" /> 
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost>
    </dataHost>
    <dataHost name="green" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="green_master" url="10.0.0.204:3308" user="root" password="123"> 
            <readHost host="green_slave" url="10.0.0.204:3310" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="green_standby_master" url="10.0.0.205:3308" user="root" password="123"> 
            <readHost host="green_standby_slave" url="10.0.0.205:3310" user="root" password="123" /> 
    </writeHost>
    </dataHost> 
</mycat:schema>
EOF

rule.xml

vim /opt/software/mycat/conf/rule.xml

<!-- 根据归属地location进行分片,所以修改columns字段即可 -->
<tableRule name="sharding-by-intfile">
    <rule>
        <columns>location</columns>
        <algorithm>hash-int</algorithm>
    </rule>
</tableRule>

<!-- 根据上面的规则,下拉找到要修改hash-int函数 -->
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
    <!-- 文件名可以自定义 -->
    <property name="mapFile">partition-hash-int.txt</property>
    <!-- type类型:1表示字符串,0表示int -->
    <property name="type">1</property>
    <!-- defaultNode 默认的节点 ,小于0表示不设置默认节点,大于等于0表示设置默认节点 -->
    <property name="defaultNode">0</property>
</function>

通过hash-int函数中的property参数,进而修改partition-hash-int.txt

cat > /opt/software/mycat/conf/partition-hash-int.txt <<EOF
beijing=0
shanghai=1
DEFAULT_NODE=0
EOF

mycat restart

3. 插入记录

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into phone_t(id, location, tel) values
(1, 'beijing', '18144830318'),
(2, 'shanghai', '14767801068'),
(3, 'beijing', '18228896265'),
(4, 'shanghai', '14570778582'),
(5, 'henan', '15704338402');"

4. 查看结果

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from phone_t;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from phone_t;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from phone_t;"

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from phone_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+----------+-------------+
| id | location | tel         |
+----+----------+-------------+
|  2 | shanghai | 14767801068 |
|  4 | shanghai | 14570778582 |
|  1 | beijing  | 18144830318 |
|  3 | beijing  | 18228896265 |
|  5 | henan    | 15704338402 |
+----+----------+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from phone_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+----------+-------------+
| id | location | tel         |
+----+----------+-------------+
|  1 | beijing  | 18144830318 |
|  3 | beijing  | 18228896265 |
|  5 | henan    | 15704338402 |
+----+----------+-------------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from phone_t;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+----------+-------------+
| id | location | tel         |
+----+----------+-------------+
|  2 | shanghai | 14767801068 |
|  4 | shanghai | 14570778582 |
+----+----------+-------------+

归属地为北京的,被分配到了红色分片;归属地为上海的,被分配到了绿色分片;其他的被分配到了默认的节点,这里也是红色分片。

结果符合预期。

全局表

使用场景:

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

也就是遇到多张表(a、b)都有联同一张表(g)的需求,那么就将这张表分布在各个分片中,在同一个分片内进行join,从而提升性能。

image

来看配置过程。

1. 创建表

还是在core中创建表:

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.a(id int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.b(id int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.g(id int primary key auto_increment, name varchar(32)) charset utf8;"

mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.a(id int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.b(id int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.g(id int primary key auto_increment, name varchar(32)) charset utf8;"

2. mycat配置

schema.xml

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.en
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
    <table name="user_t" dataNode="RedShard" />
    <table name="order_t" dataNode="GreenShard" />
    <!-- 配置a、b表为取模分片,当然也可以指定其他分片策略 -->
    <table name="a" dataNode="RedShard,GreenShard" rule="mod-long" />
    <table name="b" dataNode="RedShard,GreenShard" rule="mod-long" />
    <!-- 声明g表为全局表,主键是id,类型是global,分布在所有分片上 -->
    <table name="g" primaryKey="id"  type="global" dataNode="RedShard,GreenShard" /> 
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "core" /> 
    <dataNode name="GreenShard" dataHost="green" database= "core" /> 
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost>
    </dataHost>
    <dataHost name="green" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="green_master" url="10.0.0.204:3308" user="root" password="123"> 
            <readHost host="green_slave" url="10.0.0.204:3310" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="green_standby_master" url="10.0.0.205:3308" user="root" password="123"> 
            <readHost host="green_standby_slave" url="10.0.0.205:3310" user="root" password="123" /> 
    </writeHost>
    </dataHost> 
</mycat:schema>
EOF

rule.xml

vim /opt/software/mycat/conf/rule.xml

<!-- mod-long规则,也是根据id进行分片,这里都无需改动 -->
<tableRule name="mod-long">
	<rule>
		<columns>id</columns>
		<algorithm>mod-long</algorithm>
	</rule>
</tableRule>

<!-- 根据上面的规则,下拉找到要修改mod-long函数 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
	<!-- how many data nodes,我们当前有两个分片,所以写2 -->
	<property name="count">2</property>
</function>

<!-- 修改完毕,重启mycat -->
mycat restart

3. 插入记录

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into a(id, name) values(1, 'a1'), (2, 'a2'), (3, 'a3'), (4, 'a4');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into b(id, name) values(1, 'b1'), (2, 'b2'), (3, 'b3'), (4, 'b4');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into g(id, name) values(1, 'g1'), (2, 'g2'), (3, 'g3'), (4, 'g4');"

4. 查看结果

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from a;"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from b;"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from g;"

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from a;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from b;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from g;"

mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from a;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from b;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from g;"

# 对于a、b表来说,正常返回所有值,这没问题
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from a;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | a1   |
|  3 | a3   |
|  2 | a2   |
|  4 | a4   |
+----+------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from b;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | b1   |
|  3 | b3   |
|  2 | b2   |
|  4 | b4   |
+----+------+

# 对于全局表g来说,随机从某个分片返回结果,这也没问题,因为g表在所有分片上的数据是一致的
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from g;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | g1   |
|  2 | g2   |
|  3 | g3   |
|  4 | g4   |
+----+------+

# 对于红色分片来说,a、b表按模存储结果也没问题,g表返回全部数据也没问题
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from a;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  2 | a2   |
|  4 | a4   |
+----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from b;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  2 | b2   |
|  4 | b4   |
+----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from g;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | g1   |
|  2 | g2   |
|  3 | g3   |
|  4 | g4   |
+----+------+

# 对于绿色分片来说,a、b表按模存储结果也没问题,g表返回全部数据也没问题
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from a;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | a1   |
|  3 | a3   |
+----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from b;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | b1   |
|  3 | b3   |
+----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from g;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+
| id | name |
+----+------+
|  1 | g1   |
|  2 | g2   |
|  3 | g3   |
|  4 | g4   |
+----+------+

目前各自数据都是没问题的。

5. 联表查询测试

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from a left join g on a.id=g.id;"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from b left join g on b.id=g.id;"

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from a left join g on a.id=g.id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+------+------+
| id | name | id   | name |
+----+------+------+------+
|  1 | a1   |    1 | g1   |
|  3 | a3   |    3 | g3   |
|  2 | a2   |    2 | g2   |
|  4 | a4   |    4 | g4   |
+----+------+------+------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from b left join g on b.id=g.id;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+------+------+------+
| id | name | id   | name |
+----+------+------+------+
|  1 | b1   |    1 | g1   |
|  3 | b3   |    3 | g3   |
|  2 | b2   |    2 | g2   |
|  4 | b4   |    4 | g4   |
+----+------+------+------+

联表查询都很正常。

E-R分片

全局表适用于多个表都join同一张表;而所谓的E-R表,也叫做父子表,指的是另一种情况,即a join bx join y这种情况,为了避免跨分片join,让a跟b在一个分片上,x跟y在一个分片上。

重点的配置:

<!-- 就下面这一行配置,声明x表为取模分片,它的"子"表y和x进行关联,然后在y表的定义中声明外键字段 -->
<table name="x" dataNode="RedShard,GreenShard" rule="mod-long">
    <childTable name="y" joinKey="yid" parentKey="xid" />
</table>

来看配置过程。
1. 创建表

还是在core中创建表:

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.x(xid int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "create table core.y(yid int primary key auto_increment, name varchar(32)) charset utf8;"

mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.x(xid int primary key auto_increment, name varchar(32)) charset utf8;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "create table core.y(yid int primary key auto_increment, name varchar(32)) charset utf8;"

2. mycat配置

schema.xml

mv /opt/software/mycat/conf/schema.xml /opt/software/mycat/conf/schema.xml.gl
cat > /opt/software/mycat/conf/schema.xml <<EOF
<?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="RedShard"> 
    <table name="user_t" dataNode="RedShard" />
    <table name="order_t" dataNode="GreenShard" />
    <table name="a" dataNode="RedShard,GreenShard" rule="mod-long" />
    <table name="b" dataNode="RedShard,GreenShard" rule="mod-long" />
    <table name="g" primaryKey="id"  type="global" dataNode="RedShard,GreenShard" /> 
    <!-- 就下面这一行配置,声明x表为取模分片,它的"子"表y和x进行关联,然后在y表的定义中声明外键字段 -->
    <table name="x" dataNode="RedShard,GreenShard" rule="mod-long">
        <childTable name="y" joinKey="yid" parentKey="xid" />
    </table>
</schema>  
    <dataNode name="RedShard" dataHost="red" database= "core" /> 
    <dataNode name="GreenShard" dataHost="green" database= "core" /> 
    <dataHost name="red" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="red_master" url="10.0.0.204:3307" user="root" password="123"> 
            <readHost host="red_slave" url="10.0.0.204:3309" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="red_standby_master" url="10.0.0.205:3307" user="root" password="123"> 
            <readHost host="red_standby_slave" url="10.0.0.205:3309" user="root" password="123" /> 
    </writeHost>
    </dataHost>
    <dataHost name="green" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
        <heartbeat>select user()</heartbeat>  
    <writeHost host="green_master" url="10.0.0.204:3308" user="root" password="123"> 
            <readHost host="green_slave" url="10.0.0.204:3310" user="root" password="123" /> 
    </writeHost> 
    <writeHost host="green_standby_master" url="10.0.0.205:3308" user="root" password="123"> 
            <readHost host="green_standby_slave" url="10.0.0.205:3310" user="root" password="123" /> 
    </writeHost>
    </dataHost> 
</mycat:schema>
EOF

rule.xml

vim /opt/software/mycat/conf/rule.xml

<!-- mod-long规则,要修改为根据xid进行取模 -->
<tableRule name="mod-long">
	<rule>
		<columns>xid</columns>
		<algorithm>mod-long</algorithm>
	</rule>
</tableRule>

<!-- 根据上面的规则,下拉找到要修改mod-long函数,这里无需改动 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
	<!-- how many data nodes,我们当前有两个分片,所以写2 -->
	<property name="count">2</property>
</function>

<!-- 修改完毕,重启mycat -->
mycat restart

3. 插入记录

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into x(xid, name) values(1, 'x1'), (2, 'x2'), (3, 'x3'), (4, 'x4');"

# 下面语句执行会报错:ERROR 1064 (HY000) at line 1: ChildTable multi insert not provided
# 原因是mycat对于子表插入时,不允许一次插入多条数据,解决办法也很简单,分开插入即可
# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into y(yid, name) values(1, 'y1'), (2, 'y2'), (3, 'y3'), (4, 'y4');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into y(yid, name) value(1, 'y1');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into y(yid, name) value(2, 'y2');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into y(yid, name) value(3, 'y3');"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;insert into y(yid, name) value(4, 'y4');"

4. 查看结果

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from x;"
mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from y;"

mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from x;"
mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from y;"

mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from x;"
mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from y;"

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from x;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+
| xid | name |
+-----+------+
|   1 | x1   |
|   3 | x3   |
|   2 | x2   |
|   4 | x4   |
+-----+------+
[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from y;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+
| yid | name |
+-----+------+
|   1 | y1   |
|   3 | y3   |
|   2 | y2   |
|   4 | y4   |
+-----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from x;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+
| xid | name |
+-----+------+
|   2 | x2   |
|   4 | x4   |
+-----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3307/mysql.sock -e "use core;select * from y;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+
| yid | name |
+-----+------+
|   2 | y2   |
|   4 | y4   |
+-----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from x;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+
| xid | name |
+-----+------+
|   1 | x1   |
|   3 | x3   |
+-----+------+
[root@db01 ~]# mysql -uroot -p123 -S /data/mysql/3308/mysql.sock -e "use core;select * from y;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+
| yid | name |
+-----+------+
|   1 | y1   |
|   3 | y3   |
+-----+------+

目前各自数据都是没问题的。

5. 联表查询测试

mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from x left join y on x.xid=y.yid;"

[root@db01 ~]# mysql -uroot -p123456 -h10.0.0.204 -P8066 -e "use TESTDB;select * from x left join y on x.xid=y.yid;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----+------+------+------+
| xid | name | yid  | name |
+-----+------+------+------+
|   2 | x2   |    2 | y2   |
|   4 | x4   |    4 | y4   |
|   1 | x1   |    1 | y1   |
|   3 | x3   |    3 | y3   |
+-----+------+------+------+

联表查询都很正常。


that's all, see also:

Oldguo-标杆班级-MySQL-分布式架构-MyCAT | Linux启动MyCat报错:Could not write pid:No such file or directory 解决办法 | Mycat之数据库分片(分片枚举)-yellowcong | ERROR 1064 (HY000): ChildTable multi insert not provided

posted @ 2017-11-13 18:50  听雨危楼  阅读(248)  评论(0编辑  收藏  举报