利用MyCAT实现MySQL的读写分离
Posted y_zilong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用MyCAT实现MySQL的读写分离相关的知识,希望对你有一定的参考价值。
环境准备:
服务器共三台
所在主机的系统环境 CentOS Linux release 8.3.2011
mycat-server 10.0.0.10 #内存建议2G以上
mysql-master 10.0.0.20 mysql 8.0
mysql-slave 10.0.0.30 mysql 8.0
关闭selinux和firewalld,时间同步
systemctl stop firewalld
setenforce 0
ntpdate ntp.aliyun.com
1、创建MySQL主从数据库(详细步骤可以参考主从复制的那篇文章)
[root@mysql-master ~]# yum -y install mysql-server
[root@mysql-slave ~]# yum -y install mysql-server
#修改master和slave上的配置文件
[root@mysql-master ~]# vi /etc/my.cnf
[mysqld]
server-id=20
log-bin
[root@mysql-master ~]# systemctl enable --now mysqld
[root@mysql-slave ~]# vi /etc/my.cnf
[mysqld]
server-id=30
[root@mysql-slave ~]# systemctl enable --now mysqld
#master授权一个账号给从、可以从主复制数据
mysql> create user yzil@'%' identified by 'redhat';
mysql> grant replication slave on *.* to yzil@'%';
mysql> show master status;
mysql-master-bin.000001 | 659 |
#slave使用有复制权限的用户账号连接至主服务器,并启动复制线程
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.0.0.20',
-> MASTER_USER='yzil',
-> MASTER_PASSWORD='redhat',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mysql-master-bin.000001',
-> MASTER_LOG_POS=659;
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.20
Master_User: yzil
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-master-bin.000001
Read_Master_Log_Pos: 659
Relay_Log_File: mysql-slave-relay-bin.000002
Relay_Log_Pos: 331
Relay_Master_Log_File: mysql-master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
mysql>
2、在MySQL代理服务器10.0.0.10安装mycat并启动
[root@mycat-server ~]# yum -y install java
#确认安装成功
[root@mycat-server ~]# java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)
#下载并安装
[root@mycat-server ~]# wget http://dl.mycat.org.cn/1.6.7.6/20210303094759/Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz
[root@mycat-server ~]# mkdir /apps
[root@mycat-server ~]# tar xvf Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz -C /apps/
#配置环境变量
[root@mycat-server apps]# echo 'PATH=/apps/mycat/bin:$PATH' > /etc/profile.d/mycat.sh
[root@mycat-server apps]# source /etc/profile.d/mycat.sh
#查看端口
[root@mycat-server apps]# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 100 127.0.0.1:25 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
#启动mycat
[root@mycat-server ~]# cd /apps/mycat/bin/
[root@mycat-server bin]# mycat
Usage: /apps/mycat/bin/mycat { console | start | stop | restart | status | dump }
#注意:此步启动较慢,需要等一会儿,另外如果内存太小,会导致无法启动
[root@mycat-server bin]# mycat start
Starting Mycat-server...
#可以看到打开多个端口,其中8066端口用于连接mycat
[root@mycat-server bin]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=971,fd=4))
LISTEN 0 100 127.0.0.1:25 0.0.0.0:* users:(("master",pid=1328,fd=16))
LISTEN 0 1 127.0.0.1:32000 0.0.0.0:* users:(("java",pid=26914,fd=4))
LISTEN 0 50 *:36691 *:* users:(("java",pid=26914,fd=74))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=971,fd=6))
LISTEN 0 100 [::1]:25 [::]:* users:(("master",pid=1328,fd=17))
LISTEN 0 50 *:1984 *:* users:(("java",pid=26914,fd=73))
LISTEN 0 128 *:8066 *:* users:(("java",pid=26914,fd=103))
LISTEN 0 50 *:38819 *:* users:(("java",pid=26914,fd=72))
LISTEN 0 128 *:9066 *:* users:(("java",pid=26914,fd=99))
[root@mycat-server bin]#
#查看日志,确定成功,可能需要一会才能看到成功的提示
[root@mycat-server ~]# tail /apps/mycat/logs/wrapper.log
STATUS | wrapper | 2021/05/24 13:12:26 | --> Wrapper Started as Daemon
STATUS | wrapper | 2021/05/24 13:12:26 | Launching a JVM...
INFO | jvm 1 | 2021/05/24 13:12:27 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
INFO | jvm 1 | 2021/05/24 13:12:27 | Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved.
INFO | jvm 1 | 2021/05/24 13:12:27 |
INFO | jvm 1 | 2021/05/24 13:12:35 | MyCAT Server startup successfully. see logs in logs/mycat.log
[root@mycat-server ~]#
用默认密码123456来连接mycat
Centos8:无法连接mycat需要加参数连接
[root@mysql-slave ~]# mysql -uroot -p'123456' -h 10.0.0.10 -P8066
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (HY000): Access denied for user 'root', because password is error[root@mysql-master ~]# vi /etc/my.cnf
[client]
default-auth=mysql_native_password
[root@mysql-master ~]#
[root@mysql-master ~]# mysql -uroot -p'123456' -h 10.0.0.10 -P8066
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 11
Server version: 5.6.29-mycat-1.6.7.6-release-20210303094759 MyCat Server (OpenCloudDB)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.
mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB |
+----------+
1 row in set (0.00 sec)
mysql>
3、定义mycat
mycat分前端和后端
前端,定义给前端APP连接
后端,定义转发至真实mysql server的规则
注意:前端APP连接数据库,只能连它自己的数据库,所以定义都是按库为单位进行定义的,不是整个mysql server
后端真实库的权限问题,不要设置的太高
在mycat服务器上修改server.xml文件配置Mycat的连接信息,定义前端
[root@mycat-server ~]# vi /apps/mycat/conf/server.xml
<!--
<property name="serverPort">8066</property>
<property name="managerPort">9066</property>
<property name="idleTimeout">300000</property>
<property name="authTimeout">15000</property>
<property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //连接空闲检查
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">TESTDB</property>
#改为下面
#修改8066改为3306,并取消注释信息
<property name="serverPort">3306</property>
<property name="managerPort">9066</property>
<property name="idleTimeout">300000</property>
<property name="authTimeout">15000</property>
<property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property>
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property>
或者:修改下面行的8066改为3306复制到独立非注释行
<property name="serverPort">3306</property>
<property name="handleDistributedTransactions">0</property> #将上面行放在此行前面
<user name="root" defaultAccount="true"> #连接mycat的用户名
<property name="password">redhat</property> #连接mycat的密码
<property name="schemas">TESTDB</property> #数据库名要和schema.xml相对应
#查看监听端口变为3306
[root@mycat-server bin]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=971,fd=4))
LISTEN 0 100 127.0.0.1:25 0.0.0.0:* users:(("master",pid=1328,fd=16))
LISTEN 0 1 127.0.0.1:32000 0.0.0.0:* users:(("java",pid=27529,fd=4))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=971,fd=6))
LISTEN 0 50 *:34327 *:* users:(("java",pid=27529,fd=72))
LISTEN 0 100 [::1]:25 [::]:* users:(("master",pid=1328,fd=17))
LISTEN 0 50 *:1984 *:* users:(("java",pid=27529,fd=73))
LISTEN 0 50 *:44771 *:* users:(("java",pid=27529,fd=74))
LISTEN 0 128 *:3306 *:* users:(("java",pid=27529,fd=103))
LISTEN 0 128 *:9066 *:* users:(("java",pid=27529,fd=99))
[root@mycat-server bin]#
这里使用的是root,密码是redhat,逻辑数据库为TESTDB,可以定义多个TESTDB和TESTDB2,这些信息都可以自己随意定义,读写权限都有,没有针对表做任何特殊的权限。
4、修改schema.xml实现读写分离策略,定义后端
[root@mycat-server ~]# vi /apps/mycat/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
#定义schema,也就是后端虚拟库,并指定对应的虚拟节点
#当前端访问TESTDB这个虚拟库时,会转发到dn1这个节点
#建议虚拟库名和真实库名一致
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema>
#定义虚拟节点主机信息,及对应的真实库名称
#当前端访问请求到dn1,会转发到localhost1这个主机的db1库
#注意:db1指的是后端真实的库名
<dataNode name="dn1" dataHost="localhost1" database="hellodb" />
#定义localhost1这个主机对应的真实后端,并指定路由规则
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
#心跳检测,检测后端真实server的可用性,使用select user()语句去检测
<heartbeat>select user()</heartbeat>
#指定主要的写主机与读主机
#注意,账号密码,最好重新创建一个,尽量不要使用root
#注意,写,不能同时写,会有锁等待问题,一次写操作,只能在一个写节点进行写,读可以多个
<writeHost host="host1" url="10.0.0.20:3306" user="root"
password="123456">
<readHost host="host1" url="10.0.0.30:3306" user="root"
password="123456" />
</writeHost>
#定义的虚拟节点对应的真实节点的路由规则
</dataHost>
</mycat:schema>
#重新启动mycat
[root@mycat-server ~]# cd /apps/mycat/bin/
[root@mycat-server bin]# mycat restart
[root@mycat-server bin]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=963,fd=4))
LISTEN 0 100 127.0.0.1:25 0.0.0.0:* users:(("master",pid=1460,fd=16))
LISTEN 0 1 127.0.0.1:32000 0.0.0.0:* users:(("java",pid=7156,fd=4))
LISTEN 0 128 *:3306 *:* users:(("java",pid=7156,fd=103))
LISTEN 0 128 *:9066 *:* users:(("java",pid=7156,fd=99))
LISTEN 0 50 *:38101 *:* users:(("java",pid=7156,fd=72))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=963,fd=6))
LISTEN 0 100 [::1]:25 [::]:* users:(("master",pid=1460,fd=17))
LISTEN 0 50 *:40957 *:* users:(("java",pid=7156,fd=74))
LISTEN 0 50 *:1984 *:* users:(("java",pid=7156,fd=73))
[root@mycat-server bin]#
balance属性
balance="0",不开启读写分离机制,所有读操作都发送到当前可用的writeHost上
balance="1", 定义的全部主机都参与select语句的负载均衡,也就是说,当双主双从模式下,M2,S1,S2都参与select语句的负载均衡
balance="2", 所有读请求随机的分发到writeHost,readHost上分布
balance="3", 所有读请求随机的分发到writeHost对应的readHost执行,writeHost不负担读压力,注意,balance=3,只有在1.4及以后的版本才有
writeType属性
writeType="0",所有写操作发送到配置的第一个writeHost,第一个挂了,切换到定义的第二个writeHost,这时,即使重启服务,也不会切换回去,还是以第二个writeHost为准
writeType="1", 所有写操作会随机发送到writeHost。注意,1.5版本以后废弃了,不推荐使用
上面配置中,balance改为1,表示读写分离,writeType="0",表示写操作发送到配置的第一个writeHost,第一个挂了,切换到定义的第二个writeHost
以上配置达到的效果就是10.0.0.20为主库,10.0.0.30为从库
注意:要保证能使用root/123456权限成功登录10.0.0.20和10.0.0.30机器上面的mysql数据库。同时也一定要授权mycat机器能使用root/123456权限成功登录这两台机器的mysql数据库!
5、在后端主服务器创建用户并对mycat授权
mysql> create database mycat;
mysql> create user root@'10.0.0.%' identified by '123456';
mysql> grant all on *.* to 'root'@'10.0.0.%';
mysql> fulsh privileges;
6、在mycat服务器上连接并测试
[root@mycat-server ~]# yum install -y mysql
[root@mycat-server ~]# vi /etc/my.cnf
[client]
default-auth=mysql_native_password
[root@mycat-server ~]# mysql -uroot -predhat -h 127.0.0.1 TESTDB
mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB | #只能看到一个虚拟数据库
+----------+
1 row in set (0.00 sec)
mysql> use TESTDB;
Database changed
mysql> create table t1(id int);
Query OK, 0 rows affected (0.31 sec)
mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 30 |
+-------------+
1 row in set (0.02 sec)
mysql> select @@hostname;
+----------------------+
| @@hostname |
+----------------------+
| mysql-slave.yzil.xyz |
+----------------------+
1 row in set (0.01 sec)
mysql>
7、通过通用日志确认实现读写分离
mysql> show variables like 'general_log'; #查看日志是否开启
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| general_log | OFF |
+---------------+-------+
1 row in set (0.01 sec)
mysql> set global general_log=on; #开启日志功能
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'general_log_file'; #查看日志文件保存位置
+------------------+--------------------------------+
| Variable_name | Value |
+------------------+--------------------------------+
| general_log_file | /var/lib/mysql/mysql-slave.log |
+------------------+--------------------------------+
1 row in set (0.00 sec)
mysql>
在主和从服务器分别启用通用日志,查看读写分离
[root@mysql-master ~]# vi /etc/my.cnf
[mysqld]
general_log=ON
[root@mysql-master ~]# systemctl restart mysqld
mysql> show variables like 'general_log';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| general_log | ON |
+---------------+-------+
1 row in set (0.13 sec)
mysql>
mysql> use TESTDB;
Database changed
mysql> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| t1 |
| teachers |
| toc |
+-------------------+
8 rows in set (0.01 sec)
mysql>
[root@mysql-master ~]# tail -f /var/lib/mysql/mysql-master.log
2021-05-25T03:05:00.603842Z 11 Query select user() #mycat对后端服务器的健康性检查方法select user()
2021-05-25T03:05:10.603841Z 13 Query select user()
2021-05-25T03:05:20.603842Z 8 Query select user()
[root@mysql-slave ~]# tail -f /var/lib/mysql/mysql-slave.log
2021-05-25T03:05:10.603257Z 13 Query select user()
2021-05-25T03:05:11.616535Z 12 Query show tables
2021-05-25T03:05:20.603478Z 14 Query select user()
#从日志中可以观察到读是在slave上面
8、停止从节点,mycat自动调度读请求至主节点
停止主节点,mycat不会自动调度写请求至从节点
[root@mysql-slave ~]# systemctl stop mysqld
[root@mycat-server ~]# mysql -uroot -predhat -h 127.0.0.1 TESTDB
mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 20 |
+-------------+
1 row in set (0.01 sec)
mysql>
#停止主节点,mycat不会自动调度写请求至从节点
mysql> insert teachers values (5,'yyy','M');
ERROR 1184 (HY000): java.net.ConnectException: Connection refused
以上是关于利用MyCAT实现MySQL的读写分离的主要内容,如果未能解决你的问题,请参考以下文章
mysql+mycat搭建稳定高可用集群,负载均衡,主备复制,读写分离
mysql+mycat搭建稳定高可用集群,负载均衡,主备复制,读写分离
MySQL+MyCat分库分表 读写分离配置MySQL+MyCat分库分表 读写分离配置