# Mycat2搭建MySQL读写分离

# Mycat安装及配置

# 安装

# 下载安装包

下载对应的 tar 安装包,以及对应的 jar 包。

tar包: http://dl.mycat.org.cn/2.0/install-template/ 下载最新的tar包mycat2-install-template-1.21.zip。

jar包:http://dl.mycat.org.cn/2.0 在xx.xx-release目录下载最新的jar包mycat2-1.22-release-jar-with-dependencies.jar。

把这个 jar 放进解压的 tar 中的 mycat\lib 文件夹下:

# 服务器安装

  • 安装mycat

通过ssh终端工具上传mycat包至服务器 /usr/local/

[root@localhost mycat]# pwd
/usr/local/mycat
[root@localhost mycat]# ll
总用量 8
drwxr-xr-x. 2 root root 4096 35 2021 bin
drwxr-xr-x. 9 root root  275 619 12:06 conf
drwxr-xr-x. 2 root root 4096 618 22:05 lib
drwxr-xr-x. 2 root root   42 619 17:02 logs
1
2
3
4
5
6
7
8

修改bin目录下[mycatwrapper-linux-ppc-64wrapper-linux-x86-32wrapper-linux-x86-64]文件的权限,修改成最高权限,否则运行启动命令时,会因权限不足而报错:

[root@localhost bin]# chmod 777 mycat wrapper-linux-*
1
  • 安装JDK

jar包执行需要JDK环境,还需要安装JDK,并配置JDK环境变量。

通过https://www.oracle.com/java/technologies/downloads/#java8 下载jdk8,这里下载的是jdk-8u333-linux-x64.tar.gz (opens new window) 。通过ssh工具上传至服务器,解压至/usr/local/

[root@localhost opt]# tar -xvf jdk-8u333-linux-x64.tar.gz -C /usr/local/
1

配置环境变量:

# /etc/profile 文件会遍历/etc/profile.d/目录下的.sh文件,所有这里新增my_env.sh,把环境变量配置在其中即可。
[root@localhost opt]# vim /etc/profile.d/my_env.sh 

# 配置我们自己的环境变量
# JAVA_HOME
export JAVA_HOME=/usr/local/jdk1.8.0_333
export PATH=$PATH:$JAVA_HOME/bin

# 让配置的环境变量生效
[root@localhost opt]# source /etc/profile
1
2
3
4
5
6
7
8
9
10

# 启动Mycat

1、在mycat连接的mysql数据库里添加用户

创建用户 ,用户名为mycat,密码为123456,赋权限,如下:

--创建mycat用户
CREATE USER 'mycat'@'%' IDENTIFIED BY '123456'; 
--必须要赋的权限 mysql8才有的 
GRANT XA_RECOVER_ADMIN ON *.* TO 'root'@'%'; 
--视情况赋权限 
GRANT ALL PRIVILEGES ON *.* TO 'mycat'@'%' ; 
--刷新权限
flush privileges;
1
2
3
4
5
6
7
8

2、修改mycat的prototype的配置

启动mycat之前需要确认prototype数据源所对应的mysql数据库配置,修改对应的 user(用户),password(密码),url中的ip。路径/usr/local/mycat/conf/datasources/prototypeDs.datasource.json

