数据库运维
记录DBA学习成长历程

21 MySQL分布式架构

文章目录

1 分布式架构演变

RDBMS
RDBMS+NOSQL
分布式架构+NoSQL
NeWSQL(HTAP)

2 基础架构介绍

2.1 环境准备

两台虚拟机 db01 db02
每台创建四个mysql实例:3307 3308 3309 3310

2.2 删除历史环境

pkill mysqld
rm -rf /data/33*
mv /etc/my.cnf /etc/my.cnf.bak

2.3 创建相关目录初始化数

mkdir /data/33{07..10}/data -p
chown -R mysql.mysql /data
mysqld --initialize-insecure --user=mysql --datadir=/data/3307/data --
basedir=/usr/local/mysql
mysqld --initialize-insecure --user=mysql --datadir=/data/3308/data --
basedir=/usr/local/mysql
mysqld --initialize-insecure --user=mysql --datadir=/data/3309/data --
basedir=/usr/local/mysql
mysqld --initialize-insecure --user=mysql --datadir=/data/3310/data --
basedir=/usr/local/mysql

2.4 准备配置文件和启动脚本

========db01==============
cat >/data/3307/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3307/data
socket=/data/3307/mysql.sock
port=3307
log-error=/data/3307/mysql.log
log_bin=/data/3307/mysql-bin
binlog_format=row
skip-name-resolve
server-id=7
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000
gtid_mode =ON
enforce_gtid_consistency =ON
slave_parallel_type
=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat >/data/3308/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3308/data
port=3308
socket=/data/3308/mysql.sock
log-error=/data/3308/mysql.log
log_bin=/data/3308/mysql-bin
binlog_format=row
skip-name-resolve
server-id=8
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000

slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat >/data/3309/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3309/data
socket=/data/3309/mysql.sock
port=3309
log-error=/data/3309/mysql.log
log_bin=/data/3309/mysql-bin
binlog_format=row
skip-name-resolve
server-id=9
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat >/data/3310/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3310/data
socket=/data/3310/mysql.sock
port=3310
log-error=/data/3310/mysql.log
log_bin=/data/3310/mysql-bin
binlog_format=row
skip-name-resolve
server-id=10
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000

#*************** gtid ***************
gtid_mode =ON
enforce_gtid_consistency =ON

#*************** gtid ***************
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat>/etc/systemd/system/mysqld3307.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refm
an/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --
defaults-file=/data/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/refm
an/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --
defaults-file=/data/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/refm
an/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --
defaults-file=/data/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/refm
an/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf
LimitNOFILE = 5000
EOF

========db02===============
cat >/data/3307/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3307/data
socket=/data/3307/mysql.sock
port=3307
log-error=/data/3307/mysql.log
log_bin=/data/3307/mysql-bin
binlog_format=row
skip-name-resolve
server-id=17
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000

#*************** gtid ***************
gtid_mode =ON
enforce_gtid_consistency =ON

#*************** gtid ***************
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat >/data/3308/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3308/data
port=3308
socket=/data/3308/mysql.sock
log-error=/data/3308/mysql.log
log_bin=/data/3308/mysql-bin
binlog_format=row
skip-name-resolve
server-id=18
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat >/data/3309/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3309/data
socket=/data/3309/mysql.sock
port=3309
log-error=/data/3309/mysql.log
log_bin=/data/3309/mysql-bin
binlog_format=row
skip-name-resolve
server-id=19
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

cat >/data/3310/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/3310/data
socket=/data/3310/mysql.sock
port=3310
log-error=/data/3310/mysql.log
log_bin=/data/3310/mysql-bin
binlog_format=row
skip-name-resolve
server-id=20
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1

#*************** group commit***************
binlog_group_commit_sync_delay=1
binlog_group_commit_sync_no_delay_count=1000
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=4
master_info_repository=TABLE
relay_log_info_repository=TABLE
EOF

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=/usr/local/mysql/bin/mysqld --
defaults-file=/data/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=/usr/local/mysql/bin/mysqld --
defaults-file=/data/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=/usr/local/mysql/bin/mysqld --
defaults-file=/data/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=/usr/local/mysql/bin/mysqld --
defaults-file=/data/3310/my.cnf
LimitNOFILE = 5000
EOF

2.5 修改权限,启动多实例

