MySQL for OPS 10:MyCAT 分布式架构
写在前面的话
在学习的索引的时候,有提到,当数据表数据达到 800W 的时候,索引的性能就开始逐步下降。对于一个公司而言,主要业务数据表达到 1000W 都很容易。同时这张表一般都是业务常用的表,操作还比较频繁。所以为了提升用户体验,需要采用另外的方式对数据库进行优化,那就是分库分表。而 MyCAT 就是能够帮助我们管理分库分表的这样一个中间件。
MyCAT 环境基础架构准备
架构图 1:
架构图 2:
【1】搭建基础环境:
1. 在 db01:192.168.100.111 上面安装数据库多实例:
# 创建基础目录
mkdir -p /data/{data,logs,backup,conf}/mysql-33{07,08,09,10}
mkdir -p /data/logs/mysql-33{07,08,09,10}/{bin-log,slow-log,error-log,relay-log}
mkdir -p /data/packages/mysql
mkdir -p /data/services # 添加用户
useradd -s /sbin/nologin mysql # 修改目录权限
chown -R mysql.mysql /data/logs/mysql-33*
chown -R mysql.mysql /data/data/mysql-33* # 清理默认配置文件
mv /etc/my.cnf /etc/my.cnf_bak # 解压包
cd /data/packages/mysql/
tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
cd /data/services/
mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql # 配置环境变量并查看
echo 'export PATH=$PATH:/data/services/mysql/bin' >> /etc/profile
source /etc/profile
mysql -V
2. 在 db01:192.168.100.111 上面初始化数据:
# 初始化数据
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3307
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3308
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3309
mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3310
3. 在 db01:192.168.100.111 上面初始化配置:
#
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 地址下载相关的包:
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 分布式架构的更多相关文章
- [待完善]mycat分布式架构部署
mycat介绍:http://mycat.org.cn/ mycat分布式架构部署
- MySQL之九---分布式架构(Mycat/DBLE)
MyCAT基础架构图 双主双从结构 MyCAT基础架构准备 准备环境 环境准备: 两台虚拟机 db01 db02 每台创建四个mysql实例:3307 3308 3309 3310 删除历史环境 p ...
- 分享 : 警惕MySQL运维陷阱:基于MyCat的伪分布式架构
分布式数据库已经进入了全面快速发展阶段.这种发展是与时俱进的,与人的需求分不开,因为现在信息时代的高速发展,导致数据量和交易量越来越大.这种现象首先导致的就是存储瓶颈,因为MySQL数据库实质上还是一 ...
- 转:三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构
在微信公众号看到一篇关于mycat的文章,觉得分析的很不错,给大家分享一下 三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构 原文链接:https://mp.weixin.qq.com/s ...
- 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 ...
- Mycat分布式数据库架构解决方案--Mycat实现读写分离
echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 安装完 ...
- Mycat分布式数据库架构解决方案--Mycat实现数据库分表
echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 准备工 ...
- Mycat分布式数据库架构解决方案--schema.xml详解
echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文件 ...
- 安排:《蚂蚁花呗1234面:Redis+分布式架构+MySQL+linux+红黑树》
前言: 大厂面试机会难得,为了提高面试通关率,建议朋友们在面试前先复盘自己的知识栈,依据掌握程度划分重要.优先级,系统地去学习!如果不准备充分就去参加面试,既会失去进入大厂的机会,更是对自己的不负责. ...
随机推荐
- html转换成canvas
使用的工具是:html2canvas html2canvas(this.currentRef) .then(async (canvas) => { let url = canvas.toData ...
- Java之Lambda表达式
函数式编程思想概述 面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做. 面向对象的思想: 做一件事情,找一个能解决这个事情的对 ...
- java之父类中的构造器是否能被子类继承?
子类默认继承父类的属性和方法,但不会继承父类的构造器,而是在子类被实例化时会默认调用父类的空构造器.子类在创建的时候会调用自己的空构造器,并在空构造器会隐式调用super(),即父类的空构造器.如果父 ...
- swoole怎么保持不掉线
正常情况下客户端中断TCP连接时,会发送一个FIN包,进行4次断开握手来通知服务器.但一些异常情况下,如客户端突然断电断网或者网络异常,服务器可能无法得知客户端已断开连接. 尤其是移动网络,TCP连接 ...
- 【xAsset框架】HFS 轻量级HTTP Server快速入门指南
一.引子 最近马三有幸参与开发了一个简易轻量的Unity资源管理框架 xAsset ,xasset 提供了一种使用资源路径的简单的方式来加载资源,简化了Unity项目资源打包,更新,加载,和回收的作业 ...
- windows 下安装beego
好久没写博客了,最近忙于一些杂事,看见有几个博友留言了,未能及时回复,稍后晚点回复诸位博友.不多说了,windows安装beego(请先确保git环境已安装并设置了git环境变量.这个简单网上很多教程 ...
- Python中使用cutecharts实现简单的手绘风格的图表
场景 效果 cutecharts的Github: https://github.com/chenjiandongx/cutecharts 注: 博客: https://blog.csdn.net/ba ...
- 读写锁(ReadWriteLock)
为了提高性能,Java提供了读写锁,读写锁分为读锁和写锁.多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的.如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率. 读 ...
- 搜索某个目录下所有jar包中的mapper目录下的xml文件
rm -rf /mapper/* find /data/app/app-*/lib ! -path "*xnpush*" ! -path "*portal*" ...
- arcgis api 4.x for js 基础工具篇之测距测面
前言 在搭建好WebGIS应用框架的时候,相信大家首先开发的都会是基础功能,此篇文章我们主要讲述的是“测距”."测面"功能. 注* 在测量单位中常规都是基于"平面坐标系& ...