{
	"dbType":"mysql",
	"idleTimeout":60000,
	"initSqls":[],
	"initSqlsGetConnection":true,
	"instanceType":"READ_WRITE",
	"maxCon":1000,
	"maxConnectTimeout":10000,
	"maxRetryCount":5,
	"minCon":1,
	"name":"prototypeDs",
	"password":"123456",
	"type":"JDBC",
	"url":"jdbc:mysql://localhost:3306/mydb?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&allowPublicKeyRetrieval=true",
	"user":"mycat",
	"weight":0
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

3、验证数据库访问情况

Mycat 作为数据库中间件要和数据库部署在不同机器上,所以要验证远程访问情况。

mysql -umycat -p123456 -h 192.168.10.10 -P 3306

#如远程访问报错,请建对应用户
grant all privileges on *.* to mycat@'缺少的host' identified by '123456';
1
2
3
4

4、启动mycat

linux启动命令

cd mycat/bin 
./mycat start 启动
./mycat status 查看状态 
./mycat stop 停止 
./mycat console 前台运行 
./mycat install 添加到系统自动启动(暂未实现) 
./mycat remove 取消随系统自动启动(暂未实现) 
./mycat restart 重启服务 
./mycat pause 暂停 
./mycat status 查看启动状态
1
2
3
4
5
6
7
8
9
10

# 配置文件

# 服务(server)

通过server配置负载均衡策略、端口号、工作池等,可以采用默认配置。

/usr/local/mycat/conf/server.json

{
  "loadBalance":{
    "defaultLoadBalance":"BalanceRandom",
    "loadBalances":[]
  },
  "mode":"local",
  "properties":{},
  "server":{
    "bufferPool":{

    },
    "idleTimer":{
      "initialDelay":3,
      "period":60000,
      "timeUnit":"SECONDS"
    },
    "ip":"0.0.0.0",
    "mycatId":1,
    "port":8066,
    "reactorNumber":8,
    "tempDirectory":null,
    "timeWorkerPool":{
      "corePoolSize":0,
      "keepAliveTime":1,
      "maxPendingLimit":65535,
      "maxPoolSize":2,
      "taskTimeout":5,
      "timeUnit":"MINUTES"
    },
    "workerPool":{
      "corePoolSize":1,
      "keepAliveTime":1,
      "maxPendingLimit":65535,
      "maxPoolSize":1024,
      "taskTimeout":5,
      "timeUnit":"MINUTES"
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 用户(user)

配置客户端登录的用户名、密码、IP等,新增用户会以 {用户名}.user.json 命名。

/usr/local/mycat/conf/users

[root@localhost users]# ll
总用量 4
-rw-r--r--. 1 root root 110 1228 14:05 root.user.json
[root@localhost users]# vim root.user.json 
{
	"dialect":"mysql",
	"ip":null,
	"password":"123456",
	"transactionType":"proxy",
	"username":"root"
}
1
2
3
4
5
6
7
8
9
10
11

字段含义 ip:客户端访问ip,建议为空,填写后会对客户端的ip进行限制 username:用户名 password:密码 isolation:设置初始化的事务隔离级别

READ_UNCOMMITTED:1 
READ_COMMITTED:2 
REPEATED_READ:3,默认 
SERIALIZABLE:4
1
2
3
4

transactionType:事务类型 可选值: proxy 本地事务,在涉及大于 1 个数据库的事务,commit 阶段失败会导致不一致,但是兼容 性最好 xa 事务,需要确认存储节点集群类型是否支持 XA 可以通过语句实现切换

set transaction_policy = 'xa'
set transaction_policy = 'proxy'
1
2

可以通过语句查询

SELECT @@transaction_policy
1

# 数据源(datasource)

配置Mycat连接的数据源信息,新增数据源会以{数据源名字}.datasource.json 命名。

/usr/local/mycat/conf/datasources

{
	"dbType":"mysql",
	"idleTimeout":60000,
	"initSqls":[],
	"initSqlsGetConnection":true,
	"instanceType":"READ_WRITE",
	"maxCon":1000,
	"maxConnectTimeout":10000,
	"maxRetryCount":5,
	"minCon":1,
	"name":"prototypeDs",
	"password":"Aotu@123",
	"type":"JDBC",
	"url":"jdbc:mysql://192.168.10.11:3306/aotuxx?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&allowPublicKeyRetrieval=true",
	"user":"aotuxx",
	"weight":0
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

字段含义

dbType:数据库类型,mysql name:用户名 password:密码 type:数据源类型,默认 JDBC url:访问数据库地址 idleTimeout:空闲连接超时时间 initSqls:初始化sql initSqlsGetConnection:对于 jdbc 每次获取连接是否都执行 initSqls instanceType:配置实例只读还是读写 可选值: READ_WRITE,READ,WRITE weight :负载均衡权重 连接相关配置 maxCon: 1000, maxConnectTimeout: 3000, maxRetryCount: 5, minCon: 1

# 集群(cluster)

配置集群信息,所在目录 /usr/local/mycat/conf/clusters,命名方式:{集群名字}.cluster.json

prototype.cluster.json 内容:

{
	"clusterType":"MASTER_SLAVE",
	"heartbeat":{
		"heartbeatTimeout":1000,
		"maxRetryCount":3,
		"minSwitchTimeInterval":300,
		"showLog":false,
		"slaveThreshold":0.0
	},
	"masters":[ //配置多个主节点,在主挂的时候会选一个检测存活的数据源作
		"rwSepw"
	],
	"maxCon":2000,
	"name":"prototype",
	"readBalanceType":"BALANCE_ALL",
	"replicas":[ //配置多个从节点
		"rwSepr"
	],
	"switchType":"SWITCH",
    // 可选值
    "timer": { //MySQL集群心跳周期,配置则开启集群心跳,Mycat主动检测主从延迟以 及高可用主从切换 
		"initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    }, 
    //readBalanceName:"BALANCE_ALL", 
    //writeBalanceName:"BALANCE_ALL",
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

字段含义

clusterType:集群类型 可选值: SINGLE_NODE: 单一节点 MASTER_SLAVE: 普通主从 GARELA_CLUSTER: garela cluster/PXC 集群 MHA:MHA 集群 MGR:MGR 集群

readBalanceType:查询负载均衡策略 可选值: BALANCE_ALL(默认值) : 获取集群中所有数据源 BALANCE_ALL_READ: 获取集群中允许读的数据源 BALANCE_READ_WRITE: 获取集群中允许读写的数据源,但允许读的数据源优先 BALANCE_NONE : 获取集群中允许写数据源,即主节点中选择

switchType:切换类型 可选值: NOT_SWITCH: 不进行主从切换 SWITCH: 进行主从切换

# 逻辑库表(schema)

配置逻辑库表,实现分库分表。所在目录 /usr/local/mycat/conf/schemas, 命名方式{库名}.schema.json

aotuxx.schema.json内容:

# 库配置
{
	"customTables":{},
	"globalTables":{},
	"normalProcedures":{},
	"normalTables":{},
	"schemaName":"aotuxx",
	"targetName":"prototype",
	"shardingTables":{},
	"views":{}
}
1
2
3
4
5
6
7
8
9
10
11

schemaName:逻辑库名

targetName:目的数据源或集群

targetName自动从prototype目标加载aotuxx库下的物理表或者视图作为单表,prototype 必须是mysql服务器 。

# Mycat搭建读写分离

我们通过 Mycat 和 MySQL 的主从复制配合搭建数据库的读写分离,实现 MySQL 的高可用性。我们将搭建:一主一从、双主双从两种读写分离模式。

VMware踩过的坑:如果通过一台虚拟机克隆其他机器搭建MySQL集群时,MySQL的server-uuid都一样,而一样的server-uuid会导致主从复制失败。可以通过/var/lib/mysql/auto.cnf修改里面的server-uuid解决主从复制失败的问题。

# 搭建一主一从

一个主机用于处理所有写请求,一台从机负责所有读请求,架构图如下:

# 搭建MySQL数据库主从复制

1)MySQL 主从复制原理

  • binary log的作用

binlog在MySQL中默认是不开启的,因为开启它需要消耗一定的性能。如果我们需要使用到binlog则可以选择性的开启它。比如我们需要做主从同步的集群环境的时候,master主库上面的binlog是必须要打开的。这也是binlog存在的一个重要的功能,为主从同步提供支撑。

开启binlog之后,它只会记录我们的增、删、改的操作,查询的操作它是不会记录的。也就是说,它只记录对数据库有变更的操作,如果没有变更则不会记录在binlog日志文件中。对于平时我们的一些DDL操作也会被记录在binlog日志文件中,比如我们删除一个表、增加一个列、创建一个索引、删除一个索引等这样的操作,也会被记录在binlog日志文件中。

  • relay log的作用

Relay log 一般叫做中继日志,一般情况下它在MySQL主从同步读写分离集群的从节点才开启。主节点一般不需要这个日志。

master主节点的binlog传到slave从节点后,被写道relay log里,从节点的slave sql线程从relaylog里读取日志然后应用到slave从节点本地。从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后SQL线程会读取relay-log日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致。

它的作用可以参考上图,从图片中可以看出,它是一个中介临时的日志文件,用于存储从master节点同步过来的binlog日志内容,它里面的内容和master节点的binlog日志里面的内容是一致的。然后slave从节点从这个relaylog日志文件中读取数据应用到数据库中,来实现数据的主从复制。

(2)主机配置

修改配置文件:vim /etc/my.cnf

#主服务器唯一ID 
server-id=1 

#启用二进制日志, 可以指定具体的路径(目录需要给mysql用户权限),不指定默认生成在/var/lib/mysql下mysql-bin.xxx
log-bin=/data/logs/binlogs/mysql-bin
# 设置binlog清理时间7天:7*24*3600
binlog_expire_logs_seconds=604800
# binlog每个日志文件的大小
max_binlog_size=100m
# binlog缓存大小
binlog_cache_size=4m
# 最大binlog缓存大小
max_binlog_cache_size=512m

# 设置不要复制的数据库(可设置多个) 
binlog-ignore-db=mysql 
binlog-ignore-db=information_schema 
#设置需要复制的数据库 
binlog-do-db=需要复制的主数据库名字 
#设置logbin格式 
binlog_format=STATEMENT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

(3)从机配置

修改配置文件:vim /etc/my.cnf

#从服务器唯一ID 
server-id=2 

#启用中继日志,指定具体目录(目录需要给mysql用户权限)
relay-log=/data/logs/relaylogs/mysql-relay
#每个relaylog日志文件的大小
max_relay_log_size=100m
1
2
3
4
5
6
7

(4)主机、从机重启 MySQL 服务

systemctl restart mysqld
1

(5)主机从机都关闭防火墙

# 关闭防火墙
systemctl stop firewalld
# 禁用防火墙
systemctl disable firewalld
1
2
3
4

(6)在主机上建立帐户并授权 slave

作用:从机通过slave账号将主机数据复制到从机中。

#在主机MySQL里执行授权命令 
CREATE USER 'slave'@'%' IDENTIFIED BY '123456'; GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%'; 

#此语句必须执行 
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456'; 

# 刷新权限
flush privileges; 

#查询master的状态 
show master status;

#记录下File和Position的值 
#执行完此步骤后不要再操作主服务器MySQL,防止主服务器状态值变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14

(7)在从机上配置需要复制的主机

#复制主机的命令
CHANGE MASTER TO MASTER_HOST='主机的IP地址', 
MASTER_USER='slave', MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.具体数字',MASTER_LOG_POS=具体值;

#启动从服务器复制功能
start slave;

#查看从服务器状态
show slave status\G;

#下面两个参数都是Yes,则说明主从配置成功! 
# Slave_IO_Running: Yes 
# Slave_SQL_Running: Yes
1
2
3
4
5
6
7
8
9
10
11
12
13
14

(8)主机新建库、新建表、insert 记录,从机复制

#建库语句 
CREATE DATABASE mydb1; 
#建表语句 
CREATE TABLE mytbl(id INT,NAME VARCHAR(50)); 
#插入数据 
INSERT INTO mytbl VALUES(1,"zhang3");
1
2
3
4
5
6

(9) 如何停止从服务复制功能

stop slave;
1

(10)如何重新配置主从

stop slave; 
reset master;
1
2

reset master 作用:

  • 删除binlog索引文件中列出的所有binlog文件
  • 清空binlog索引文件
  • 创建一个新的binlog文件
  • 清空系统变量gtid_purged和gtid_executed
  • 在MySQL 5.7.5 及后续版本中, RESET MASTER还会会清空 mysql.gtid_executed 数据表。

reset slave 作用:

  • 清除slave 复制时的master binlog的位置
  • 清空master info, relay log info
  • 删除所有的relay log文件,并创建一个新的relay log文件。
  • 重置复制延迟(CHANGE MASTER TO 的 MASTER_DELAY参数指定的)为0。

重置操作之后,就需要使用 CHANGE MASTER TO ... 重新指定复制连接参数。

# 配置Macat读写分离

登录Mycat,创建逻辑库,配置数据源。

在Mycat里创建数据库mydb1

#创建mydb1逻辑库
create database mydb1;
1
2

执行以上sql后/usr/local/mycat/conf/schemas 目录下会创建 mydb1.schema.json 文件。

修改mydb1.schema.json 指定数据源 "targetName": "prototype",配置主机数据源

vim /usr/local/mycat/conf/schemas/mydb1.schema.json

{
	"customTables":{},
	"globalTables":{},
	"normalProcedures":{},
	"normalTables":{},
	"schemaName":"mydb1",
	"targetName":"prototype", //新增这一行,指定数据源
	"shardingTables":{},
	"views":{}
}
1
2
3
4
5
6
7
8
9
10

使用注解方式添加数据源

#登录Mycat,注解方式添加数据源,指向从机
/*+ mycat:createDataSource{ "name":"rwSepw", "url":"jdbc:mysql://192.168.10.11:3306/mydb1?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&allowPublicKeyRetrieval=true", "user":"mycat", "password":"123456" } */; 
/*+ mycat:createDataSource{ "name":"rwSepr", "url":"jdbc:mysql://192.168.10.12:3306/mydb1?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&allowPublicKeyRetrieval=true", "user":"mycat", "password":"123456" } */;

#查询配置数据源结果
/*+ mycat:showDataSources{} */;
1
2
3
4
5
6

mycat 用户具有访问 mydb1 库的权限。

更新集群信息,添加主从节点,实现读写分离

#更新集群信息,添加dr0从节点 
/*! mycat:createCluster{"name":"prototype","masters":["rwSepw"],"replicas":["rwSepr"]} */;
#查看配置集群信息
/*+ mycat:showClusters{} */;
1
2
3
4

查看集群配置文件 vim /usr/local/mycat/conf/clusters/prototype.cluster.json

{
	"clusterType":"MASTER_SLAVE",
	"heartbeat":{
		"heartbeatTimeout":1000,
		"maxRetryCount":3,
		"minSwitchTimeInterval":300,
		"showLog":false,
		"slaveThreshold":0.0
	},
	"masters":[ //配置多个主节点,在主挂的时候会选一个检测存活的数据源作
		"rwSepw"
	],
	"maxCon":2000,
	"name":"prototype",
	"readBalanceType":"BALANCE_ALL",
	"replicas":[ //配置多个从节点
		"rwSepr"
	],
	"switchType":"SWITCH",
    // 可选值
    "timer": { //MySQL集群心跳周期,配置则开启集群心跳,Mycat主动检测主从延迟以及高可用主从切换 
		"initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    }
}

#readBalanceType: 查询负载均衡策略 
#可选值: BALANCE_ALL(默认值) 
#获取集群中所有数据源:BALANCE_ALL_READ 
#获取集群中允许读的数据源:BALANCE_READ_WRITE 
#获取集群中允许读写的数据源,但允许读的数据源优先:BALANCE_NONE 

#switchType 
#NOT_SWITCH:不进行主从切换 
#SWITCH:进行主从切换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 重新启动Mycat

./usr/local/mycat/bin/mycat restart
1

# 验证读写分离

(1)在写主机数据库表mytbl中插入带系统变量数据,造成主从数据不一致 。

INSERT INTO mytbl VALUES(2, @@hostname);
1

(2)在Mycat里查询mytbl表,可以看到查询语句在主从两个主机间切换。

# 搭建双主双从

一个主机 m1 用于处理所有写请求,它的从机 s1 和另一台主机 m2 还有它的从机 s2 负责所有读请求。当 m1 主机宕机后,m2 主机负责写请求,m1、m2 互为备机。架构图 如下

# 搭建MySQL数据库主从复制(双主双从)

(1)双主机配置

配置Master1,修改配置文件:vim /etc/my.cnf

#主服务器唯一ID 
server-id=1 

#启用二进制日志,可以指定具体的路径(目录需要给mysql用户权限),不指定默认生成在/var/lib/mysql下mysql-bin.xxx
log-bin=/data/logs/binlogs/mysql-bin
# 设置binlog清理时间7天:7*24*3600
binlog_expire_logs_seconds=604800
# binlog每个日志文件的大小
max_binlog_size=100m
# binlog缓存大小
binlog_cache_size=4m
# 最大binlog缓存大小
max_binlog_cache_size=512m

# 设置不要复制的数据库(可设置多个) 
binlog-ignore-db=mysql 
binlog-ignore-db=information_schema 
#设置需要复制的数据库 
binlog-do-db=需要复制的主数据库名字
#设置logbin格式 
binlog_format=STATEMENT

# 在作为从数据库的时候,有写入操作也要更新二进制日志文件 
log-slave-updates 
#表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是 1 .. 65535 
auto-increment-increment=2 
# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535 
auto-increment-offset=1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

配置Master2,修改配置文件:vim /etc/my.cnf

#主服务器唯一ID 
server-id=2 
#启用二进制日志,可以指定具体的路径(目录需要给mysql用户权限),不指定默认生成在/var/lib/mysql下mysql-bin.xxx
log-bin=/data/logs/binlogs/mysql-bin
# 设置binlog清理时间7天:7*24*3600
binlog_expire_logs_seconds=604800
# binlog每个日志文件的大小
max_binlog_size=100m
# binlog缓存大小
binlog_cache_size=4m
# 最大binlog缓存大小
max_binlog_cache_size=512m

# 设置不要复制的数据库(可设置多个) 
binlog-ignore-db=mysql 
binlog-ignore-db=information_schema 
#设置需要复制的数据库 
binlog-do-db=需要复制的主数据库名字 
#设置logbin格式 
binlog_format=STATEMENT 

# 在作为从数据库的时候,有写入操作也要更新二进制日志文件 
log-slave-updates 
#表示自增长字段每次递增的量,指自增字段的起始值,其默认值是1,取值范围是 1 .. 65535 
auto-increment-increment=2 
# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1 .. 65535 
auto-increment-offset=2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

(2)双从机配置

配置Slave1,修改配置文件:vim /etc/my.cnf

#从服务器唯一ID
server-id=3 
#启用中继日志,指定具体目录(目录需要给mysql用户权限)
relay-log=/data/logs/relaylogs/mysql-relay
#每个relaylog日志文件的大小
max_relay_log_size=100m
1
2
3
4
5
6

配置Slave2,修改配置文件:vim /etc/my.cnf

#从服务器唯一ID 
server-id=4 
#启用中继日志,指定具体目录(目录需要给mysql用户权限)
relay-log=/data/logs/relaylogs/mysql-relay
#每个relaylog日志文件的大小
max_relay_log_size=100m
1
2
3
4
5
6

(3)双主机、双从机重启 mysql 服务

systemctl restart mysqld
1

(4)主机从机都关闭防火墙

# 关闭防火墙
systemctl stop firewalld
# 禁用防火墙
systemctl disable firewalld
1
2
3
4

(5)在两台主机上建立帐户并授权 slave

#在主机MySQL里执行授权命令 
CREATE USER 'slave'@'%' IDENTIFIED BY '123456'; GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%'; 
#此语句必须执行
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456'; 

#查询Master1的状态 
show master status;

#查询Master2的状态
show master status;

#分别记录下File和Position的值 
#执行完此步骤后不要再操作主服务器MYSQL,防止主服务器状态值变化
1
2
3
4
5
6
7
8
9
10
11
12
13

(6)在从机上配置需要复制的主机

Slava1 复制 Master1,Slava2 复制 Master2。

复制主机的命令:

CHANGE MASTER TO MASTER_HOST='主机的IP地址', 
MASTER_USER='slave', MASTER_PASSWORD='123456', 
MASTER_LOG_FILE='mysql-bin.具体数字',MASTER_LOG_POS=具体值;
1
2
3

启动两台从服务器复制功能:

start slave;
1

查看从服务器状态:

show slave status\G;
1

下面两个参数都是Yes,则说明主从配置成功! Slave_IO_Running: Yes Slave_SQL_Running: Yes

(7)两个主机互相复制

Master2 复制 Master1,Master1 复制 Master2。

启动两台主服务器复制功能 :

start slave;
1

查看从服务器状态:

show slave status\G;
1

下面两个参数都是Yes,则说明主从配置成功! Slave_IO_Running: Yes Slave_SQL_Running: Yes

(8)Master1 主机新建库、新建表、insert 记录,Master2 和从机复制

(9)如何停止从服务复制功能

stop slave;
1

(10)如何重新配置主从

stop slave; 
reset master;
1
2

reset master 作用:

  • 删除binlog索引文件中列出的所有binlog文件
  • 清空binlog索引文件
  • 创建一个新的binlog文件
  • 清空系统变量gtid_purged和gtid_executed
  • 在MySQL 5.7.5 及后续版本中, RESET MASTER还会会清空 mysql.gtid_executed 数据表。

reset slave 作用:

  • 清除slave 复制时的master binlog的位置
  • 清空master info, relay log info
  • 删除所有的relay log文件,并创建一个新的relay log文件。
  • 重置复制延迟(CHANGE MASTER TO 的 MASTER_DELAY参数指定的)为0。

重置操作之后,就需要使用 CHANGE MASTER TO ... 重新指定复制连接参数。

# 修改Mycat的集群配置实现多种主从

Mycat2.0的特点把集群概念凸显了出来,和mysql主从复制、集群配合实现多节点读写分离 。

(1) 双主双从集群角色划分

m1:主机 
m2:备机,也负责读 
s1,s2:从机
1
2
3

(2)增加两个数据源

/*+ mycat:createDataSource{ "name":"rwSepw2", "url":"jdbc:mysql://192.168.10.13:3306/mydb1?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&allowPublicKeyRetrieval=true", "user":"mycat", "password":"123456" } */;

/*+ mycat:createDataSource{ "name":"rwSepr2","url":"jdbc:mysql://192.168.10.14:3306/mydb1?useSSL=false&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&allowPublicKeyRetrieval=true", "user":"mycat", "password":"123456" } */;
1
2
3

mycat 用户具有访问 mydb1 库的权限。

(3)修改集群配置文件

vim /usr/local/mycat/conf/clusters/prototype.cluster.json

{ 
    "clusterType":"MASTER_SLAVE", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ //配置多个主节点,在主挂的时候会选一个检测存活的数据源作
        "rwSepw","rwSepw2"
    ], 
    "replicas":[ //配置多个从节点
        "rwSepw2","rwSepr","rwSepr2" 
    ],
    "maxCon":200, 
    "name":"prototype", 
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH" , 
    //可选值
    "timer":{ //MySQL集群心跳周期,配置则开启集群心跳,Mycat主动检测主从延迟以及高可用主从切换 
        "initialDelay":30, 
        "period":5,
        "timeUnit":"SECONDS" 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

(4)重启Mycat生效

./usr/local/mycat/bin/mycat restart
1

# 读写分离配置扩展

通过对集群配置的修改,可以根据需求实现更多种情况的读写分离配置,总结如下

(1)读写分离(一主一从,无备)(m是主,s是从)

{ 
    "clusterType":"MASTER_SLAVE", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ "m" ], 
    "replicas":[ "s" ],
    "maxCon":200, 
    "name":"prototype",
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH" , 
    "timer":{ 
        "initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

(2)读写分离(一主一从,一备)(m是主,s是从备)

{ 
    "clusterType":"MASTER_SLAVE", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ "m","s" ], 
    "replicas":[ "s" ],
    "maxCon":200, 
    "name":"prototype", 
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH" ,
    "timer":{ 
        "initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

(3)读写分离(一主一从,一备)(m是主,s是从,b是备)

{ 
    "clusterType":"MASTER_SLAVE", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ "m","b" ], 
    "replicas":[ "s" ],
    "maxCon":200, 
    "name":"prototype", 
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH" , 
    "timer":{ 
        "initialDelay": 30,
        "period":5, 
        "timeUnit":"SECONDS" 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

(4)MHA(一主一从,一备)(m是主,s是从,b是备,READ_ONLY判断主)

{ 
    "clusterType":"MHA", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ "m","b" ], 
    "replicas":["s" ],
    "maxCon":200, 
    "name":"prototype", 
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH" , 
    "timer":{ 
        "initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

(5)MGR(一主一从,一备)(m是主,s是从,b是备,READ_ONLY判断主)

{ 
    "clusterType":"MGR", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ "m","b" ], 
    "replicas":["s" ],
    "maxCon":200, 
    "name":"prototype", 
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH", 
    "timer":{ 
        "initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

(6)GARELA_CLUSTER(一主一从,一备)(m是主,s是从,b多主)

{ 
    "clusterType":"GARELA_CLUSTER", 
    "heartbeat":{ 
        "heartbeatTimeout":1000, 
        "maxRetryCount":3, 
        "minSwitchTimeInterval":300, 
        "slaveThreshold":0 
    },
    "masters":[ "m","b" ], 
    "replicas":["s" ],
    "maxCon":200, 
    "name":"prototype", 
    "readBalanceType":"BALANCE_ALL", 
    "switchType":"SWITCH" , 
    "timer":{ 
        "initialDelay": 30, 
        "period":5, 
        "timeUnit":"SECONDS" 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 分库分表

一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业 务将表进行分类,分布到不同 的数据库上面,这样也就将数据或者说压力分担到不同 的库上面,如下图:

系统被切分成了,用户,订单交易,支付几个模块。

# 如何分库

一个问题:在两台主机上的两个数据库中的表,能否关联查询?

答案:不可以关联查询。

分库的原则:有紧密关联关系的表应该在一个库里,相互没有关联关系的表可以分到 不同的库里。

#客户表 rows:20万
CREATE TABLE customer( id INT AUTO_INCREMENT,NAME VARCHAR(200), PRIMARY KEY(id) );

#订单表 rows:600万
CREATE TABLE orders( id INT AUTO_INCREMENT, order_type INT, customer_id INT, amount DECIMAL(10,2), PRIMARY KEY(id) );

#订单详细表 rows:600万
CREATE TABLE orders_detail( id INT AUTO_INCREMENT, detail VARCHAR(2000), order_id INT, PRIMARY KEY(id) );

#订单状态字典表 rows:20 
CREATE TABLE dict_order_type( id INT AUTO_INCREMENT, order_type VARCHAR(200), PRIMARY KEY(id) );
1
2
3
4
5
6
7
8
9
10
11

以上四个表如何分库?客户表分在一个数据库,另外三张都需要关联查询,分在另外一个数据库。

# 如何分表

1、选择要拆分的表

MySQL 单表存储数据条数是有瓶颈的,单表达到 1000 万条数据就达到了瓶颈,会影响查询效率,需要进行水平拆分(分表)进行优化。 例如:例子中的 orders、orders_detail 都已经达到 600 万行数据,需要进行分表优化。

2、分表字段

以 orders 表为例,可以根据不同自字段进行分表

编号 分表字段 效果
1 id(主键、或创建时间) 查询订单注重时效,历史订单被查询的次数少,如此分片会造成一个节点访问多,一个访问少,不平均。
2 customer_id(客户 id) 根据客户 id 去分,两个节点访问平均,一个客户的所有订单都在同一个节点

# 实现分库分表

Mycat2 一大优势就是可以在终端直接创建数据源、集群、库表,并在创建时指定 分库、分表。与 1.6 版本比大大简化了分库分表的操作。

1、添加数据库、存储数据源

/*+ mycat:createDataSource{ 
"name":"dw0",
"url":"jdbc:mysql://192.168.10.11:3306",
"user":"mycat",
"password":"123456"
} */;

/*+ mycat:createDataSource{ 
"name":"dr0", 
"url":"jdbc:mysql://192.168.10.13:3306", 
"user":"mycat", 
"password":"123456" 
} */;

/*+ mycat:createDataSource{ 
"name":"dw1", 
"url":"jdbc:mysql://192.168.10.12:3306", 
"user":"mycat", 
"password":"123456" 
} */; 

/*+ mycat:createDataSource{ 
"name":"dr1", 
"url":"jdbc:mysql://192.168.10.14:3306", 
"user":"mycat", 
"password":"123456" 
} */;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

通过注释命名添加数据源后,在对应目录会生成相关配置文件

cd /usr/local/mycat/conf/datasources
1

如下图:

2、添加集群配置

把新添加的数据源配置成集群

#在 mycat 终端输入
/*! 
mycat:createCluster{"name":"c0","masters":["dw0"],"replicas":["dr0"]} 
*/;

/*! 
mycat:createCluster{"name":"c1","masters":["dw1"],"replicas":["dr1"]} 
*/;
1
2
3
4
5
6
7
8

可以查看集群配置信息

cd /usr/local/mycat/conf/clusters
1

如下图:

3、创建全局表

#添加数据库db1 
CREATE DATABASE db1;

#在建表语句中加上关键字 BROADCAST(广播,即为全局表)
CREATE TABLE db1.`travelrecord` (
    `id` bigint NOT NULL AUTO_INCREMENT, 
    `user_id` varchar(100) DEFAULT NULL, 
    `traveldate` date DEFAULT NULL, 
    `fee` decimal(10,0) DEFAULT NULL, 
    `days` int DEFAULT NULL, 
    `blob` longblob, PRIMARY KEY (`id`), 
    KEY `id` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;
1
2
3
4
5
6
7
8
9
10
11
12
13

进入相关目录查看 schema 配置

vim /usr/local/mycat/conf/schemas/db1.schema.json
1

可以看到自动生成的全局表配置信息

4、创建分片表(分库分表)

#在 Mycat 终端直接运行建表语句进行数据分片
CREATE TABLE db1.orders( 
    id BIGINT NOT NULL AUTO_INCREMENT, 
    order_type INT,
    customer_id INT, 
    amount DECIMAL(10,2), 
    PRIMARY KEY(id), 
    KEY `id` (`id`) 
)ENGINE=INNODB DEFAULT CHARSET=utf8;

dbpartition BY mod_hash(customer_id) tbpartition BY mod_hash(customer_id) tbpartitions 1 dbpartitions 2;

#数据库分片规则,表分片规则,以及各分多少片
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(1,101,100,100100); 
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(2,101,100,100300); 
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(3,101,101,120000); 
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(4,101,101,103000); 
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(5,102,101,100400); 
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(6,102,100,100020); 
SELECT * FROM orders;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

同样可以查看生成的配置信息,进入相关目录查看 schema 配置

vim /usr/local/mycat/conf/schemas/db1.schema.json
1

查看数据库可见,分片数据:

在 Mycat 终端查询依然可以看到全部数据

5、创建 ER 表

与分片表关联的表如何分表,也就是 ER 表如何分表,如下

#在 Mycat 终端直接运行建表语句进行数据分片
CREATE TABLE orders_detail( 
    `id` BIGINT NOT NULL AUTO_INCREMENT, 
    detail VARCHAR(2000), 
    order_id INT, PRIMARY KEY(id) 
)ENGINE=INNODB DEFAULT CHARSET=utf8;

dbpartition BY mod_hash(order_id) tbpartition BY mod_hash(order_id) tbpartitions 1 dbpartitions 2;

INSERT INTO orders_detail(id,detail,order_id) VALUES(1,'detail1',1); 
INSERT INTO orders_detail(id,detail,order_id) VALUES(2,'detail1',2); 
INSERT INTO orders_detail(id,detail,order_id) VALUES(3,'detail1',3); 
INSERT INTO orders_detail(id,detail,order_id) VALUES(4,'detail1',4); 
INSERT INTO orders_detail(id,detail,order_id) VALUES(5,'detail1',5); 
INSERT INTO orders_detail(id,detail,order_id) VALUES(6,'detail1',6);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

对比数据节点 1

对比数据节点 2

上述两表具有相同的分片算法,但是分片字段不相同,Mycat2 在涉及这两个表的 join 分片字段等价关系的时候可以完成 join 的下推,Mycat2 无需指定 ER 表,是自动识别的,具体看分片算法的接口。

查看配置的表是否具有 ER 关系,使用:

/*+ mycat:showErGroup{}*/
1

group_id 表示相同的组,该组中的表具有相同的存储分布

运行关联查询语句:

SELECT * FROM orders o INNER JOIN orders_detail od ON od.order_id=o.id;
1

原理如下:

# 常用分片规则

1、分片算法简介

Mycat2 支持常用的(自动)HASH 型分片算法也兼容 1.6 的内置的(cobar)分片算法.。

HASH 型分片算法默认要求集群名字以 c 为前缀,数字为后缀,c0 就是分片表第一个 节点,c1 就是第二个节点.该命名规则允许用户手动改变 。

2、Mycat2 与 1.x 版本区别

Mycat2 Hash 型分片算法多数基于 MOD_HASH(MOD 对应 JAVA 的%运算),实际上是取 余运算。

Mycat2 Hash 型分片算法对于值的处理,总是把分片值转换到列属性的数据类型再运算。

而 1.x 系列的分片算法统一转换到字符串类型再运算且只能根据一个分片字段计算 出存储节点下标。

Mycat2 Hash 型分片算法适用于等价条件查询。

而 1.x 系列由于含有用户经验的路由规则。1.x 系列的分片规则总是先转换成字符 串再运算。

3、分片规则与适用性

分片算法 描述 分库 分表 数值类型
MOD_HASH 取模哈希 数值,字符串
UNI_HASH 取模哈希 数值,字符串
RIGHT_SHIFT 右移哈希 数值
RANGE_HASH 两字段其一取模 数值,字符串
YYYYMM 按年月哈希 DATE,DATETIME
YYYYDD 按年日哈希 DATE,DATETIME
YYYYWEEK 按年周哈希 DATE,DATETIME
HASH 取模哈希 数值,字符串,如果不是,则转
MM 按月哈希 DATE,DATETIME
DD 按日期哈希 DATE,DATETIME
MMDD 按日期哈希 DATE,DATETIME
WEEK 按周哈希 DATE,DATETIME
STR_HASH 字符串哈希 字符串

4、常用分片规则简介

(1)MOD_HASH

[数据分片]HASH 型分片算法-MOD_HASH

如果分片值是字符串则先对字符串进行 hash 转换为数值类型

分库键和分表键是同键:

分表下标=分片值%(分库数量*分表数量)

分库下标=分表下标/分表数量

分库键和分表键是不同键:

分表下标= 分片值%分表数量

分库下标= 分片值%分库数量

(2)RIGHT_SHIFT

[数据分片]HASH 型分片算法-RIGHT_SHIFT

RIGHT_SHIFT(字段名,位移数)

仅支持数值类型

分片值右移二进制位数,然后按分片数量取余

(3)YYYYMM

[数据分片]HASH 型分片算法-YYYYMM

仅用于分库

(YYYY*12+MM)%分库数.MM 是 1-12

(4)MMDD

仅用于分表

仅 DATE/DATETIME

一年之中第几天%分表数

tbpartitions 不超过 366

# 全局序列

Mycat2 在 1.x 版本上简化全局序列,自动默认使用雪花算法生成全局序列号,如 不需要 Mycat 默认的全局序列,可以通过配置关闭自动全局序列。

1、建表语句方式关闭全局序列

如果不需要使用 mycat 的自增序列,而使用 mysql 本身的自增主键的功能,需要在配置中更改对应的建表 sql,不设置 AUTO_INCREMENT 关键字,这样,mycat 就不认为这个表有自增主键的功能,就不会使用 mycat 的全局序列号。这样,对应的插入 sql 在 mysql 处理,由 mysql 的自增主键功能补全自增值。

雪花算法:引入了时间戳和 ID 保持自增的分布式 ID 生成算法

建表sql可以自动在原型库对应的逻辑表的物理表获取,如果逻辑表的建表SQL与物理表的建表SQL不对应,则需要在配置文件中配置建表SQL。

例如:

#带 AUTO_INCREMENT 关键字使用默认全局序列
CREATE TABLE db1.`travelrecord` ( 
    `id` bigint NOT NULL AUTO_INCREMENT, 
    `user_id` varchar(100) DEFAULT NULL, 
    `traveldate` date DEFAULT NULL, 
    `fee` decimal(10,0) DEFAULT NULL, 
    `days` int DEFAULT NULL, 
    `blob` longblob, PRIMARY KEY (`id`), 
    KEY `id` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;

#去掉关键字,不使用
CREATE TABLE db1.`travelrecord` ( 
    `id` bigint NOT NULL, 
    `user_id` varchar(100) DEFAULT NULL, 
    `traveldate` date DEFAULT NULL, 
    `fee` decimal(10,0) DEFAULT NULL, 
    `days` int DEFAULT NULL, 
    `blob` longblob, PRIMARY KEY (`id`), 
    KEY `id` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 BROADCAST;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

2、设置 Mycat 数据库方式获取全局序列

(1)、在prototype服务器的db1库导入dbseq.sql文件

Mycat2已经为用户提供了相关sql脚本,需要在对应数据库下运行脚本,不能通过 Mycat客户端执行。

脚本所在目录mycat/conf

脚本内容:

点击查看代码
DROP TABLE IF EXISTS MYCAT_SEQUENCE; 
CREATE TABLE MYCAT_SEQUENCE ( 
    name VARCHAR(64) NOT NULL, 
    current_value BIGINT(20) NOT NULL, 
    increment INT NOT NULL DEFAULT 1, 
    PRIMARY KEY (name) 
) ENGINE=InnoDB; 
-- ---------------------------- 
-- Function structure for `mycat_seq_currval` 
-- ---------------------------- 
DROP FUNCTION IF EXISTS `mycat_seq_currval`; 
DELIMITER ;; 
CREATE FUNCTION `mycat_seq_currval`(seq_name VARCHAR(64)) RETURNS varchar(64) CHARSET latin1 
	DETERMINISTIC 
BEGIN
	DECLARE retval VARCHAR(64); 
	SET retval="-1,0"; 
	SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) ) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name; 
	RETURN retval ; 
END 
;;
DELIMITER ;

-- ---------------------------- 
-- Function structure for `mycat_seq_nextval` 
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_nextval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(64)) RETURNS varchar(64) CHARSET latin1
	DETERMINISTIC
BEGIN
	DECLARE retval VARCHAR(64);
	DECLARE val BIGINT; 
	DECLARE inc INT; 
	DECLARE seq_lock INT; set val = -1; 
	set inc = 0; SET seq_lock = -1; 
	SELECT GET_LOCK(seq_name, 15) into seq_lock;
	if seq_lock = 1 then
		SELECT current_value + increment, increment INTO val, inc FROM MYCAT_SEQUENCE WHERE name = seq_name for update;
        if val != -1 then
            UPDATE MYCAT_SEQUENCE SET current_value = val WHERE name = seq_name;
        end if;
		SELECT RELEASE_LOCK(seq_name) into seq_lock;
	end if;
	SELECT concat(CAST((val - inc + 1) as CHAR),",",CAST(inc as CHAR)) INTO retval;
	RETURN retval;
END
;;
DELIMITER ;

-- ---------------------------- 
-- Function structure for `mycat_seq_setvals` 
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_nextvals`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_nextvals`(seq_name VARCHAR(64), count INT) RETURNS VARCHAR(64) CHARSET latin1
	DETERMINISTIC
BEGIN
	DECLARE retval VARCHAR(64); 
	DECLARE val BIGINT; 
	DECLARE seq_lock INT; 
	SET val = -1; 
	SET seq_lock = -1; 
	SELECT GET_LOCK(seq_name, 15) into seq_lock; 
	if seq_lock = 1 then
		SELECT current_value + count INTO val FROM MYCAT_SEQUENCE WHERE name = seq_name for update;
		IF val != -1 THEN
			UPDATE MYCAT_SEQUENCE SET current_value = val WHERE name = seq_name;
		END IF;
        SELECT RELEASE_LOCK(seq_name) into seq_lock;
	end if;
    SELECT CONCAT(CAST((val - count + 1) as CHAR), ",", CAST(val as CHAR)) INTO retval;
    RETURN retval;
END
;;
DELIMITER ;

-- ---------------------------- 
-- Function structure for `mycat_seq_setval` 
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_setval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_setval`(seq_name VARCHAR(64), value BIGINT) RETURNS varchar(64) CHARSET latin1
	DETERMINISTIC
BEGIN
	DECLARE retval VARCHAR(64); 
	DECLARE inc INT; SET inc = 0; 
	SELECT increment INTO inc FROM MYCAT_SEQUENCE WHERE name = seq_name; 
	UPDATE MYCAT_SEQUENCE SET current_value = value WHERE name = seq_name; 
	SELECT concat(CAST(value as CHAR),",",CAST(inc as CHAR)) INTO retval;
	RETURN retval;
END 
;;
DELIMITER ;

INSERT INTO MYCAT_SEQUENCE VALUES ('GLOBAL', 1, 1);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

(2)、添加全局序列配置文件

进入/mycat/conf/sequences目录,添加配置文件

{数据库名字}_{表名字}.sequence.json

配置内容:

{ 
	"clazz":"io.mycat.plug.sequence.SequenceMySQLGenerator", 
    "name":"db1_travelrecord", 
    "targetName": "prototype", 
    "schemaName":"db1"//指定物理库名 
}
1
2
3
4
5
6

可选参数targetName 更改序列号服务器

"targetName": "prototype" 是执行自增序列的节点,也是dbseq.sql导入的节点

dbseq.sql导入的当前库的库名与逻辑表的逻辑库名一致

导入后检查库下有没有mycat_sequence表。

其中increment是序列号自增的步伐,为1的时候严格按1递增,当1000的时候,mycat会每 次批量递增1000取序列号。此时在多个mycat访问此序列号表的情况下,不能严格自增NAME列中的值是对应的 库名_表名 该值需要用户设置,即插入一条逻辑表相关的记录,用于记录序列号。

(3)、切换为数据库方式全局序列号

使用注释前要导入dbseq.sql以及设置mycat_sequence表内的逻辑表记录

通过注释设置为数据库方式全局序列号

/*+ mycat:setSequence{ 
"name":"db1_travelrecord", 
"clazz":"io.mycat.plug.sequence.SequenceMySQLGenerator", 
"name":"db1_travelrecord", 
"targetName": "prototype", 
"schemaName":"db2" 
} */;
1
2
3
4
5
6
7

(4)、切换为雪花算法方式全局序列号

/*+ mycat:setSequence{"name":"db1_travelrecord","time":true} */;
1

# Mycat 安全设置

# 权限配置

1、user 标签权限控制

目前 Mycat 对于中间件的连接控制并没有做太复杂的控制,目前只做了中间件 逻辑库级别的读写权限控制。是通过 mycat/conf/users 目录下的{用户名}.user.json 进行配置。

#root.user.json 
{ 
    "dialect":"mysql", 
    "ip":null, 
    "password":"123456", 
    "transactionType":"xa", 
    "username":"root" 
}
1
2
3
4
5
6
7
8

如下图:

配置说明:

标签属性 说明
name 应用连接中间件逻辑库的用户名
password 该用户对应的密码
ip 建议为空,填写后会对客户端的 ip 进行限制
dialect 使用语言,默认 mysql
transactionType 事务类型,默认 proxy
proxy:本地事务,在涉及大于 1 个数据库的事务,commit 阶段失败会导致不一致,但是兼容性最好
xa:分布式事务,需要确认存储节点集群类型是否支持 XA
更改命令:set transaction_policy = 'xa'
set transaction_policy = 'proxy'
查看命令:SELECT @@transaction_policy

2、权限说明

Mycat2 权限分为两块:登录权限、sql 权限。

(1)登录权限

Mycat2 在 MySQL 网络协议的时候检查客户端的 IP,用户名,密码 。其中 IP 使用正则表达式匹配,一旦匹配成功,就放行。

**(2)sql 权限 **

使用自定义拦截器实现。