chown -R mysql.mysql /data/*
systemctl start mysqld3307
systemctl start mysqld3308
systemctl start mysqld3309
systemctl start mysqld3310

mysql -S /data/3307/mysql.sock -e "showvariables like 'server_id'"
mysql -S /data/3308/mysql.sock -e "showvariables like 'server_id'"
mysql -S /data/3309/mysql.sock -e "showvariables like 'server_id'"
mysql -S /data/3310/mysql.sock -e "showvariables like 'server_id'"

2.6 节点主从规划

10.0.0.52:3308 <-----> 10.0.0.51:3308
10.0.0.52:3310 -----> 10.0.0.52:3308
10.0.0.51:3310 -----> 10.0.0.51:3308

2.7 开始配置主从环境

# shard1
## 10.0.0.51:3307 <-----> 10.0.0.52:3307

# db02
mysql -S /data/3307/mysql.sock -e "create user repl@'10.0.0.%' identified with mysql_native_password by '123'; grant replication slave on *.* to repl@'10.0.0.%';"

mysql -S /data/3307/mysql.sock -e "create user root@'10.0.0.%' identified with mysql_native_password by '123'; grant all on *.* to root@'10.0.0.%'; "

# db01
mysql -S /data/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52',MASTER_PORT=3307, MASTER_AUTO_POSITION=1,
MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3307/mysql.sock -e "start slave;"
mysql -S /data/3307/mysql.sock -e "show
slave status\G"|grep Running:

# db02
mysql -S /data/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51',MASTER_PORT=3307, MASTER_AUTO_POSITION=1,
MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3307/mysql.sock -e "start slave;"
mysql -S /data/3307/mysql.sock -e "show slave status\G"|grep Running:

## 10.0.0.51:3309 ------> 10.0.0.51:3307
# db01
mysql -S /data/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51',MASTER_PORT=3307, MASTER_AUTO_POSITION=1,MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3309/mysql.sock -e "start slave;"
mysql -S /data/3309/mysql.sock -e "show slave status\G"|grep Running:

## 10.0.0.52:3309 ------> 10.0.0.52:3307
# db02
mysql -S /data/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52',MASTER_PORT=3307, MASTER_AUTO_POSITION=1,
MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3309/mysql.sock -e "start slave;"
mysql -S /data/3309/mysql.sock -e "show slave status\G"|grep Running:

==========================================
# shard2
## 10.0.0.52:3308 <-----> 10.0.0.51:3308
# db01
mysql -S /data/3308/mysql.sock -e "create user repl@'10.0.0.%' identified with mysql_native_password by '123'; grant replication slave on *.* to
repl@'10.0.0.%';"
mysql -S /data/3308/mysql.sock -e "create user root@'10.0.0.%' identified with mysql_native_password by '123'; grant all on *.* to root@'10.0.0.%'; "

# db02
mysql -S /data/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51',MASTER_PORT=3308, MASTER_AUTO_POSITION=1,
MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3308/mysql.sock -e "start slave;"
mysql -S /data/3308/mysql.sock -e "show slave status\G"|grep Running:

# db01
mysql -S /data/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52',MASTER_PORT=3308, MASTER_AUTO_POSITION=1,
MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3308/mysql.sock -e "start slave;"
mysql -S /data/3308/mysql.sock -e "show slave status\G"|grep Running:

## 10.0.0.52:3310 -----> 10.0.0.52:3308
# db02
mysql -S /data/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52',MASTER_PORT=3308, MASTER_AUTO_POSITION=1,MASTER_USER='repl'
, MASTER_PASSWORD='123';"
mysql -S /data/3310/mysql.sock -e "start slave;"
mysql -S /data/3310/mysql.sock -e "show slave status\G"|grep Running:

##10.0.0.51:3310 -----> 10.0.0.51:3308
# db01
mysql -S /data/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51',MASTER_PORT=3308, MASTER_AUTO_POSITION=1,
MASTER_USER='repl', MASTER_PASSWORD='123';"
mysql -S /data/3310/mysql.sock -e "start slave;"
mysql -S /data/3310/mysql.sock -e "show slave status\G"|grep Running:

检测主从状态
mysql -S /data/3307/mysql.sock -e "show slave status\G"|grep Yes
mysql -S /data/3308/mysql.sock -e "show slave status\G"|grep Yes
mysql -S /data/3309/mysql.sock -e "show slave status\G"|grep Yes
mysql -S /data/3310/mysql.sock -e "show slave status\G"|grep Yes
+++++++++++++++++++++++++++++++++++++++++++
注:如果中间出现错误,在每个节点进行执行以下命令,从头执行
mysql -S /data/3307/mysql.sock -e "stop slave; reset slave all;"
mysql -S /data/3308/mysql.sock -e "stop slave; reset slave all;"
mysql -S /data/3309/mysql.sock -e "stop slave; reset slave all;"
mysql -S /data/3310/mysql.sock -e "stop slave; reset slave all;"

3 MyCAT安装

3.1 预先安装Java运行环境

yum install -y java

3.2 下载

Mycat-server-xxxxx.linux.tar.gz
http://dl.mycat.org.cn/

3.3 解压文件

tar xf Mycat-server-*

3.4 软件目录结构

ls
bin catlet conf lib logs version.txt

3.5 启动和连接

vim /etc/profile
export PATH=/data/app/mycat/bin:$PATH
source /etc/profile
mycat start
mysql -uroot -p123456 -h 127.0.0.1 -P8066

注: Mycat中使用的是MySQL 5.1版本驱动,连接8.0时将会失败。
解决方案:
1. 下载更新客户端程序
https://downloads.mysql.com/archives/cj/
2. 连接时添加auth=mysql_native_password参数
mysql -uroot -p123456 -h10.0.0.51 - P8066 --default-auth=mysql_native_password
3. 更新MySQL客户端命令为8.0之前版本

4 配置文件详解

bin:程序目录
conf:配置文件目录
schema.xml:主配置文件:节点信息、读写分离、高可用设置、调用分片策略..
rule.xml:分片策略的定义、功能、使用用方法
server.xml:mycat服务有关配置: 用户、网络、权限、策略、资源...
xx.txt文件:分片参数定义文件
log4j2.xml:Mycat 相关日志记录配置
logs:wrapper.log : 启动日志;mycat.log :工作日志

5 schema.xml配置文件基本结构

5.1 配置模板介绍

[root@db01 conf]# cd /data/mycat/conf/
mv schema.xml schema.xml.bak
vim schema.xml

# 逻辑库:
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
</schema>

# DN数据节点(逻辑分片):数据节点(逻辑分片):
<dataNode name="dn1" dataHost="localhost1" database= "world" />
作用:垂直和水平查分。

# DH 数据主机
作用: 高可用和读写分离
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="db1" url="10.0.0.51:3307" user="root" password="123">
<readHost host="db2" url="10.0.0.51:3309" user="root" password="123" />
</writeHost>
</dataHost>
</mycat:schema>
<?xml version="1.0"?>

5.2 配置文件简单试水-读写分离

#配置文件模板-读写分离
<?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="dn1">
</schema>
<dataNode name="dn1"
dataHost="localhost1" database= "world" />
<dataHost name="localhost1"
maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql"
dbDriver="native" switchType="1">
<heartbeat>select user()
</heartbeat>
<writeHost host="db1"
url="10.0.0.51:3307" user="root"
password="123">
<readHost host="db2"
url="10.0.0.51:3309" user="root"
password="123" />
</writeHost>
</dataHost>
</mycat:schema>

# 测试环境准备
db01:
mysql -S /data/3307/mysql.sock -e "create user root@'10.0.0.%' identified with mysql_native_password by '123';"
mysql -S /data/3307/mysql.sock -e "grant all on *.* to root@'10.0.0.%' ;"
mysql -S /data/3307/mysql.sock -e "source /root/world.sql"

mysql -S /data/3308/mysql.sock -e "create user root@'10.0.0.%' identified with mysql_native_password by '123';"
mysql -S /data/3308/mysql.sock -e "grant all on *.* to root@'10.0.0.%' ;"
mysql -S /data/3308/mysql.sock -e "source /root/world.sql"

# 重启mycat
mycat restart

读写分离测试
# 连接mycat 服务
mysql -uroot -p123456 -h10.0.0.52 -P8066 --default-auth=mysql_native_password

# 测试读
mysql> select @@server_id;

# 测试写
mysql> begin ; select @@server_id;commit;

5.3 配置读写分离及高可用

[root@db01 conf]# mv schema.xml schema.xml.rw
[root@db01 conf]# vim schema.xml 
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"
dataNode="sh1">
</schema>
<dataNode name="sh1" dataHost="oldguo1" database= "world" />
<dataHost name="oldguo1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()
</heartbeat>
<writeHost host="db1" url="10.0.0.51:3307" user="root" password="123">
<readHost host="db2"
url="10.0.0.51:3309" user="root" password="123" />
</writeHost>
<writeHost host="db3" url="10.0.0.52:3307" user="root" password="123">
<readHost host="db4" url="10.0.0.52:3309" user="root" password="123" />
</writeHost>
</dataHost>
</mycat:schema>

primary writehost :负责写操作的writehost 
standby writeHost :和readhost一样,只提供读服务

当写节点宕机后,后面跟的readhost也不提供服务,这时候standby的writehost就提供写服务,后面跟的readhost提供读服务

测试读写分离:
mycat restart
mysql -uroot -p123456 -h10.0.0.51 -P8066 --default-auth=mysql_native_password
mysql> select @@server_id;
mysql> begin;select @@server_id;commit;

测试高可用:
[root@db01 conf]# systemctl stop mysqld3307
mysql -uroot -p123456 -h 10.0.0.51 -P 8066
mysql> select @@server_id;
mysql> begin;select @@server_id;commit;
[root@db01 conf]# systemctl start mysqld3307
mysql -uroot -p123456 -h 10.0.0.51 -P 8066
mysql> select @@server_id;
mysql> begin;select @@server_id;commit;

说明:
1. MHA + Mycat+ 3分片
<dataHost name="mha1" maxCon="1000" minCon="10" balance="1" writeType="0"
dbType="mysql" dbDriver="native" switchType="2">
<heartbeat>show slave status</heartbeat>
<writeHost host="db1" url="10.0.0.55:3306" user="root" password="123">
<readHost host="db2" url="10.0.0.52:3306" user="root" password="123" />
<readHost host="db3" url="10.0.0.53:3306" user="root" password="123" />
</writeHost>
</dataHost>
<dataHost name="mha2" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="2">
<heartbeat>show slave status</heartbeat>
<writeHost host="db1" url="10.0.0.56:3307" user="root" password="123">
<readHost host="db2" url="10.0.0.51:3307" user="root" password="123" />
<readHost host="db2" url="10.0.0.53:3307" user="root" password="123" />
</writeHost>
</dataHost>
<dataHost name="mha3" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="2">
<heartbeat>show slave status</heartbeat>
<writeHost host="db1" url="10.0.0.57:3308" user="root" password="123">
<readHost host="db2" url="10.0.0.51:3308" user="root" password="123" />
<readHost host="db2" url="10.0.0.52:3308" user="root" password="123" />
</writeHost>
</dataHost>

2. PXC+Mycat+3分片
<dataHost name="pxc1" maxCon="1000"
minCon="10" balance="1" writeType="0"
dbType="mysql" dbDriver="native"
switchType="3">
<heartbeat>show status like
'wsrep%'</heartbeat>
<writeHost host="db1"
url="10.0.0.51:3306" user="root"
password="123">
</writeHost>
<writeHost host="db2"
url="10.0.0.52:3306" user="root"
password="123">
</writeHost>
<writeHost host="db3"
url="10.0.0.53:3306" user="root"
password="123">
</writeHost>
</dataHost>
...此处省略...
3. 调研: MGR+Mycat+3分片
4. 调研: DBLE

5.4 Schema.xml核心参数介绍

5.4.1 balance属性

读操作负载均衡类型,目前的取值有3种:
1. balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上。
2. balance="1",全部的readHost与standby writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。
3. balance="2",所有读操作都随机的在writeHost、readhost上分发。

5.4.2 writeType属性

写操作负载均衡,目前的取值有2种:
1. writeType="0", 所有写操作发送到配置的第一个writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为主,切换记录在配置文件中:dnindex.properties .
2. writeType=“1”,所有写操作都随机的发送到配置的writeHost,但不推荐使用

5.4.3 switchType属性

-1: 表示不自动切换
1 : 默认值,自动切换
2 : 基于MySQL主从同步的状态决定是否切换 ,心跳语句为 show slave status (注意超时参数,参考orch)
3 : 基于Galary Cluster(PXC,MGC) 切换机制,心跳语句为:show status like 'wsrep%'

5.4.4 连接有关

maxCon="1000":最大的并发连接数
minCon="10" :mycat在启动之后,会在后端节点上自动开启的连接线程

5.4.5 tempReadHostAvailable="1"

这个一主一从时(1个writehost,1个readhost时),可以开启这个参数,如果2个writehost,2个readhost时<heartbeat>select user()</heartbeat> 监测心跳

5.4.6 checkSQLschema="false"

是否检查,在select时的库名字。
例如,执行 select * from TESTDB.t1;
参数开启为true,会自动TESTDB去掉。否则会使得后端节点执行报错。
当然如果,TESTDB写成了一个不存在的逻辑库名字,也会报错。
结论: 一般我们可以先use,后select的方式进行查询数据即可避免此类问题。

6 Mycat 分布式架构--垂直分表

taobao
user (sh1)
order_t(sh2)

cd /data/app/mycat/conf
mv schema.xml schema.xml.ha
vim schema.xml
<?xml version="1.0"?>

<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1">
<table name="user" dataNode="sh1"/>
<table name="order_t" dataNode="sh2"/>
</schema>
<dataNode name="sh1" dataHost="oldguo1" database= "taobao" />
<dataNode name="sh2" dataHost="oldguo2" database= "taobao" />
<dataHost name="oldguo1" maxCon="1000" minCon="10" balance="1" writeType="0"
dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="db1" url="10.0.0.51:3307" user="root" password="123">
<readHost host="db2" url="10.0.0.51:3309" user="root" password="123" />
</writeHost>
<writeHost host="db3" url="10.0.0.52:3307" user="root" password="123">
<readHost host="db4" url="10.0.0.52:3309" user="root" password="123" />
</writeHost>
</dataHost>
<dataHost name="oldguo2" maxCon="1000" minCon="10" balance="1" writeType="0"
dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="db1" url="10.0.0.51:3308" user="root" password="123">
<readHost host="db2" url="10.0.0.51:3310" user="root" password="123" />
</writeHost>
<writeHost host="db3" url="10.0.0.52:3308" user="root" password="123">
<readHost host="db4" url="10.0.0.52:3310" user="root" password="123" />
</writeHost>
</dataHost>
</mycat:schema>
创建测试库和表:
mysql -S /data/3307/mysql.sock -e "create database taobao charset utf8;"
mysql -S /data/3308/mysql.sock -e "create database taobao charset utf8;"
mysql -S /data/3307/mysql.sock -e "use taobao;create table user(id int,name
varchar(20))";
mysql -S /data/3308/mysql.sock -e "use taobao;create table order_t(id int,name varchar(20))"
# 重启mycat
mycat restart
# mycat中对user 和 order 数据插入
mysql -uroot -p123456 -h10.0.0.52 -P8066 --default-auth=mysql_native_password
insert into user values(1,'a');
insert into user values(2,'b');
insert into user values(3,'c');
commit;
insert into order_t values(1,'x'),(2,'y');
commit;
[root@db01 conf]# mysql -S /data/3307/mysql.sock -e "show tables from taobao"
+------------------+
| Tables_in_taobao |
+------------------+
| user |
+------------------+
[root@db01 conf]# mysql -S /data/3308/mysql.sock -e "show tables from taobao"
+------------------+
| Tables_in_taobao |
+------------------+
| order_t |
+------------------+
[root@db01 conf]# mysql -S /data/3307/mysql.sock -e "select * from taobao.user"
+------+------+
| id | name |
+------+------+
| 1 | a |
| 2 | b |
| 3 | c |
+------+------+
[root@db01 conf]# mysql -S
/data/3308/mysql.sock -e "select * from taobao.order_t"
+------+------+
| id | name |
+------+------+
| 1 | x |
| 2 | y |
+------+------+

7 Mycat 分布式架构--水平拆分

7.1 重要概念

分片策略 :几乎融合经典业务中大部分的分片策略。
Mycat已经开发了相应算法,非常方便调用。
范围分片
取模
枚举
日期
HASH
等。
分片键: 作为分片条件的列。

7.2 范围分片

比如说t3表
(1)行数非常多,2000w(1-1000w:sh1 1000w01-2000w:sh2)
(2)访问非常频繁,用户访问很平均
# 1. 修改schema.xml文件,定制分片策略
cp schema.xml schema.xml.1
vim schema.xml
添加:
<table name="t3" dataNode="sh1,sh2" rule="auto-sharding-long" />
# 2. 定义和使用分片策略
vim rule.xml
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
<function name="rang-long" class="io.mycat.route.function.AutoPartitio nByLong">
<property name="mapFile">autopartitionlong.txt</property>
</function>
# 3. 定义范围
vim autopartition-long.txt
0-10=0
10-20=1
4. 创建测试表:
mysql -S /data/3307/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
5. 测试:
重启mycat
mycat restart
mysql -uroot -p123456 -h10.0.0.51 -P8066 --default-auth=mysql_native_password
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(4,'d');
insert into t3(id,name) values(11,'aa');
insert into t3(id,name) values(12,'bb');
insert into t3(id,name) values(13,'cc');
insert into t3(id,name) values(14,'dd');
[root@db01 conf]# mysql -S
/data/3308/mysql.sock -e "select * from taobao.t3"
[root@db01 conf]# mysql -S
/data/3307/mysql.sock -e "select * from taobao.t3"

7.3 取模分片

1%3 1
2%3 2
3%3 0
4%3 1
任何正整数数字和N(正整数)取模,得的值永远都是0~N-1
id % 分片数量取模
N % 5 = 0-4 idx
取余分片方式:分片键(一个列)与节点数量进行取余,得到余数,将数据写入对应节点
# 1. 修改配置文件
vim schema.xml
<table name="t4" dataNode="sh1,sh2" rule="mod-long" />
# 2. 查看和定义分片使用
vim rule.xml
<property name="count">2</property>
# 3. 准备测试环境
创建测试表:
mysql -S /data/3307/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
重启mycat
mycat restart
# 4. 测试:
mysql -uroot -p123456 -h10.0.0.51 -P8066 --default-auth=mysql_native_password
use TESTDB 
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,'d');
insert into t4(id,name) values(6,'x'),(8,'y'),(10,'z');
分别登录后端节点查询数据
mysql -S /data/3308/mysql.sock -e "select * from taobao.t4"
mysql -S /data/3307/mysql.sock -e "select * from taobao.t4"

7.4 月份分片

假设,tm (id int not null primary key,create_time datetime)
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>partbymonth</algorithm>
</rule>
</tableRule>
<function name="partbymonth"  class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2020-01-01</property>
</function>
mysql -S /data/3307/mysql.sock -e "use taobao;create table tm (id int not null primary key auto_increment,create_time datetime not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table tm (id int not null primary key auto_increment,create_time datetime not null);"
测试例子:

7.5 枚举分片

t5 表
id name telnum
1 bj 1212
2 sh 22222
3 bj 3333
4 sh 44444
5 bj 5555
sharding-by-intfile
# 1. 设计分片策略
vim schema.xml
<table name="t5" dataNode="sh1,sh2" rule="sharding-by-intfile" />
# 2. 应用分片策略
vim rule.xml
<tableRule name="sharding-by-intfile">
<rule>
<columns>name</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap">
<property name="mapFile">partition-hashint.txt</property>
<property name="type">1</property>
</function>
vim partition-hash-int.txt 配置:
bj=0
sh=1
DEFAULT_NODE=1
# 3. 准备测试环境
mysql -S /data/3307/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
重启mycat
mycat restart
# 4. 插入测试数据:
mysql -uroot -p123456 -h10.0.0.51 -P8066 --default-auth=mysql_native_password
use TESTDB 
insert into t5(id,name) values(1,'bj');
insert into t5(id,name) values(2,'sh');
insert into t5(id,name) values(3,'bj');
insert into t5(id,name) values(4,'sh');
insert into t5(id,name) values(5,'tj');
mysql -S /data/3308/mysql.sock -e "select * from taobao.t5"
mysql -S /data/3307/mysql.sock -e "select * from taobao.t5"

7.6 Mycat全局表

a b c d .....
join
t
a
id name age
1 zs 18 sh1
id addr aid
1001 bj 1
1002 sh 2
2 ls 19 sh2
id addr aid
1001 bj 1
1002 sh 2
t
id addr aid
1001 bj 1
1002 sh 2
使用场景:
如果你的业务中有些数据类似于数据字典,比如配置文件的配置,常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大,而且大部分的业务场景都会用到,那么这种表适合于Mycat全局表,无须对数据进行切分,要在所有的分片上保存一份数据即可,Mycat 在Join操作中,业务表与全局表进行Join聚合会优先选择相同分片内的全局表join,避免跨库Join,在进行数据插入操作时,mycat将把数据分发到全局表对应的所有分片执行,在进行数据读取时候将会随机获取一个节点读取数据。
# 1. 设置全局表策略
vim schema.xml
<table name="t_area" primaryKey="id" type="global" dataNode="sh1,sh2" />
# 2. 后端数据准备
mysql -S /data/3307/mysql.sock -e "use taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"
重启mycat
mycat restart
# 3. 测试:
mysql -uroot -p123456 -h10.0.0.51 -P8066
use TESTDB
insert into t_area(id,name) values(1,'a');
insert into t_area(id,name)values(2,'b');
insert into t_area(id,name)values(3,'c');
insert into t_area(id,name)values(4,'d');
mysql -S /data/3308/mysql.sock -e "select * from taobao.t_area"
mysql -S /data/3307/mysql.sock -e "select * from taobao.t_area"

7.7 E-R分片

a
join
b
on a.xx =b.yy
a
id name
1 a sh1
3 c
2 b sh2
4 d
b
id addr aid
1001 bj 1
1002 sh 2
1003 tj 3 sh2
1004 wh 4
为了防止跨分片join,可以使用E-R模式
<table name="a" dataNode="sh1,sh2" rule="mod-long">
<childTable name="b" joinKey="aid" parentKey="id" />
</table>
select * from a join b on a.id = b.aid where a.name=d
例子:
1. 修改配置文件
vim schema.xml
<table name="a" dataNode="sh1,sh2" rule="mod-long_oldguo">
<childTable name="b" joinKey="aid" parentKey="id" />
</table>
2. 修改rule.xml mod-log分片策略:
vim rule.xml
<tableRule name="mod-long_oldguo">
<rule>
<columns>id</columns>
<algorithm>modlong_oldguo</algorithm>
</rule>
</tableRule>
<function name="mod-long_oldguo" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">2</property>
</function>
3. 创建测试表
mysql -S /data/3307/mysql.sock -e "use taobao;create table a (id int not null
primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3307/mysql.sock -e "use taobao;create table b (id int not null
primary key auto_increment,addr varchar(20) not null ,aid int );"
mysql -S /data/3308/mysql.sock -e "use taobao;create table a (id int not null
primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table b (id int not null
primary key auto_increment,addr varchar(20) not null ,aid int );"
4. 重启mycat 测试
mycat restart
mysql -uroot -p123456 -h10.0.0.51 -P8066 --default-auth=mysql_native_password
use TESTDB
insert into a(id,name) values(1,'a'); 13308
insert into a(id,name) values(2,'b'); 03307
insert into a(id,name) values(3,'c'); 13308
insert into a(id,name) values(4,'d'); 03307
insert into a(id,name) values(5,'e'); 13308
insert into b(id,addr,aid)values(1001,'bj',1); 1 3308
insert into b(id,addr,aid)values(1002,'sj',3); 1 3308
insert into b(id,addr,aid)values(1003,'sd',4); 0 3307
insert into b(id,addr,aid)values(1004,'we',2); 0 3307
insert into b(id,addr,aid)values(1005,'er',5); 1 3308

后端数据节点数据分布:
mysql -S /data/3307/mysql.sock -e "select * from taobao.a"
mysql -S /data/3307/mysql.sock -e "select * from taobao.b"
mysql -S /data/3308/mysql.sock -e "select * from taobao.a"
mysql -S /data/3308/mysql.sock -e "select * from taobao.b"

8 管理类操作

[root@db01 conf]# mysql -uroot -p123456 -h10.0.0.51 -P9066 --default-auth=mysql_native_password
# 查看帮助
show @@help;
# 重新加载配置信息
reload @@config : schema.xml
reload @@config_all : 所有配置重新加载
rollback @@config | Rollback all
config from memory
# sql监控分析功能,建议在做压测的时候关闭。
reload @@sqlstat=open | Open real-time sql stat analyzer
reload @@sqlstat=close | Close real-time sql stat analyzer
# 查看Mycat 服务情况
show @@server ;
# 查看分片DN节点信息
mysql> show @@datanode;
mysql> show @@datanode where schema = ?;
# 查看数据源
show @@datasource
show @@datasource where datanode=sh1;
#报告心跳信息
show @@heartbeat
show @@heartbeat.detail where name=?
RS_CODE :
-1:连接失败
1 :连接正常
-2:连接超时
0 :初始化状态
如果节点故障,会有5次检测,失败后则状态为-1。
# 查看连接信息
show @@connection
# 关闭连接
kill @@connection id1,id2,...
# 查看后端连接
show @@backend
# 查看缓存应用情况
show @@cache;
# 查看sql统计
mysql> show @@sql;
mysql> show @@sql_slow;
mysql> show @@sql.sum;

9 配置mycat的日志管理

<asyncRoot level="info" includeLocation="true">
级别:All < Trace < Debug < Info < Warn <Error < Fatal < OFF
调试建议使用 Debug 级别,生产上一般使用 Info级别

10 配置Mycat的服务器参数

10.1 charset 属性

该属性用于字符集设置。
<system>
<property
name="charset">utf8</property>
</system>

10.2 processors 属性

该属性主要用于指定系统可用的线程数,默认值为机器CPU 核心线程数。主要影响 processorBufferPool、processorBufferLocalPercent、processorExecutor 属性。NIOProcessor 的个数也是由这个属性定义的,所以调优的时候可以适当的调高这个属性。

10.3 processorBufferChunk 属性

该属性指定每次分配 Socket Direct Buffer 的大小,默认是 4096 个字节。这个属性也影响 bufferpool 的长度。如果一次性获取的数过大 buffer 不够用会经常出现警告,此时可以适当调大。

10.4 processorBufferPool 属性

该属性指定 bufferPool 计算比例值。由于每次执行NIO 读、写操作都需要使用到 buffer,系统初始化的时候会建立一定长度的 buffer 池来加快读、写的效率,减少建立 buffer 的时间。Mycat 中有两个主要的buffer 池:
BufferPool:BufferPool 由ThreadLocalPool 组合而成,每次从 BufferPool 中获取 buffer 都会优先获取ThreadLocalPool 中的buffer,未命中之后才会去获取 BufferPool 中的
buffer。也就是说 ThreadLocalPool 是作为BufferPool 的二级缓存,每个线程内部自己使用的。BufferPool 上的 buffer 则是每个 NIOProcessor都共享的。这个属性的默认值为:
默认bufferChunkSize(4096) * processors属性 * 1000
BufferPool 的总长度 = bufferPool /bufferChunk。
若 bufferPool 不是 bufferChunk 的整数倍,则总长度为前面计算得出的商 + 1
假设系统线程数为 4,其他都为属性的默认值,则:
bufferPool = 4096 * 4 * 1000
BufferPool 的总长度 : 4000 = 16384000 / 4096

10.5 processorBufferLocalPercent 属性

前面提到了 ThreadLocalPool。这个属性就是用来控制分配这个 pool 的大小用的,这个属性默认值为100。
线程缓存百分比 = bufferLocalPercent /processors 属性。
例如,系统可以同时运行 4 个线程,使用默认值,则根据公式每个线程的百分比为 25。最后根据这个百分比来计算出具体的 ThreadLocalPool 的长度公式如下:
ThreadLocalPool 的长度 = 线程缓存百分比 *BufferPool 长度 / 100
假设 BufferPool 的长度为 4000,其他保持默认值。
那么最后每个线程建立上的 ThreadLocalPool 的长度为: 1000 = 25 * 4000 / 100

10.6 心跳属性

mycat 中有几个周期性的任务来异步的处理一些我需要的工作。这些属性就在系统调优的过程中也是比不可少的。
processorCheckPeriod :
清理 NIOProcessor 上前后端空闲、超时和关闭连接的间隔时间。默认是 1 秒,单位毫秒。
dataNodeIdleCheckPeriod :
对后端连接进行空闲、超时检查的时间间隔,默认是300 秒,单位毫秒。
dataNodeHeartbeatPeriod :
对后端所有读、写库发起心跳的间隔时间,默认是 10秒,单位毫秒。

10.7 服务相关属性

bindIp :
mycat 服务监听的 IP 地址,默认值为 0.0.0.0。
serverPort :
定义 mycat 的使用端口,默认值为 8066。
managerPort :
定义 mycat 的管理端口,默认值为 9066。

10.8 Mysql 连接相关属性

packetHeaderSize :
指定 Mysql 协议中的报文头长度。默认 4。
maxPacketSize :
指定 Mysql 协议可以携带的数据最大长度。默认16M。
idleTimeout :
指定连接的空闲超时时间。某连接在发起空闲检查下,发现距离上次使用超过了空闲时间,那么这个连接会被回收,就是被直接的关闭掉。默认 30 分钟,单位毫秒。
charset :
连接的初始化字符集。默认为 utf8。
txIsolation :
前端连接的初始化事务隔离级别,只在初始化的时候使用,后续会根据客户端传递过来的属性对后端数据库连接进行同步。默认为 REPEATED_READ,设置值为数字默认3。
READ_UNCOMMITTED = 1;
READ_COMMITTED = 2;
REPEATED_READ = 3;
SERIALIZABLE = 4;
sqlExecuteTimeout :
SQL 执行超时的时间,Mycat 会检查连接上最后一次
执行 SQL 的时间,若超过这个时间则会直接关闭这连接。
默认时间为 300 秒,单位秒。

11 逻辑库配置

# 总配置文件
schema.xml
<schema name="oldguo" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1">
sh3
sh4
</schema>
# mycat 服务配置
server.xml
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">oldguo</property>
<property name="defaultSchema">oldguo</property>
<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">oldguo</property>
<property name="readOnly">true</property>
<property name="defaultSchema">oldguo</property>
</user>
reload @@config_all : 所有配置重新加载
2. 添加一个逻辑库
schema.xml
<schema name="oldguo" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1">
</schema>
server.xml
<property name="schemas">oldguo,oldguo</property>
reload @@config_all : 所有配置重新加载

12 sequence分布式全局序列

12.1 介绍

t1
id int not null pk auto_increment,
name varchar(20),
sharding_key int not null
insert into t1(name,sharding_key) values (。。。。)
在实现分库分表的情况下,数据库自增主键已经无法保证在集群中是全局唯一的主键了,因此mycat提供了全局的sequence.

12.1 本地方式

采用该方式,mycat将sequence配置到classpath目录的sequence_conf.properties文件中,在
sequence_conf.properties文件做如下配置
GLOBAL_SEQ.HISIDS=
GLOBAL_SEQ.MINID=1001
GLOBAL_SEQ.MAXID=100000000
GLOBAL_SEQ.CURID=1000
其中HISIDS表示历史分段(一般无特殊需要则可以不配置),MINID表示最新的ID值,MAXID表示最大的ID值,CURID表示当前的ID值。
0. 打开本地seq功能。
需要启用这种方式,则首先需要在server.xml中配置如下
参数:
<system><property name="sequnceHandlerType">0</property>
</system>
配置测试:
1. 修改sequence_conf.properties
vim sequence_conf.properties
#全局seq
GLOBAL_SEQ.HISIDS=
GLOBAL_SEQ.MINID=1001
GLOBAL_SEQ.MAXID=10000000
GLOBAL_SEQ.CURID=1000
或者:自己定制
# self define sequence
OLDGUO.HISIDS=
OLDGUO.MINID=2001
OLDGUO.MAXID=20000000
OLDGUO.CURID=2000
2. 设置server.xml
<!--lang:java-->
public static final int
SEQUENCEHANDLER_LOCALFILE = 0;
public static final int
SEQUENCEHANDLER_MYSQLDB = 1;
public static final int
SEQUENCEHANDLER_LOCAL_TIME = 2;
private int sequnceHandlerType = SEQUENCEHANDLER_LOCALFILE;
3.建表,插入数据测试
mysql> create table test(id int not null primary key ,name varchar(20));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into test(id,name) values(next value for MYCATSEQ_OLDGUO,@@hostname);
Query OK, 1 row affected (0.07 sec)
mysql> select * from test;
+-------+------+
| id | name |
+-------+------+
| 10001 | db02 |
+-------+------+
1 row in set (0.00 sec)
mysql> insert into test(id,name) values(next value for MYCATSEQ_GLOBAL,@@hostname);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+-------+------+
| id | name |
+-------+------+
| 10001 | db02 |
| 10002 | db02 |
+-------+------+
2 rows in set (0.00 sec)
mysql> select * from test;
+-------+------+
| id | name |
+-------+------+
| 10001 | db02 |
| 10002 | db02 |
+-------+------+
2 rows in set (0.01 sec)
mysql> insert into test(id,name) values(next value for
MYCATSEQ_GLOBAL,@@hostname);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+-------+------+
| id | name |
+-------+------+
| 10001 | db02 |
| 10002 | db02 |
| 10003 | db02 |
+-------+------+

12.3 数据库方式

12.3.1 原理

在数据库中建立一张表,存放 sequence 名称(name),sequence 当前值(current_value),步长
(increment int 类型每次读取多少个 sequence,假设为 K)等信息;

12.3.2 获取步骤

当初次使用该 sequence 时,根据传入的 sequence 名称,从数据库这张表中读取current_value,和increment 到 MyCat 中,并将数据库中的current_value 设置为原 current_value 值 + increment 值;
MyCat 将读取到 current_value+increment 作为本次要使用的 sequence 值,下次使用时,自动加 1,当使用 increment 次后,执行步骤 1)相同的操作.MyCat 负责维护这张表,用到哪些 sequence,只需要在这张表中插入一条记录即可。若某次读取的 sequence 没有用完,系统就停掉了,则这次读取的 sequence 剩余值不会再使用。

12.3.3 配置细节

# 修改Mycat配置文件server.xml
<property name="sequnceHandlerType">1</property>
# 修改Mycat配置文件schema.xml
<table name="t" primaryKey="id" autoIncrement="true" dataNode="sh1,sh2"
rule="mod-long"/>
<table name="MYCAT_SEQUENCE" primaryKey="name" dataNode="sh2"/>
# 修改Mycat 配置文件
sequence_db_conf.properties,
GLOBAL=sh2 --->修改
COMPANY=dn1
CUSTOMER=dn1
ORDERS=dn1
# 在sh2节点的 主 数据库中添加 MYCAT_SEQUENCE表
DROP TABLE IF EXISTS MYCAT_SEQUENCE;
CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT NOT
NULL,increment INT NOT NULL DEFAULT 100,PRIMARY KEY(name)) ENGINE=InnoDB;
# 在dn2节点的 主库数据库中的 MYCAT_SEQUENCE 表
插入sequence初始记录
insert into MYCAT_SEQUENCE(name,current_value,increment ) VALUES('GLOBAL',10000,100);
# 在sh2节点的 主数据库中创建存储过程
## 获取当前sequence的值:
DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER $
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64)
CHARSET utf8 DETERMINISTIC BEGIN DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO
retval FROM MYCAT_SEQUENCE WHERE name =seq_name;
RETURN retval;
END $
DELIMITER ;
## 设置sequence值:
DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER $
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS
varchar(64) CHARSET utf8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = value WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END $
DELIMITER ;
## 获取下一个sequence值:
DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER $
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64)
CHARSET utf8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END $
DELIMITER ;
# 测试获取全局自增ID
mysql> insert into t4(id,name) values(NEXT VALUE FOR MYCATSEQ_GLOBAL,'zy') ;

12.4 时间戳方式

ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加)
server.xml:
<system><property name="sequnceHandlerType">2</property>
</system>
sequence_time_conf.properties:
WORKID=0-31 任意整数

 

赞(0)
MySQL学习笔记 » 21 MySQL分布式架构