[TOC]
10:mysql之读写分离
今日工作任务路线图

一、工作场景
MySQL读写分离在多种工作场景中优势明显。在高并发读场景里,如电商平台商品浏览、社交媒体内容加载,大量读请求可由从库处理,减轻主库压力,提升系统响应速度 。对于数据实时性要求低的报表生成、数据分析场景,允许主从短暂延迟,能充分发挥读写分离的优势 。在容灾与备份方面,从库可作为主库实时备份,主库故障时能快速切换,保障业务持续运行 。另外,全球分布式架构中,将读操作路由到离用户近的从库,可减少网络延迟。
二、为什么学
学习 MySQL 读写分离很有必要。在高并发场景下,数据库面临大量读写请求,读写分离可将读操作分配到从库,有效减轻主库压力,提升系统整体性能与响应速度。对于有海量数据处理需求的企业,能提升业务处理效率。它还能增强系统的可扩展性,可通过增加从库数量来应对不断增长的读请求。在数据备份与恢复方面,从库可充当主库的实时副本,一旦主库出现故障,能快速恢复数据,保障业务连续性。掌握这一技术,有助于提升数据库管理和运维能力。
三、准备环境
当前任务环节

3.1 准备新的虚拟机
| 主机名 | IP地址 | 说明 |
|---|---|---|
| mysql56 | 192.168.90.56 | master【马斯特】数据库 |
| mysql57 | 192.168.90.57 | slave【斯累夫】数据库 |
| mycat58 | 192.168.90.58 | 读写分离服务 |
mysql56配置IP地址和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.56/24 autoconnect【奥特欧 坑聂特】 yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160[root@mysql56 ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mysql56mysql57配置IP地址和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.57/24 autoconnect【奥特欧 坑聂特】 yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160[root@mysql57 ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mysql57mycat58配置IP地址和主机名
[root@localhost ~]# nmcli connection【肯耐申】 modify【莫迪fái】 ens160 ipv4.addresses【额拽西斯】 192.168.90.58/24 autoconnect【奥特欧 坑聂特】 yes[root@localhost ~]# nmcli connection【肯耐申】 up ens160[root@mycat ~]# hostnamectl【厚斯内姆 ctl】 set-hostname【赛特-厚斯内姆】 mycat583.2 读写分离原理
Mycat【麦-凯特】 读写分离原理基于对 MySQL 主从复制的利用。 Mycat【麦-凯特】 作为中间件,介于应用程序和 MySQL 数据库之间。 当应用程序发起 SQL 请求时,Mycat【麦-凯特】 会根据 SQL 语句类型进行判断。对于读操作,如 SELECT【涩莱克特】 语句,Mycat【麦-凯特】 将请求路由到从库处理,从库可有多台,能实现负载均衡,以此减轻主库读压力。而对于写操作,如 INSERT【因涩特】、UPDATE【阿普 dei 特】、DELETE【迪 利 特】 语句,Mycat【麦-凯特】 会将请求转发到主库,确保数据写入的一致性。 主库数据更新后,通过 MySQL 主从复制机制同步到从库,保证数据的实时性和准确性。

四、搭建一主一从结构
当前任务环节

因为数据的查询和存储分别访问不同的数据库服务器,所以要通过主从同步来保证负责读访问的服务与负责写访问的服务器数据一致。
4.1 配置主数据库服务器
[root@mysql56 ~]# yum -y install【因-斯多】 mysql-server mysql[root@mysql56 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld
# 启用binlog日志[root@mysql56 ~]# vim /etc/my.cnf.d/mysql-server.cnf# [root@mysql56 ~]# vim /etc/my.cnf[mysqld]server-id=56log-bin=mysql56:wq
[root@mysql56 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld# [root@mysql56 ~]# systemctl restart mysqld
# 用户授权[root@mysql56 ~]# mysql# [root@mysql56 ~]# mysql -uroot -p123
mysql> create【克瑞特】 user repluser@"%" identified【爱-丹-提伐】 with【威付】 mysql_native_password by【拜】 "123qqq...A";# mysql> create user repluser@'%' identified with mysql_native_password by 'repluser';# Query OK, 0 rows affected (0.26 sec)
mysql> grant【古亮普】 replication【瑞普利K申】 slave【斯累夫】 on *.* to repluser@"%" ;# mysql> grant replication slave on *.* to repluser@'%';# Query OK, 0 rows affected (0.15 sec)
# 查看日志信息mysql> show【瘦】 master【马斯特】 status【 斯dèi 特斯】;# mysql> show master status;# +----------------+----------+--------------+------------------+-------------------+# | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |# +----------------+----------+--------------+------------------+-------------------+# | mysql56.000001 | 668 | | | |# +----------------+----------+--------------+------------------+-------------------+# 1 row in set (0.00 sec)4.2 配置从数据库服务器
# 指定server-id 并重启数据库服务[root@mysql57 ~]# yum -y install【因-斯多】 mysql-server mysql[root@mysql57 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld[root@mysql57 ~]# vim /etc/my.cnf.d/mysql-server.cnf# [root@mysql57 ~]# vim /etc/my.cnf[mysqld]server-id=57:wq
[root@mysql57 ~]# systemctl【西斯屯-ctl】 restart【 率 s 达r】 mysqld# [root@mysql57 ~]# systemctl restart mysqld
# 管理员登陆,指定主服务器信息[root@mysql57 ~]# mysql# [root@mysql57 ~]# mysql -uroot -p123
mysql> change【趁(chèn)吉】 master【马斯特】 to master【马斯特】_host="192.168.90.56", master【马斯特】_user="repluser", master【马斯特】_password="123qqq...A", master【马斯特】_log_file="mysql56.000001",master【马斯特】_log_pos=667;# mysql> change master to master_host='192.168.88.10',master_user='repluser',master_password='repluser',master_log_file="mysql56.000001",master_log_pos=668;# Query OK, 0 rows affected, 8 warnings (9.74 sec)
# 启动slave【斯累夫】进程mysql> start【s 达儿】 slave【斯累夫】;# mysql> start slave;# Query OK, 0 rows affected, 1 warning (0.95 sec)
# 查看状态信息mysql> show【瘦】 slave【斯累夫】 status【 斯dèi 特斯】 \G# mysql> show slave status \G*************************** 1. row *************************** Slave_IO_State: Waiting for source to send event Master_Host: 192.168.90.56 Master_User: repluser Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql56.000001 Read_Master_Log_Pos: 667 Relay_Log_File: mysql57-relay-bin.000002 Relay_Log_Pos: 322 Relay_Master_Log_File: mysql56.000001 Slave_IO_Running: Yes //IO线程 Slave_SQL_Running: Yes //SQL线程 Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 667 Relay_Log_Space: 533 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 56 Master_UUID: e0ab8dc4-0109-11ee-87e7-525400ad7ed3 Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates【阿普 dei 特s】 Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: Master_public_key_path: Get_master_public_key: 0 Network_Namespace:1 row in set, 1 warning (0.00 sec)五、配置mycat【麦-凯特】服务器
当前任务环节

5.1 拷贝软件到mycat【麦-凯特】58主机
mycat2-1.21-release-jar-with-dependencies.jar
mycat2**-install-**template-1.21.zip
5.2 安装mycat【麦-凯特】软件
# 安装jdk[root@mycat58 upload]# yum -y install【因-斯多】 java-1.8.0-openjdk.x86_64# [root@mycat58 ~]# yum -y install java-1.8.0-openjdk.x86_64# 安装解压命令[root@mycat58 upload]# which【维曲】 unzip || yum -y install【因-斯多】 unzip# [root@mycat58 ~]# which unzip || yum -y install unzip# 安装mycat[root@mycat58 upload]# unzip mycat2-install-template-1.21.zip# [root@mycat58 ~]# unzip mycat2-install-template-1.21.zip[root@mycat58 upload]# mv mycat【麦-凯特】 /usr/local/# [root@mycat58 ~]# mv mycat /usr/local/# 安装依赖[root@mycat58 upload]# cp mycat2-1.21-release-jar-with-dependencies.jar /usr/local/mycat/lib/# [root@mycat58 ~]# cp mycat2-1.21-release-jar-with-dependencies.jar /usr/local/mycat/lib/# 修改权限[root@mycat58 upload]# chmod -R 777 /usr/local/mycat/# [root@mycat58 ~]# chmod -R 777 /usr/local/mycat/5.3 配置mycat【麦-凯特】密码
定义客户端连接mycat【麦-凯特】服务使用用户及密码:
[root@mycat58 ~]# vim /usr/local/mycat/conf/users/root.user.json{ "dialect":"mysql", "ip":null, "password":"654321", 密码 "transactionType":"proxy", "username":"mycat" 用户名}mycat【麦-凯特】连接本机数据库配置
[root@mycat58 ~]# vim /usr/local/mycat/conf/datasources/prototypeDs.datasource.json{ "dbType":"mysql", "idleTimeout":60000, "initSqls":[], "initSqlsGetConnection":true, "instanceType":"READ_WRITE", "maxCon":1000, "maxConnectTimeout":3000, "maxRetryCount":5, "minCon":1, "name":"prototypeDs", "password":"123456", 密码 "type":"JDBC", "url":"jdbc:mysql://localhost:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8", 连接本机的数据库服务 "user":"jam", 用户名 "weight":0}5.4 mycat58主机mysql安装
# 安装软件[root@mycat58 ~]# yum -y install【因-斯多】 mysql-server mysql# 启动服务[root@mycat58 ~]# systemctl【西斯屯-ctl】 start【s 达儿】 mysqld# 连接服务[root@mycat58 ~]# mysql# [root@mycat58 ~]# mysql -uroot -p123
# 创建jam用户mysql> create【克瑞特】 user jam@"%" identified【爱-丹-提伐】 by【拜】 "123456";# mysql> create user jam@'%' identified by '123456';# Query OK, 0 rows affected (0.52 sec)
# 授予权限mysql> grant【古亮普】 all on *.* to jam@"%" ;# mysql> grant all on *.* to jam@'%';# Query OK, 0 rows affected (1.14 sec)
# 断开连接mysql> exit【诶西特】# mysql> exitBye[root@mycat58 ~]#5.5 mycat【麦-凯特】服务启动和连接
启动mycat【麦-凯特】服务
[root@mycat58 ~]# /usr/local/mycat/bin/mycat help# [root@mycat58 ~]# /usr/local/mycat/bin/mycat helpUsage: /usr/local/mycat/bin/mycat { console | start【s 达儿】 | stop | restart【 率 s 达r】 | status【 斯dèi 特斯】 | dump }
[root@mycat58 ~]# /usr/local/mycat/bin/mycat start# [root@mycat58 ~]# /usr/local/mycat/bin/mycat start# Starting mycat2...
# 半分钟左右 能看到端口[root@mycat58 ~]# netstat -utnlp | grep 8066# [root@mycat58 ~]# netstat -tunlp | grep 8066# tcp6 0 0 :::8066 :::* LISTEN 30687/java连接mycat【麦-凯特】服务
[root@mycat58 ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321# [root@mycat58 ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321
mysql> show【瘦】 databases;# mysql> show databases;+--------------------+| `Database` |+--------------------+| information_schema || mysql || performance_schema |+--------------------+3 rows in set (0.11 sec)Mysql>六、配置读写分离
当前任务环节

6.1 添加数据源
添加数据源:连接mycat【麦-凯特】服务后做如下操作
# 连接mycat【麦-凯特】服务[root@mycat58 ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321# [root@mycat58 ~]# mysql -h 127.0.0.1 -P8066 -umycat -p654321
# 添加mysql56数据库服务器MySQL> /*+ mycat:createdatasource{"name":"whost56", "url":"jdbc:mysql://192.168.90.56:3306","user":"jama","password":"123456"}*/;# mysql> /*+ mycat:createdatasource{"name":"whost56", "url":"jdbc:mysql://192.168.88.10:3306","user":"jama","password":"123456"}*/;# Query OK, 0 rows affected (0.86 sec)
# 添加mysql57数据库服务器Mysql>/*+ mycat:createdatasource{"name":"rhost57", "url":"jdbc:mysql://192.168.90.57:3306","user":"jama","password":"123456"}*/;# mysql> /*+ mycat:createdatasource{"name":"rhost57", "url":"jdbc:mysql://192.168.88.20:3306","user":"jama","password":"123456"}*/;# Query OK, 0 rows affected (0.06 sec)
# 查看数据源mysql> /*+mycat:showDataSources{}*/ \G# mysql> /*+mycat:showDataSources{}*/ \G*************************** 1. row *************************** NAME: whost56 USERNAME: jama PASSWORD: 123456 MAX_CON: 1000 MIN_CON: 1 EXIST_CON: 0 USE_CON: 0 MAX_RETRY_COUNT: 5 MAX_CONNECT_TIMEOUT: 30000 DB_TYPE: mysql URL: jdbc:mysql://192.168.90.56:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true WEIGHT: 0 INIT_SQL:INIT_SQL_GET_CONNECTION: true INSTANCE_TYPE: READ_WRITE IDLE_TIMEOUT: 60000 DRIVER: { CreateTime:"2023-06-02 17:01:14", ActiveCount:0, PoolingCount:0, CreateCount:0, DestroyCount:0, CloseCount:0, ConnectCount:0, Connections:[ ]} TYPE: JDBC IS_MYSQL: true*************************** 2. row *************************** NAME: rhost57 USERNAME: jama PASSWORD: 123456 MAX_CON: 1000 MIN_CON: 1 EXIST_CON: 0 USE_CON: 0 MAX_RETRY_COUNT: 5 MAX_CONNECT_TIMEOUT: 30000 DB_TYPE: mysql URL: jdbc:mysql://192.168.90.57:3306?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&autoReconnect=true WEIGHT: 0 INIT_SQL:INIT_SQL_GET_CONNECTION: true INSTANCE_TYPE: READ_WRITE IDLE_TIMEOUT: 60000 DRIVER: { CreateTime:"2023-06-02 17:01:14", ActiveCount:0, PoolingCount:0, CreateCount:0, DestroyCount:0, CloseCount:0, ConnectCount:0, Connections:[ ]} TYPE: JDBC IS_MYSQL: true*************************** 3. row *************************** NAME: prototypeDs USERNAME: jam PASSWORD: 123456 MAX_CON: 1000 MIN_CON: 1 EXIST_CON: 0 USE_CON: 0 MAX_RETRY_COUNT: 5 MAX_CONNECT_TIMEOUT: 3000 DB_TYPE: mysql URL: jdbc:mysql://localhost:3306/mysql?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true WEIGHT: 0 INIT_SQL:INIT_SQL_GET_CONNECTION: true INSTANCE_TYPE: READ_WRITE IDLE_TIMEOUT: 60000 DRIVER: { CreateTime:"2023-06-02 17:01:14", ActiveCount:0, PoolingCount:0, CreateCount:0, DestroyCount:0, CloseCount:0, ConnectCount:0, Connections:[ ]} TYPE: JDBC IS_MYSQL: true3 rows in set (0.00 sec)mysql>
# 添加的数据源以文件的形式保存在安装目录下[root@mycat58 conf]# ls /usr/local/mycat/conf/datasources/# [root@mycat58 ~]# ls /usr/local/mycat/conf/datasources/# prototypeDs.datasource.json rhost57.datasource.json whost56.datasource.json
[root@mycat58 conf]#6.2 配置数据库服务器添加jama用户
# 在master【马斯特】服务器添加[root@mysql56 ~]# mysql
mysql> create【克瑞特】 user jama@"%" identified【爱-丹-提伐】 by【拜】 "123456";# mysql> create user jama@"%" identified by "123456";# Query OK, 0 rows affected (0.24 sec)
mysql> grant【古亮普】 all on *.* to jama@"%";# mysql> grant all on *.* to jama@"%";# Query OK, 0 rows affected (0.19 sec)
mysql> exit【诶西特】[root@mysql56 ~]#
# 在slave【斯累夫】服务器查看是否同步成功[root@mysql57 ~]# mysql -e 'select【涩莱克特】 user , host from【弗乱】 mysql.user where user="jama"'+------+------+| user | host |+------+------+| jama | % |+------+------+[root@mysql57 ~]#6.3 创建集群
创建集群,连接mycat【麦-凯特】服务后做如下配置:
[root@mycat58 ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321
# 创建集群mysql>/*!mycat:createcluster{"name":"rwcluster","masters":["whost56"],"replicas":["rhost57"]}*/ ;
# 查看集群信息mysql> /*+ mycat:showClusters{}*/ \G*************************** 1. row *************************** NAME: rwcluster SWITCH_TYPE: SWITCHMAX_REQUEST_COUNT: 2000 TYPE: BALANCE_ALL WRITE_DS: whost56 READ_DS: whost56,rhost57 WRITE_L: io.mycat.plug.loadBalance.BalanceRandom$1 READ_L: io.mycat.plug.loadBalance.BalanceRandom$1 AVAILABLE: true*************************** 2. row *************************** NAME: prototype SWITCH_TYPE: SWITCHMAX_REQUEST_COUNT: 200 TYPE: BALANCE_ALL WRITE_DS: prototypeDs READ_DS: prototypeDs WRITE_L: io.mycat.plug.loadBalance.BalanceRandom$1 READ_L: io.mycat.plug.loadBalance.BalanceRandom$1 AVAILABLE: true2 rows in set (0.00 sec)mysql>
# 创建的集群以文件的形式保存在目录下[root@mycat58 conf]# ls /usr/local/mycat/conf/clusters/prototype.cluster.json rwcluster.cluster.json[root@mycat58 conf]#6.4 指定主机角色
# 修改master【马斯特】角色主机仅负责写访问[root@mycat58 ~]# vim /usr/local/mycat/conf/datasources/whost56.datasource.json{ "dbType":"mysql", "idleTimeout":60000, "initSqls":[], "initSqlsGetConnection":true, "instanceType":"WRITE", 仅负责写访问 "logAbandoned":true, "maxCon":1000, "maxConnectTimeout":30000, "maxRetryCount":5, "minCon":1, "name":"whost56", "password":"123456", "queryTimeout":0, "removeAbandoned":false, "removeAbandonedTimeoutSecond":180, "type":"JDBC", "url":"jdbc:mysql://192.168.90.56:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true", "user":"jama", "weight":0}:wq
# 修改slave【斯累夫】角色主机仅负责读访问[root@mycat58 ~]# vim /usr/local/mycat/conf/datasources/rhost57.datasource.json{ "dbType":"mysql", "idleTimeout":60000, "initSqls":[], "initSqlsGetConnection":true, "instanceType":"READ",仅负责读访问 "logAbandoned":true, "maxCon":1000, "maxConnectTimeout":30000, "maxRetryCount":5, "minCon":1, "name":"rhost57", "password":"123456", "queryTimeout":0, "removeAbandoned":false, "removeAbandonedTimeoutSecond":180, "type":"JDBC", "url":"jdbc:mysql://192.168.90.57:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true", "user":"jama", "weight":0}6.5 修改读策略
readBalanceType参数值 | 负载均衡策略说明 | 行为描述 |
|---|---|---|
| BALANCE_ALL_READ | 在所有从库(Replicas)间均衡 | 所有的 SELECT查询请求会在 replicas列表配置的所有从库上进行负载均衡。写节点(masters)不参与读流量的分担。 |
| BALANCE_ALL (如果支持) | 在所有节点(主和从)间均衡 | 读请求会随机地在所有数据库节点(包括写节点 masters和读节点 replicas)上进行分发。这种模式允许主库也承担一部分读压力。 |
| BALANCE_MASTER (如果支持) | 仅从主库读取 | 所有读请求都会发往配置的写节点(masters)。这通常用于需要强一致性读的场景,或者尚未配置从库的情况。 |
[root@mycat58 ~]# vim /usr/local/mycat/conf/clusters/rwcluster.cluster.json{ "clusterType":"MASTER_SLAVE", "heartbeat":{ "heartbeatTimeout":1000, "maxRetryCount":3, "minSwitchTimeInterval":300, "showLog":false, "slaveThreshold":0.0 }, "masters":[ "whost56" ], "maxCon":2000, "name":"rwcluster", "readBalanceType":"BALANCE_ALL_READ",# _READ将查询语句分发到从数据库节点 "replicas":[ "rhost57" ], "switchType":"SWITCH"}:wq
# 重启mycat【麦-凯特】服务[root@mycat58 ~]# /usr/local/mycat/bin/mycat restartStopping mycat2...Stopped mycat2.Starting mycat2...
[root@mycat58 ~]#七、测试读写分离
当前任务环节

7.1 指定testdb库存储数据使用的集群
具体操作如下:
[root@mycat58 ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321
mysql> create【克瑞特】 database testdb;# mysql> create database testdb;# Query OK, 0 rows affected (0.54 sec)
mysql> exit【诶西特】
# 指定testdb库存储数据使用的集群[root@mycat58 ~]# vim /usr/local/mycat/conf/schemas/testdb.schema.json{ "customTables":{}, "globalTables":{}, "normalProcedures":{}, "normalTables":{}, "schemaName":"testdb", "targetName":"rwcluster", 添加此行,之前创建的集群名rwcluster "shardingTables":{}, "views":{}}:wq
[root@mycat58 ~]# /usr/local/mycat/bin/mycat restartStopping mycat2...Stopped mycat2.Starting mycat2...
[root@mycat58 ~]#
# 连接mycat【麦-凯特】服务建表插入记录[root@client50 ~]# mysql -h192.168.90.58 -P8066 -umycat -p654321
mysql> create【克瑞特】 table【忒-部】 testdb.user (name varchar【瓦儿-查儿】(10) , password varchar【瓦儿-查儿】(10));# mysql> create table testdb.user (name varchar(10), password varchar(10));# Query OK, 0 rows affected (3.65 sec)
mysql> insert【因涩特】 into【因兔】 testdb.user values【挖柳斯】("yaya","123456");# mysql> insert into testdb.user values("yaya","123456");# Query OK, 1 row affected (0.28 sec)
mysql> select【涩莱克特】 * from【弗乱】 testdb.user;# mysql> select * from testdb.user;# +------+----------+# | name | password |# +------+----------+# | yaya | 123456 |# +------+----------+# 1 row in set (0.01 sec)7.2 测试读写分离
# 在从服务器本机插入记录,数据仅在从服务器有,主服务器没有[root@mysql57 ~]# mysql -e 'insert【因涩特】 into【因兔】 testdb.user values【挖柳斯】 ("yayaA","654321")'# [root@mysql57 ~]# mysql -uroot -p123 -e 'insert into testdb.user values("yayaA","654321")'# mysql: [Warning] Using a password on the command line interface can be insecure.
[root@mysql57 ~]# mysql -e 'select【涩莱克特】 * from【弗乱】 testdb.user'# [root@mysql57 ~]# mysql -uroot -p123 -e 'select * from testdb.user'# mysql: [Warning] Using a password on the command line interface can be insecure.# +-------+----------+# | name | password |# +-------+----------+# | yaya | 123456 |# | yayaA | 654321 |# +-------+----------+
# 主服务器数据不变,日志偏移量不不变[root@mysql56 ~]# mysql -e 'select【涩莱克特】 * from【弗乱】 testdb.user'# [root@mysql56 ~]# mysql -uroot -p123 -e 'select * from testdb.user'# mysql: [Warning] Using a password on the command line interface can be insecure.# +------+----------+# | name | password |# +------+----------+# | yaya | 123456 |# +------+----------+
[root@mysql56 ~]# mysql -e 'show【瘦】 master【马斯特】 status【 斯dèi 特斯】'# [root@mysql56 ~]# mysql -uroot -p123 -e 'show master status'# mysql: [Warning] Using a password on the command line interface can be insecure.# +----------------+----------+--------------+------------------+-------------------+# | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |# +----------------+----------+--------------+------------------+-------------------+# | mysql56.000002 | 1910 | | | |# +----------------+----------+--------------+------------------+-------------------+
# 客户端连接mycat【麦-凯特】服务读/写数据[root@client50 ~]# mysql -h192.168.90.58 -P8066 -umycat -p654321# [root@mycat58 ~]# mysql -h 127.0.0.1 -P8066 -umycat -p654321
# 查看到的是2条记录的行mysql> select【涩莱克特】 * from【弗乱】 testdb.user;# mysql> select * from testdb.user;# +-------+----------+# | name | password |# +-------+----------+# | yaya | 123456 |# | yayaA | 654321 |# +-------+----------+# 2 rows in set (1.34 sec)
# 插入记录mysql> insert【因涩特】 into【因兔】 testdb.user values【挖柳斯】("yayaB","123456");# mysql> insert into testdb.user values("yayaB","123456");# Query OK, 1 row affected (0.14 sec)
mysql> select【涩莱克特】 * from【弗乱】 testdb.user;# mysql> select * from testdb.user;# +-------+----------+# | name | password |# +-------+----------+# | yaya | 123456 |# | yayaB | 123456 |# +-------+----------+# 2 rows in set (0.00 sec)
# 在主服务器查看数据和日志偏移量[root@mysql56 ~]# mysql -e 'select【涩莱克特】 * from【弗乱】 testdb.user'# [root@mysql56 ~]# mysql -uroot -p123 -e 'select * from testdb.user'# mysql: [Warning] Using a password on the command line interface can be insecure.# +-------+----------+# | name | password |# +-------+----------+# | yaya | 123456 |# | yayaB | 123456 |# +-------+----------+
[root@mysql56 ~]# mysql -e 'show【瘦】 master【马斯特】 status【 斯dèi 特斯】'# [root@mysql56 ~]# mysql -uroot -p123 -e 'show master status'# mysql: [Warning] Using a password on the command line interface can be insecure.# +----------------+----------+--------------+------------------+-------------------+# | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |# +----------------+----------+--------------+------------------+-------------------+# | mysql56.000002 | 2203 | | | |# +----------------+----------+--------------+------------------+-------------------+
# 客户端连接mycat【麦-凯特】服务查看到的是3条记录[root@client50 ~]# mysql -h192.168.90.58 -P8066 -umycat -p654321 -e 'select【涩莱克特】 * from【弗乱】 testdb.user'# [root@mycat58 mycat]# mysql -h192.168.88.30 -P8066 -umycat -p654321 -e 'select * from testdb.user'# mysql: [Warning] Using a password on the command line interface can be insecure.# +-------+----------+# | name | password |# +-------+----------+# | yaya | 123456 |# | yayaA | 654321 |# +-------+----------+MyCat 核心配置文件功能总结
| 配置文件 | 核心功能 |
|---|---|
| server.xml | 系统级配置(账户、密码、逻辑库、序列、连接参数) |
| schema.xml | 逻辑库-物理库映射、表配置、分片规则关联、数据节点/主机配置 |
| rule.xml | 分片规则定义与参数配置 |
| dataHost.xml(可选) | 独立配置数据主机(部分版本将 DataHost 配置拆分到该文件,默认在 schema.xml 中) |
MySQL 读写分离的原理与优势
一、核心原理
MySQL 读写分离基于 主从复制 机制,通过中间件(如 MyCat、ProxySQL、MaxScale)实现请求分流,核心逻辑如下:
- 架构基础:部署1台主库(Master)和1+台从库(Slave),主库负责写操作,从库仅负责读操作;
- 数据同步:主库执行写操作(INSERT/UPDATE/DELETE)后,通过二进制日志(binlog)将数据变更同步到所有从库,保障主从数据一致性;
- 请求路由:应用程序的SQL请求统一发送至中间件,中间件根据SQL类型分流:
- 写请求(含事务类读请求)直接路由到主库,确保数据写入的原子性和一致性;
- 读请求(SELECT)分发到任意从库,支持多从库负载均衡;
- 故障兼容:中间件实时监测主从节点状态,自动剔除故障从库,主库故障时可配合主从切换机制保障业务连续性。
二、核心优势
- 提升并发承载能力:读操作(占业务请求80%以上)分流至多从库,主库专注处理写操作,避免读写冲突排队,系统整体并发量显著提升;
- 减轻主库负载压力:主库无需承担大量读请求的CPU、IO资源消耗,降低主库因负载过高导致的卡顿、超时风险;
- 高可用与容错:从库故障仅影响部分读业务,主库故障可快速切换读请求至从库,避免单点故障导致系统瘫痪;
- 优化响应速度:从库可就近部署(异地多活),降低网络延迟;且从库可关闭写日志、优化索引,专项提升读性能;
- 灵活横向扩展:读压力增长时,无需升级主库硬件,仅需新增从库节点接入集群,扩展成本低、效率高;
- 简化维护与数据安全:从库可作为灾备节点,主库数据丢失时可从从库恢复;报表统计、数据备份等非核心操作可在从库执行,不影响主库业务。
Mycat 在 MySQL 读写分离中的核心作用
Mycat 作为开源分布式数据库中间件,是 MySQL 读写分离架构的 核心枢纽,其核心价值是屏蔽底层主从集群复杂度,实现请求智能分流、数据一致性保障和高可用调度,让应用无需感知主从架构即可享受读写分离带来的性能提升。具体作用如下:
一、请求路由:读写操作智能分流(核心功能)
Mycat 是应用与 MySQL 集群之间的“流量分发器”,实现读写请求的精准拆分:
- SQL 类型识别:自动解析应用发送的 SQL 语句,区分读操作(SELECT、SHOW 等)和写操作(INSERT、UPDATE、DELETE、DDL 等);
- 路由规则执行:
- 写请求(含事务类读请求,如
SELECT ... FOR UPDATE)强制路由到 主库,确保数据写入的原子性和一致性,避免写操作分散导致的数据冲突; - 读请求默认路由到 从库,并支持多从库负载均衡(如轮询、加权轮询、一致性哈希等算法),将读压力均匀分摊到多个从库,减轻主库负担;
- 写请求(含事务类读请求,如
- 灵活路由扩展:支持自定义路由规则(如指定某类查询走特定从库、分库分表场景下的联合路由),适配复杂业务需求。
二、数据一致性保障:解决主从同步延迟问题
MySQL 主从复制存在天然的同步延迟(毫秒级到秒级),可能导致“主库写入数据后,从库未及时同步,读请求获取旧数据”的问题。Mycat 提供多种机制保障数据一致性:
- 强制走主库策略:支持通过 SQL 注解(如
/*MASTER*/ SELECT * FROM table)或配置规则,让关键读请求(如刚写入后需立即查询的场景)强制路由到主库,避免延迟导致的数据不一致; - 延迟判断机制:可配置从库同步延迟阈值(如 1 秒),Mycat 实时监测主从延迟,若从库延迟超过阈值,自动将读请求切换到其他低延迟从库或主库,确保读取数据的时效性;
- 事务一致性控制:事务内的所有操作(无论读写)均路由到主库,避免事务跨主从执行导致的隔离级别失效或数据不一致。
三、负载均衡:提升集群并发处理能力
针对多从库架构,Mycat 提供成熟的负载均衡策略,最大化利用从库资源:
- 读负载均衡:将海量读请求均匀分发到多个从库,避免单台从库过载,提升整体读并发能力(如 3 台从库可承载 3 倍于单从库的读请求);
- 权重配置支持:可根据从库硬件性能(CPU、内存、IO)配置权重(如高性能从库权重设为 3,普通从库设为 1),让资源更优的从库承担更多请求;
- 动态负载调整:支持在线新增/下线从库节点,Mycat 自动感知节点变化并调整负载分发策略,无需重启应用或中间件。
四、高可用调度:避免单点故障,保障业务连续性
Mycat 实时监测主从节点状态,提供故障自动切换和容错能力,提升集群可用性:
- 节点健康检查:通过心跳检测(如定期执行
SELECT 1)监测主从库是否存活,若发现节点故障(如从库宕机、主库离线),自动将其从集群中剔除,避免请求路由到故障节点导致的业务报错; - 主从切换支持:配合 MGR(MySQL Group Replication)或第三方高可用工具(如 Keepalived),主库故障时,Mycat 可自动识别新主库并切换路由规则,写请求无缝迁移到新主库,读请求继续由正常从库处理,实现业务“无感知”恢复;
- 故障恢复自动接入:当故障节点修复后,Mycat 可自动检测并将其重新纳入集群,恢复负载均衡,无需人工干预。
五、透明接入:降低应用改造成本
Mycat 对应用完全透明,无需修改应用代码即可实现读写分离:
- 协议兼容:完全兼容 MySQL 协议,应用可像连接普通 MySQL 数据库一样连接 Mycat(仅需修改数据库连接地址为 Mycat 服务地址,端口为 Mycat 监听端口),无需调整 SQL 语法或数据库驱动;
- 逻辑库抽象:Mycat 将底层多个主从库抽象为一个“逻辑库”,应用仅需面向逻辑库开发,无需关心底层主从节点的数量、地址和部署架构,降低架构复杂度和运维成本。
六、辅助功能:强化读写分离架构的稳定性与可维护性
- 权限集中管理:在 Mycat 层面统一配置应用访问权限(如某应用仅允许读从库、某账户仅允许写主库),无需在每个 MySQL 节点单独配置,简化权限管理;
- SQL 拦截与过滤:支持拦截非法 SQL(如高风险 DDL、慢查询)或不符合规则的请求(如写请求路由到从库),避免恶意操作或误操作破坏集群稳定性;
- 监控与审计:提供完善的日志(如路由日志、错误日志、访问日志)和监控指标(如请求量、路由命中率、节点状态),方便运维人员排查问题、优化性能;
- 分库分表兼容:Mycat 不仅支持读写分离,还可与分库分表功能结合,实现“读写分离+分库分表”的复杂架构,满足海量数据存储和高并发访问的场景(如电商订单库)。
总结
Mycat 在 MySQL 读写分离架构中的核心作用是 “承上启下”:向上屏蔽底层主从集群的复杂性,让应用无需改造即可享受读写分离的性能红利;向下通过智能路由、负载均衡、高可用调度和一致性保障,最大化发挥主从集群的资源价值,解决“主库负载高、读并发不足、单点故障”等核心问题,是中小型企业实现 MySQL 高可用、高并发架构的优选中间件。
Mycat 在 MySQL 读写分离中的核心作用(简洁版)
-
读写请求智能分流
自动解析 SQL 类型,写操作(INSERT/UPDATE/DELETE)路由到主库保证数据一致,读操作(SELECT)分发到从库,避免主库读压力过载。 -
保障数据一致与读负载均衡
通过“关键读请求强制走主库”解决主从同步延迟问题;支持多从库按权重分摊读请求,最大化利用从库资源,提升读并发能力。 -
透明接入与高可用兜底
应用无需改代码,仅需将连接地址指向 Mycat(兼容 MySQL 协议);实时监测主从节点状态,故障节点自动剔除,主库故障时配合切换保障业务不中断。
Mycat 读写分离 schema.xml 核心配置项及作用(简洁版)
1. **<schema> 标签** - 核心属性:`name`(逻辑库名称)、`checkSQLschema`(是否校验SQL库名) - 作用:定义应用访问的**逻辑库**,关联底层数据节点,屏蔽物理库集群复杂度。
2. **<table> 标签** - 核心属性:`name`(逻辑表名)、`dataNode`(关联的数据节点)、`primaryKey`(主键)、`autoIncrement`(是否自增) - 作用:映射逻辑表与物理表,指定表所属数据节点,配置主键和自增规则(读写分离场景中主要用于关联数据节点)。
3. **<dataNode> 标签** - 核心属性:`name`(数据节点名称)、`dataHost`(关联的数据主机)、`database`(物理库名称) - 作用:关联**数据主机**与**物理库**,是逻辑表到物理库的中间映射。
4. **<dataHost> 标签**(读写分离核心配置) - 核心属性:`name`(数据主机名称)、`balance`(读负载均衡策略)、`writeType`(写路由规则)、`switchType`(主从切换策略) - 作用:配置主从库集群信息,控制读负载分发、写请求路由、主从故障切换。
5. **<writeHost> 标签** - 核心属性:`host`(主机标识)、`url`(主库地址:端口)、`user`(数据库用户名)、`password`(密码) - 作用:定义**主库**连接信息,接收所有写请求(INSERT/UPDATE/DELETE)。
6. **<readHost> 标签** - 核心属性:`host`(主机标识)、`url`(从库地址:端口)、`user`(数据库用户名)、`password`(密码) - 作用:定义**从库**连接信息,接收读请求(SELECT),配合 `balance` 实现负载均衡。
7. **关键属性补充** - `balance="1"`:开启读负载均衡(主从库均参与读); - `writeType="0"`:写请求路由到第一个 <writeHost>(主库); - `switchType="1"`:主库故障时自动切换到备用主库/从库。Mycat balance 属性(负载均衡策略)取值含义与适用场景
balance 是 Mycat schema.xml 中 <dataHost> 标签的核心属性,专门控制 读请求的负载均衡规则,取值仅支持 0、1、2、3 四种,不同取值对应不同的集群架构和业务需求,具体如下:
1. balance=“0”:关闭读负载均衡
- 含义:不开启读负载分发,所有读请求(SELECT)均路由到当前活跃的
writeHost(主库),从库(readHost)不参与读请求处理。 - 适用场景:
- 从库未部署(仅单主库架构);
- 主从同步延迟极高(如跨地域主从,延迟秒级以上),读从库会导致数据不一致;
- 业务需要 强一致性读(如刚写入数据后立即查询、核心交易查询),必须读主库。
2. balance=“1”:主从库混合读负载(推荐默认)
- 含义:开启读负载均衡,读请求分发到所有
readHost(从库)和 备用writeHost(备用主库);当前活跃的主库(默认writeHost)不参与读请求,仅负责写操作。 - 适用场景:
- 典型主从架构(1主多从 + 1备用主库),需最大化利用从库和备用主库资源;
- 读请求占比高(如电商商品查询、新闻列表、用户信息查询),需分摊主库读压力;
- 大多数中小型业务的默认选择,兼顾性能和数据一致性(配合主从同步延迟阈值使用)。
3. balance=“2”:全节点读负载(不分主从)
- 含义:不区分主库(
writeHost)和从库(readHost),所有可用的writeHost(主库、备用主库)和readHost(从库)均参与读负载,读请求随机分发到所有节点。 - 适用场景:
- 主库硬件配置充足(CPU/内存/IO 资源未饱和),允许承担部分读请求;
- 备用主库长期闲置,需利用其资源分担读压力;
- 读压力较大但未达到需要部署多从库的规模,适合中小型集群(如 1主1从 + 1备用主库)。
4. balance=“3”:仅从库读负载
- 含义:读请求仅分发到
readHost(从库),主库(writeHost)和备用主库完全不参与读负载 - 适用场景:
- 主库写压力极大(如高频插入/更新),需完全隔离读请求(主库仅负责写);
- 对读数据时效性有要求(需避免主从延迟导致的旧数据),如金融交易查询、订单状态查询;
- 多从库架构(1主多从),且从库性能均衡,适合中大型业务的读密集场景。
balance="3"是最常用的读写分离策略,特别适合读多写少的业务场景,它能有效降低主库压力,提升系统整体性能。
核心总结(快速选型)
balance 值 | 读请求负载策略 | 核心工作机制 | 最适用场景 |
|---|---|---|---|
| 0 | 不开启读写分离 | 所有读、写操作均发送至当前可用的主库 (writeHost)。 | 单点数据库、要求强一致性读、从库延迟不可接受。 |
| 1 | 主从库混合读负载 | 读请求在所有从库 (readHost) 及备用主库 (standby writeHost) 间负载均衡,当前主库不参与读。 | 双主双从等高可用架构,最大化利用从库和备用主库资源。 |
| 2 | 全节点随机读负载 | 所有读请求随机分发到配置内所有数据库节点(包括主库和从库)。 | 读压力大,且主库性能充足,允许主库分担读请求。 |
| 3 | 仅从库读负载 | 读请求只分发到当前主库对应的从库 (readHost) 上,主库完全不负担任何读压力。 | 一主多从架构,且希望严格分离读写、保障主库写性能的场景。 |
八、作业
1 选择题
1
- 在 Mycat 读写分离配置中,schema.xml 文件里 datahost 标签的 balance 属性值为 3 时,表示( D )。 A. 不开启读写分离机制,所有读操作都可发送到当前可用的 writeHost 上 B. 全部的 readHost 与备用的 writeHost 都参与 select 语句的负载均衡 C. 所有的读写操作都随机在 writeHost,readHost 上分发 D. 所有的读请求随机分发到 writeHost 对应的 readHost 上执行,writeHost 不负担读压力
2
- Mycat 的默认数据端口和管理端口分别是( A )。 A. 8066 和 9066 B. 9066 和 8066 C. 3306 和 8066 D. 8066 和 3306
3
- 在 Mycat 配置中,server.xml 文件主要用于( A )。 A. 配置 Mycat 所需要的服务器信息,如序列生成方式、逻辑数据库、访问账户和密码等 B. 配置逻辑数据库的映射、表、分片规则、数据结点及真实的数据库信息 C. 定义分片规则 D. 配置负载均衡策略
4
- 在 Mycat 读写分离配置前,需要确保( A )。 A. MySQL 主从复制已完成并正常运行 B. MySQL 版本为 8.0 C. Mycat 安装在 Windows 系统上 D. 所有数据库服务器的 server-id 相同
2 简答题
1
- 简述 MySQL 读写分离的原理和优势。
答:
核心原理
- 架构基础:部署1台主库(Master)和1+台从库(Slave),主库负责写操作,从库仅负责读操作;
- 数据同步:主库执行写操作(INSERT/UPDATE/DELETE)后,通过二进制日志(binlog)将数据变更同步到所有从库,保障主从数据一致性;
- 请求路由:应用程序的SQL请求统一发送至中间件,中间件根据SQL类型分流:
- 写请求(含事务类读请求)直接路由到主库,确保数据写入的原子性和一致性;
- 读请求(SELECT)分发到任意从库,支持多从库负载均衡;
- 故障兼容:中间件实时监测主从节点状态,自动剔除故障从库,主库故障时可配合主从切换机制保障业务连续性。
核心优势 1. 提升并发承载能力:读操作(占业务请求80%以上)分流至多从库,主库专注处理写操作,避免读写冲突排队,系统整体并发量显著提升; 2. 减轻主库负载压力:主库无需承担大量读请求的CPU、IO资源消耗,降低主库因负载过高导致的卡顿、超时风险; 3. 高可用与容错:从库故障仅影响部分读业务,主库故障可快速切换读请求至从库,避免单点故障导致系统瘫痪; 4. 优化响应速度:从库可就近部署(异地多活),降低网络延迟;且从库可关闭写日志、优化索引,专项提升读性能; 5. 灵活横向扩展:读压力增长时,无需升级主库硬件,仅需新增从库节点接入集群,扩展成本低、效率高; 6. 简化维护与数据安全:从库可作为灾备节点,主库数据丢失时可从从库恢复;报表统计、数据备份等非核心操作可在从库执行,不影响主库业务。
2
- 说明 Mycat 在 MySQL 读写分离中的作用。
答:
- 读写请求智能分流
自动解析 SQL 类型,写操作(INSERT/UPDATE/DELETE)路由到主库保证数据一致,读操作(SELECT)分发到从库,避免主库读压力过载。 - 保障数据一致与读负载均衡
通过“关键读请求强制走主库”解决主从同步延迟问题;支持多从库按权重分摊读请求,最大化利用从库资源,提升读并发能力。 - 透明接入与高可用兜底
应用无需改代码,仅需将连接地址指向 Mycat(兼容 MySQL 协议);实时监测主从节点状态,故障节点自动剔除,主库故障时配合切换保障业务不中断。
- 读写请求智能分流
3
-
列举 Mycat 读写分离配置中 schema.xml 文件的主要配置项及其作用。 答:
-
标签 - 核心属性:
name(逻辑库名称)、checkSQLschema(是否校验SQL库名) - 作用:定义应用访问的逻辑库,关联底层数据节点,屏蔽物理库集群复杂度。
- 核心属性:
-
标签
- 核心属性:
name(逻辑表名)、dataNode(关联的数据节点)、primaryKey(主键)、autoIncrement(是否自增) - 作用:映射逻辑表与物理表,指定表所属数据节点,配置主键和自增规则(读写分离场景中主要用于关联数据节点)。
- 核心属性:
-
标签 - 核心属性:
name(数据节点名称)、dataHost(关联的数据主机)、database(物理库名称) - 作用:关联数据主机与物理库,是逻辑表到物理库的中间映射。
- 核心属性:
-
标签 (读写分离核心配置)- 核心属性:
name(数据主机名称)、balance(读负载均衡策略)、writeType(写路由规则)、switchType(主从切换策略) - 作用:配置主从库集群信息,控制读负载分发、写请求路由、主从故障切换。
- 核心属性:
-
标签 - 核心属性:
host(主机标识)、url(主库地址:端口)、user(数据库用户名)、password(密码) - 作用:定义主库连接信息,接收所有写请求(INSERT/UPDATE/DELETE)。
- 核心属性:
-
标签 - 核心属性:
host(主机标识)、url(从库地址:端口)、user(数据库用户名)、password(密码) - 作用:定义从库连接信息,接收读请求(SELECT),配合
balance实现负载均衡。
- 核心属性:
-
关键属性补充
balance="1":开启读负载均衡(主从库均参与读);writeType="0":写请求路由到第一个(主库); switchType="1":主库故障时自动切换到备用主库/从库。
- 阐述 Mycat 读写分离中负载均衡策略 balance 属性不同取值的含义和适用场景。
答:
balance 取值 “0”,核心含义为“读请求仅走主库,从库不参与”,适用场景为单主库、强一致性读、主从延迟极高
balance 取值 “1”,核心含义为“读请求走从库+备用主库,主库只读不写”,适用场景为1主多从+备用主库、常规读写分离
balance 取值 “2”,核心含义为“所有主从节点均分担读请求”,适用场景为主库资源充足、读压力适中
balance 取值 “3”,核心含义为“读请求只分发到当前主库对应的从库 (
readHost) 上,主库完全不负担任何读压力。”,适用场景为一主多从架构,且希望严格分离读写、保障主库写性能的场景 - 请详细描述在 Linux 环境下使用 Mycat 实现 MySQL 一主一从读写分离的完整操作步骤,包括 MySQL 主从复制配置、Mycat 安装与配置、测试验证等。
- 假设已有一个 MySQL 双主双从的主从复制环境,现要使用 Mycat 实现读写分离,请写出 Mycat 的具体配置步骤和配置文件示例。
- 当 Mycat 服务启动失败,如何进行故障排查和解决,请给出详细的操作流程。
4
3 操作题
1
// **MySQL 主从复制配置**# 配置主库,指定server_id和开启binlog日记[root@master ~]# grep -vE "#" /etc/my.cnf[mysqld]server-id=56log-bin=mysql56# 重启服务[root@master /]# systemctl restart mysqld# 创建用户同步的repluser账号密码replusermysql> create user repluser@"%" identified WITH mysql_native_password by "repluser";Query OK, 0 rows affected (0.09 sec)# 给repluser用户赋权mysql> grant replication slave on *.* to repluser@"%";Query OK, 0 rows affected (0.05 sec)# 查询binlog名称和偏移量mysql> show master status;+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql56.000002 | 157 | | | |+----------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)// **从库安装mysql服务**# 配置从库,指定server_id和开启binlog日记[root@slave1 ~]# vim /etc/my.cnf[root@slave1 ~]# grep -vE "#" /etc/my.cnf[mysqld]server-id=57log_bin=/var/lib/mysql/binlogrelay_log=/var/lib/mysql/relaylog# 重启服务[root@slave1 ~]# systemctl restart mysqld# 从库配置# 修改默认密码[root@slave1 ~]# mysql -uroot -p123# 配置 MySQL 主从复制mysql> change master to master_host="192.168.88.10" , master_user="repluser" , master_password="repluser" ,master_log_file="mysql56.000002" , master_log_pos=157;Query OK, 0 rows affected, 8 warnings (0.06 sec)# 启动slave进程mysql> start slave;Query OK, 0 rows affected, 1 warning (0.32 sec)# 同步查看状态信息mysql> show slave status \G......Slave_IO_Running: YesSlave_SQL_Running: Yes......# 配置mycat服务jama用户# 在master 服务器添加mysql> create user jama@"%" identified by "123456";Query OK, 0 rows affected (0.24 sec)mysql> grant all on *.* to jama@"%";Query OK, 0 rows affected (0.19 sec)# 在slave 服务器查看是否同步成功[root@slave1 ~]# mysql -e 'select user , host from mysql.user where user="jama"'+------+------+| user | host |+------+------+| jama | % |+------+------+[root@slave1 ~]#// **Mycat 安装与配置、测试验证**# 安装mycat 软件和环境# 安装jdk64和unzip[root@mycat ~]# yum -y install java-1.8.0-openjdk.x86_64 unzip# 安装mycat[root@mycat ~]# unzip mycat2-install-template-1.21.zip[root@mycat ~]# mv mycat /usr/local/# 安装依赖[root@mycat ~]# cp mycat2-1.21-release-jar-with-dependencies.jar /usr/local/mycat/lib/[root@mycat ~]# chmod -R 777 /usr/local/mycat/# 配置mycat 密码# 定义客户端连接mycat 服务使用用户及密码:[root@mycat ~]# vim /usr/local/mycat/conf/users/root.user.json{"dialect":"mysql","ip":null,"password":"654321", # 密码"transactionType":"proxy","username":"mycat" # 用户名}# mycat【麦-凯特】连接本机数据库配置[root@mycat ~]# vim /usr/local/mycat/conf/datasources/prototypeDs.datasource.json{"dbType":"mysql","idleTimeout":60000,"initSqls":[],"initSqlsGetConnection":true,"instanceType":"READ_WRITE","maxCon":1000,"maxConnectTimeout":3000,"maxRetryCount":5,"minCon":1,"name":"prototypeDs","password":"123456", # 密码"type":"JDBC","url":"jdbc:mysql://localhost:3306/mysql?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8", # 连接本机的数据库服务"user":"jam", # 用户名"weight":0}# mycat58主机mysql配置[root@mycat ~]# mysql -uroot -p123# 创建jam用户mysql> create user jam@'%' identified by '123456';Query OK, 0 rows affected (0.52 sec)# 授予权限mysql> grant all on *.* to jam@'%';Query OK, 0 rows affected (1.14 sec)# 断开连接mysql> exit# 启动mycat 服务[root@mycat ~]# /usr/local/mycat/bin/mycat startStarting mycat2...# 半分钟左右 能看到端口[root@mycat ~]# netstat -tunlp | grep -E "8066|9066"tcp6 0 0 :::8066 :::* LISTEN 18159/javatcp6 0 0 127.0.0.1:9066 :::* LISTEN 18159/java# 连接mycat 服务[root@mycat ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321mysql> show databases;+--------------------+| `Database` |+--------------------+| information_schema || mysql || performance_schema |+--------------------+3 rows in set (0.11 sec)# 配置读写分离# 添加数据源# 连接mycat 服务[root@mycat ~]# mysql -h 127.0.0.1 -P8066 -umycat -p654321# 添加mysql56数据库服务器mysql> /*+ mycat:createdatasource{"name":"whost56", "url":"jdbc:mysql://192.168.88.10:3306","user":"jama","password":"123456"}*/;Query OK, 0 rows affected (0.86 sec)# 添加mysql57数据库服务器mysql> /*+ mycat:createdatasource{"name":"rhost57", "url":"jdbc:mysql://192.168.88.20:3306","user":"jama","password":"123456"}*/;Query OK, 0 rows affected (0.06 sec)# 查看数据源mysql> /*+mycat:showDataSources{}*/ \G*************************** 1. row ***************************NAME: whost56USERNAME: jamaPASSWORD: 123456......DB_TYPE: mysqlURL: jdbc:mysql://192.168.88.10:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true......*************************** 2. row ***************************NAME: prototypeDsUSERNAME: jamPASSWORD: 123456......DB_TYPE: mysqlURL: jdbc:mysql://localhost:3306/mysql?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true......*************************** 3. row ***************************NAME: rhost57USERNAME: jamaPASSWORD: 123456......DB_TYPE: mysqlURL: jdbc:mysql://192.168.88.20:3306?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&autoReconnect=true......3 rows in set (0.01 sec)# 创建集群[root@mycat ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321# 创建集群mysql>/*!mycat:createcluster{"name":"rwcluster","masters":["whost56"],"replicas":["rhost57"]}*/ ;# 查看集群信息mysql> /*+ mycat:showClusters{}*/ \G*************************** 1. row ***************************NAME: rwclusterSWITCH_TYPE: SWITCHMAX_REQUEST_COUNT: 2000TYPE: BALANCE_ALLWRITE_DS: whost56READ_DS: whost56,rhost57WRITE_L: io.mycat.plug.loadBalance.BalanceRandom$1READ_L: io.mycat.plug.loadBalance.BalanceRandom$1AVAILABLE: true*************************** 2. row ***************************NAME: prototypeSWITCH_TYPE: SWITCHMAX_REQUEST_COUNT: 200TYPE: BALANCE_ALLWRITE_DS: prototypeDsREAD_DS: prototypeDsWRITE_L: io.mycat.plug.loadBalance.BalanceRandom$1READ_L: io.mycat.plug.loadBalance.BalanceRandom$1AVAILABLE: true2 rows in set (0.01 sec)# 指定主机角色# 修改master 角色主机仅负责写访问[root@mycat ~]# vim /usr/local/mycat/conf/datasources/whost56.datasource.json{"dbType":"mysql","idleTimeout":60000,"initSqls":[],"initSqlsGetConnection":true,"instanceType":"WRITE", 仅负责写访问"logAbandoned":true,"maxCon":1000,"maxConnectTimeout":30000,"maxRetryCount":5,"minCon":1,"name":"whost56","password":"123456","queryTimeout":0,"removeAbandoned":false,"removeAbandonedTimeoutSecond":180,"type":"JDBC","url":"jdbc:mysql://192.168.90.56:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true","user":"jama","weight":0}:wq# 修改slave 角色主机仅负责读访问[root@mycat ~]# vim /usr/local/mycat/conf/datasources/rhost57.datasource.json{"dbType":"mysql","idleTimeout":60000,"initSqls":[],"initSqlsGetConnection":true,"instanceType":"READ",仅负责读访问"logAbandoned":true,"maxCon":1000,"maxConnectTimeout":30000,"maxRetryCount":5,"minCon":1,"name":"rhost57","password":"123456","queryTimeout":0,"removeAbandoned":false,"removeAbandonedTimeoutSecond":180,"type":"JDBC","url":"jdbc:mysql://192.168.90.57:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true","user":"jama","weight":0}# 修改读策略[root@mycat ~]# vim /usr/local/mycat/conf/clusters/rwcluster.cluster.json{"clusterType":"MASTER_SLAVE","heartbeat":{"heartbeatTimeout":1000,"maxRetryCount":3,"minSwitchTimeInterval":300,"showLog":false,"slaveThreshold":0.0},"masters":["whost56"],"maxCon":2000,"name":"rwcluster","readBalanceType":"BALANCE_ALL_READ",# _READ将查询语句分发到从数据库节点"replicas":["rhost57"],"switchType":"SWITCH"}:wq# 重启mycat 服务[root@mycat ~]# /usr/local/mycat/bin/mycat restartStopping mycat2...Stopped mycat2.Starting mycat2...[root@mycat ~]#// **测试读写分离测试读写分离**# 指定testdb库存储数据使用的集群[root@mycat ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321mysql> create database testdb;Query OK, 0 rows affected (0.54 sec)mysql> exitBye# 指定testdb库存储数据使用的集群[root@mycat ~]# vim /usr/local/mycat/conf/schemas/testdb.schema.json{"customTables":{},"globalTables":{},"normalProcedures":{},"normalTables":{},"schemaName":"testdb","targetName":"rwcluster", 添加此行,之前创建的集群名rwcluster"shardingTables":{},"views":{}}:wq[root@mycat ~]# /usr/local/mycat/bin/mycat restartStopping mycat2...Stopped mycat2.Starting mycat2...# 连接mycat 服务建表插入记录[root@mycat ~]# mysql -h127.0.0.1 -P8066 -umycat -p654321mysql> create table testdb.user (name varchar(10), password varchar(10));Query OK, 0 rows affected (3.52 sec)mysql> insert into testdb.user values("yaya","123456");Query OK, 1 row affected (0.39 sec)mysql> select * from testdb.user;+------+----------+| name | password |+------+----------+| yaya | 123456 |+------+----------+1 row in set (0.02 sec)# 测试读写分离# 在从服务器本机插入记录,数据仅在从服务器有,主服务器没有[root@slave1 ~]# mysql -uroot -p123 -e 'insert into testdb.user values("yayaA","654321")'mysql: [Warning] Using a password on the command line interface can be insecure.[root@slave1 ~]# mysql -uroot -p123 -e 'select * from testdb.user'mysql: [Warning] Using a password on the command line interface can be insecure.+-------+----------+| name | password |+-------+----------+| yaya | 123456 || yayaA | 654321 |+-------+----------+# 主服务器数据不变,日志偏移量不不变[root@master ~]# mysql -uroot -p123 -e 'select * from testdb.user'mysql: [Warning] Using a password on the command line interface can be insecure.+------+----------+| name | password |+------+----------+| yaya | 123456 |+------+----------+[root@master ~]# mysql -uroot -p123 -e 'show master status'mysql: [Warning] Using a password on the command line interface can be insecure.+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql56.000002 | 1503 | | | |+----------------+----------+--------------+------------------+-------------------+# 客户端连接mycat 服务读/写数据# 查看到的是2条记录的行mysql> select * from testdb.user;+-------+----------+| name | password |+-------+----------+| yaya | 123456 || yayaA | 654321 |+-------+----------+2 rows in set (1.34 sec)# 插入记录mysql> insert into testdb.user values("yayaB","123456");Query OK, 1 row affected (0.14 sec)mysql> select * from testdb.user;+-------+----------+| name | password |+-------+----------+| yaya | 123456 || yayaB | 123456 |+-------+----------+2 rows in set (0.00 sec)# 在主服务器查看数据和日志偏移量[root@master ~]# mysql -uroot -p123 -e 'select * from testdb.user'mysql: [Warning] Using a password on the command line interface can be insecure.+-------+----------+| name | password |+-------+----------+| yaya | 123456 || yayaB | 123456 |+-------+----------+[root@master ~]# mysql -uroot -p123 -e 'show master status'mysql: [Warning] Using a password on the command line interface can be insecure.+----------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+----------------+----------+--------------+------------------+-------------------+| mysql56.000002 | 1796 | | | |+----------------+----------+--------------+------------------+-------------------+# 客户端连接mycat 服务查看到的是3条记录mysql> select * from testdb.user;+-------+----------+| name | password |+-------+----------+| yaya | 123456 || yayaA | 654321 || yayaB | 123456 |+-------+----------+3 rows in set (0.00 sec)2
Terminal window # Mycat 核心配置步骤# 1:确认 Mycat 环境(已安装 JDK 1.8+,Mycat 已部署)# 2:配置 Mycat 数据源(4个节点,每个节点1个配置文件)# 2.1 主库1数据源:masterA.datasource.json[root@mycat ~]# vim /usr/local/mycat/conf/datasources/masterA.datasource.json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "WRITE", # 主库:写角色"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "masterA", # 数据源名称(与拓扑标识一致)"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.61:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 # 写负载权重(双主权重相同,均分写请求)}# 2.2 主库2数据源:masterB.datasource.json[root@mycat ~]# vim /usr/local/mycat/conf/datasources/masterB.datasource.json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "WRITE", # 主库:写角色(双主互备)"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "masterB", # 数据源名称"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.62:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 # 与主库1权重一致,实现写负载均衡}# 2.3 从库1数据源:slaveA.datasource.json[root@mycat ~]# vim /usr/local/mycat/conf/datasources/slaveA.datasource.json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "READ", # 从库:读角色"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "slaveA", # 数据源名称"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.63:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 # 读负载权重(双从权重相同,均分读请求)}# 2.4 从库2数据源:slaveB.datasource.json[root@mycat ~]# vim /usr/local/mycat/conf/datasources/slaveB.datasource.json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "READ", # 从库:读角色"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "slaveB", # 数据源名称"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.64:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 # 与从库1权重一致,实现读负载均衡}# 3:配置 Mycat 集群(核心:双主双从读写策略)[root@mycat ~]# vim /usr/local/mycat/conf/clusters/dual_master_dual_slave.cluster.json{"clusterType": "MASTER_SLAVE", # 集群类型:主从架构(支持双主)"heartbeat": { # 心跳检测(监测节点存活)"heartbeatTimeout": 1000,"maxRetryCount": 3,"minSwitchTimeInterval": 300, # 故障切换最小间隔(毫秒)"showLog": false,"slaveThreshold": 0.5 # 从库同步延迟阈值(秒),超过则剔除},"masters": ["masterA", "masterB"], # 双主数据源名称(写请求路由到这里)"maxCon": 4000, # 集群最大连接数(4个节点总和)"name": "dual_master_dual_slave", # 集群名称(后续关联逻辑库用)"readBalanceType": "BALANCE_ALL_READ", # 读负载策略:所有从库均分读请求"replicas": ["slaveA", "slaveB"], # 双从数据源名称(读请求路由到这里)"switchType": "SWITCH", # 故障切换策略:自动切换(主库故障时切换到备用主库)"writeBalanceType": "BALANCE_ALL_WRITE" # 写负载策略:双主均分写请求(核心!双主特色)}# 4:配置 Mycat 逻辑库(关联集群)[root@mycat mycat]# vim /usr/local/mycat/conf/schemas/business.schema.json{"customTables": {},"globalTables": {},"normalProcedures": {},"normalTables": {},"schemaName": "business", # 逻辑库名称(应用连接 Mycat 时使用)"targetName": "dual_master_dual_slave", # 关联上面创建的集群名称"shardingTables": {},"views": {}}# 5:配置 Mycat 访问用户(可选,若已配置可跳过)[root@mycat ~]# vim /usr/local/mycat/conf/users/mycat_user.user.json{"dialect": "mysql","ip": null, # 允许所有IP访问(生产环境可指定IP)"password": "Mycat@666", # 应用连接 Mycat 的密码"transactionType": "proxy","username": "mycat_app" # 应用连接 Mycat 的用户名}# **启动与验证**# 重启 Mycat 加载配置[root@mycat ~]# /usr/local/mycat/bin/mycat restart# 2.1 连接 Mycat 逻辑库[root@mycat ~]# mysql -h 127.0.0.1 -P 8066 -u mycat_app -pMycat@666mysql> -- 查看逻辑库mysql> show databases;mysql> -- 查看 Mycat 数据源状态mysql> /*+ mycat:showDataSources{}*/ \Gmysql> -- 查看集群状态mysql> /*+ mycat:showClusters{}*/ \G-- **验证读写分离效果**mysql> -- 写操作(插入数据,会路由到双主之一)mysql> use business;mysql> create table test_user (id int primary key auto_increment, name varchar(20));mysql> insert into test_user (name) values ("user1"), ("user2");# 直接连接 masterA 查看双主数据[root@mycat ~]# mysql -h 192.168.90.61 -u mycat_user -pMycat@123 -e "select * from business.test_user";# 直接连接 masterB 查看双主数据[root@mycat ~]# mysql -h 192.168.90.62 -u mycat_user -pMycat@123 -e "select * from business.test_user";# 查看双从数据[root@mycat ~]# mysql -h 192.168.90.63 -u mycat_user -pMycat@123 -e "select * from business.test_user";[root@mycat ~]# mysql -h 192.168.90.64 -u mycat_user -pMycat@123 -e "select * from business.test_user";Terminal window # Mycat 实现 MySQL 双主双从读写分离(配置步骤+文件示例)## 一、环境前提(已就绪)假设双主双从复制环境已搭建完成(**核心前提:双主互为主从,主从数据同步正常**),拓扑如下:| 节点角色 | IP地址 | 端口 | 数据库用户 | 密码 | 实例标识(Mycat中用) ||----------------|----------------|------|------------|--------|-----------------------|| 主库1(MasterA) | 192.168.90.61 | 3306 | mycat_user | Mycat@123 | masterA || 主库2(MasterB) | 192.168.90.62 | 3306 | mycat_user | Mycat@123 | masterB || 从库1(SlaveA) | 192.168.90.63 | 3306 | mycat_user | Mycat@123 | slaveA || 从库2(SlaveB) | 192.168.90.64 | 3306 | mycat_user | Mycat@123 | slaveB |### 双主双从复制要求- 双主已配置 **互为主从**(MasterA → MasterB 同步,MasterB → MasterA 同步),支持写负载或故障切换;- 每个主库对应从库同步正常(MasterA → SlaveA,MasterB → SlaveB),`Slave_IO_Running=Yes` 且 `Slave_SQL_Running=Yes`;- 所有节点已创建 Mycat 访问用户(`mycat_user`),并授予权限:`GRANT ALL ON *.* TO 'mycat_user'@'%' IDENTIFIED WITH mysql_native_password BY 'Mycat@123';`## 二、Mycat 核心配置步骤(基于 Mycat 2.x,与你之前版本一致)### 步骤1:确认 Mycat 环境(已安装 JDK 1.8+,Mycat 2.x 已部署)无需额外安装,仅需配置以下文件(路径:`/usr/local/mycat/conf/`)。### 步骤2:配置 Mycat 数据源(4个节点,每个节点1个配置文件)在 `conf/datasources/` 目录下,创建4个数据源配置文件(描述每个 MySQL 节点的连接信息)。#### 2.1 主库1数据源:masterA.datasource.json```json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "WRITE", // 主库:写角色"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "masterA", // 数据源名称(与拓扑标识一致)"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.61:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 // 写负载权重(双主权重相同,均分写请求)}```#### 2.2 主库2数据源:masterB.datasource.json```json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "WRITE", // 主库:写角色(双主互备)"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "masterB", // 数据源名称"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.62:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 // 与主库1权重一致,实现写负载均衡}```#### 2.3 从库1数据源:slaveA.datasource.json```json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "READ", // 从库:读角色"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "slaveA", // 数据源名称"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.63:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 // 读负载权重(双从权重相同,均分读请求)}```#### 2.4 从库2数据源:slaveB.datasource.json```json{"dbType": "mysql","idleTimeout": 60000,"initSqls": [],"initSqlsGetConnection": true,"instanceType": "READ", // 从库:读角色"maxCon": 1000,"maxConnectTimeout": 30000,"maxRetryCount": 5,"minCon": 1,"name": "slaveB", // 数据源名称"password": "Mycat@123","type": "JDBC","url": "jdbc:mysql://192.168.90.64:3306?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true","user": "mycat_user","weight": 1 // 与从库1权重一致,实现读负载均衡}```### 步骤3:配置 Mycat 集群(核心:双主双从读写策略)在 `conf/clusters/` 目录下,创建集群配置文件 `dual_master_dual_slave.cluster.json`,定义主从关系、负载策略、故障切换规则。```json{"clusterType": "MASTER_SLAVE", // 集群类型:主从架构(支持双主)"heartbeat": { // 心跳检测(监测节点存活)"heartbeatTimeout": 1000,"maxRetryCount": 3,"minSwitchTimeInterval": 300, // 故障切换最小间隔(秒)"showLog": false,"slaveThreshold": 0.5 // 从库同步延迟阈值(秒),超过则剔除},"masters": ["masterA", "masterB"], // 双主数据源名称(写请求路由到这里)"maxCon": 4000, // 集群最大连接数(4个节点总和)"name": "dual_master_dual_slave", // 集群名称(后续关联逻辑库用)"readBalanceType": "BALANCE_ALL_READ", // 读负载策略:所有从库均分读请求"replicas": ["slaveA", "slaveB"], // 双从数据源名称(读请求路由到这里)"switchType": "SWITCH", // 故障切换策略:自动切换(主库故障时切换到备用主库)"writeBalanceType": "BALANCE_ALL_WRITE" // 写负载策略:双主均分写请求(核心!双主特色)}```### 步骤4:配置 Mycat 逻辑库(关联集群)在 `conf/schemas/` 目录下,创建逻辑库配置文件(例如 `business.schema.json`),指定业务逻辑库与集群的关联。```json{"customTables": {},"globalTables": {},"normalProcedures": {},"normalTables": {},"schemaName": "business", // 逻辑库名称(应用连接 Mycat 时使用)"targetName": "dual_master_dual_slave", // 关联上面创建的集群名称"shardingTables": {},"views": {}}```### 步骤5:配置 Mycat 访问用户(可选,若已配置可跳过)在 `conf/users/` 目录下,创建用户配置文件 `mycat_user.user.json`,定义应用连接 Mycat 的账号密码。```json{"dialect": "mysql","ip": null, // 允许所有IP访问(生产环境可指定IP)"password": "Mycat@666", // 应用连接 Mycat 的密码"transactionType": "proxy","username": "mycat_app" // 应用连接 Mycat 的用户名}```## 三、关键配置说明(双主双从核心亮点)1. **双主写负载均衡**:通过 `writeBalanceType: "BALANCE_ALL_WRITE"` + 双主 `instanceType: "WRITE"`,写请求会均匀分发到两个主库,分摊写压力;2. **双从读负载均衡**:通过 `readBalanceType: "BALANCE_ALL_READ"` + 双从 `instanceType: "READ"`,读请求均匀分发到两个从库,最大化读性能;3. **故障自动切换**:- 主库故障(如 masterA 宕机):Mycat 通过心跳检测发现后,自动将写请求切换到 masterB,业务无感知;- 从库故障(如 slaveA 宕机):自动剔除故障从库,读请求仅分发到正常从库(slaveB),不影响业务;4. **同步延迟过滤**:`slaveThreshold: 0.5` 表示从库同步延迟超过 0.5 秒时,Mycat 会暂时剔除该从库,避免读旧数据。## 四、启动与验证### 1. 启动 Mycat```bash# 重启 Mycat 加载配置/usr/local/mycat/bin/mycat restart# 查看启动状态(确保 8066 端口监听)netstat -tunlp | grep 8066```### 2. 验证配置正确性#### 2.1 连接 Mycat 逻辑库```bashmysql -h 192.168.90.58 -P 8066 -u mycat_app -pMycat@666```#### 2.2 验证逻辑库与集群关联```sql-- 查看逻辑库show databases;-- 应输出:business(配置的逻辑库名称)-- 查看 Mycat 数据源状态(Mycat 2.x 专用命令)/*+ mycat:showDataSources{}*/ \G-- 应显示 4 个数据源(masterA、masterB、slaveA、slaveB),状态为 OK-- 查看集群状态/*+ mycat:showClusters{}*/ \G-- 应显示集群 dual_master_dual_slave,主从节点正常```#### 2.3 验证读写分离效果```sql-- 1. 写操作(插入数据,会路由到双主之一)use business;create table test_user (id int primary key auto_increment, name varchar(20));insert into test_user (name) values ("user1"), ("user2");-- 2. 查看双主数据(均应存在插入的数据,证明双主同步正常)-- 直接连接 masterA 查看mysql -h 192.168.90.61 -u mycat_user -pMycat@123 -e "select * from business.test_user";-- 直接连接 masterB 查看mysql -h 192.168.90.62 -u mycat_user -pMycat@123 -e "select * from business.test_user";-- 3. 查看双从数据(均应同步主库数据,证明主从同步正常)mysql -h 192.168.90.63 -u mycat_user -pMycat@123 -e "select * from business.test_user";mysql -h 192.168.90.64 -u mycat_user -pMycat@123 -e "select * from business.test_user";-- 4. 读操作(通过 Mycat 查询,会路由到双从之一)-- 多次执行,观察 Mycat 日志(conf/logs/mycat.log),确认读请求分流到 slaveA/slaveBselect * from test_user;```## 五、注意事项1. **双主复制前提**:必须确保双主互为主从配置正确(开启 GTID 模式最佳,避免同步冲突);2. **权限统一**:所有 MySQL 节点的 `mycat_user` 权限必须一致(至少拥有业务库的读写权限);3. **生产环境优化**:- 限制 Mycat 访问 IP(在用户配置文件中指定 `ip: "192.168.90.0/24"`);- 调整 `maxCon`(连接数)、`idleTimeout`(空闲超时)适配业务压力;- 开启 Mycat 日志审计,便于排查问题;4. **避免写冲突**:双主架构下,若同一表存在并发写,需确保表有主键(或唯一索引),避免同步报错。## 总结双主双从的 Mycat 配置核心是 **“数据源分角色(双主WRITE/双从READ)+ 集群配置写负载/读负载/故障切换”**,配置步骤与单主多从一致,仅需在集群中增加主库数据源、启用写负载策略即可。你的单主多从配置思路完全可复用,只需扩展数据源和调整集群参数,放心按此方案提交作业!3
Terminal window ### 一、检查启动状态与基础环境1. **查看启动状态与错误提示**- 用`/usr/local/mycat/bin/mycat status`查看运行状态。- 手动启动并观察报错:`/usr/local/mycat/bin/mycat start 2>&1 | grep -E "ERROR|Exception"`。- 若提示“command not found”,用`find / -name "mycat" 2>/dev/null`找正确路径。2. **验证 JDK 环境**- 检查版本:`java -version`。- 检查环境变量:`echo $JAVA_HOME`。- 未配置则临时配置:`export JAVA_HOME=/usr/lib/jvm/java - 1.8.0 - openjdk; export PATH=$PATH:$JAVA_HOME/bin`。- 永久配置:在`/etc/profile`添加配置并`source /etc/profile`。### 二、查看核心日志日志默认路径`/usr/local/mycat/conf/logs/`:1. **主日志 mycat.log**:`tail -100 /usr/local/mycat/conf/logs/mycat.log | grep -E "ERROR|WARN|Exception"`。2. **启动器日志 wrapper.log**:`tail -100 /usr/local/mycat/conf/logs/wrapper.log | grep -E "ERROR|FATAL"`。### 三、排查配置文件错误1. **检查语法**:用`jq`工具校验 JSON 格式配置文件。2. **检查关键参数**:核对`datasources`、`clusters`、`schemas`、`users`配置文件参数。### 四、排查端口占用问题Mycat 默认用 8066 和 9066 端口:1. 用`netstat -tunlp | grep`或`lsof -i:`检查端口占用。2. 停止占用进程或修改`/usr/local/mycat/conf/mycat.properties`中的端口。### 五、排查权限与目录访问问题1. 检查目录权限,不足则`chmod -R 755 /usr/local/mycat/`。2. 检查日志目录写入权限,可`chmod 777 /usr/local/mycat/conf/logs/`。3. 检查运行用户,必要时修改目录所有者。### 六、排查数据源连接问题1. 测试网络连通性:`telnet`或`nc`。2. 验证账号密码,检查账号存在性、权限和服务状态。3. 检查防火墙/安全组,放行 3306 端口。### 七、排查依赖与元数据问题(Mycat 2.x 特有)1. 检查原型库配置文件。2. 验证原型库连接。3. 检查依赖 jar 包,缺失则手动下载。### 八、极端情况:恢复默认配置,逐步测试1. 备份当前配置。2. 删除自定义配置。3. 恢复默认原型库配置。4. 启动 Mycat。5. 逐步添加自定义配置并测试。Terminal window # Mycat 服务启动失败:故障排查与解决完整操作流程Mycat 启动失败的核心原因集中在 **环境依赖、配置错误、端口占用、权限不足、数据源连接异常** 五类,排查需遵循“从基础到深入、从日志到配置”的逻辑,逐步定位问题。以下是详细操作流程(基于 Mycat 2.x,兼容 1.x 核心思路):## 一、第一步:检查启动状态与基础环境(快速排除低级问题)### 1. 查看 Mycat 启动状态与错误提示首先通过官方命令查看启动状态,获取直接报错信息:```bash# 1. 查看 Mycat 运行状态(Mycat 2.x 命令)/usr/local/mycat/bin/mycat status# 2. 尝试手动启动,观察实时报错(关键!直接输出启动失败原因)/usr/local/mycat/bin/mycat start 2>&1 | grep -E "ERROR|Exception"# 3. 若提示“command not found”,确认 Mycat 安装路径正确find / -name "mycat" 2>/dev/null # 找到正确路径(如 /opt/mycat),替换执行```#### 常见状态与初步判断:- 提示“not running”:服务未启动,需进一步查日志;- 提示“Invalid JAVA_HOME”:JDK 环境未配置;- 提示“Address already in use”:端口被占用;- 提示“Could not load configuration”:配置文件错误。### 2. 验证核心依赖:JDK 环境(Mycat 必需)Mycat 依赖 JDK 1.8+(1.x 支持 1.7,2.x 强制 1.8+),先确认环境:```bash# 1. 检查 JDK 版本java -version# 正常输出示例:openjdk version "1.8.0_382"(需 1.8+,低于则报错)# 2. 检查 JAVA_HOME 环境变量echo $JAVA_HOME# 正常输出示例:/usr/lib/jvm/java-1.8.0-openjdk# 3. 若未配置 JAVA_HOME,手动配置(临时生效)export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdkexport PATH=$PATH:$JAVA_HOME/bin# 4. 永久配置(避免重启失效)echo 'export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk' >> /etc/profileecho 'export PATH=$PATH:$JAVA_HOME/bin' >> /etc/profilesource /etc/profile```#### 问题解决:- 无 JDK:执行 `yum -y install java-1.8.0-openjdk.x86_64`(CentOS)安装;- JDK 版本过低:卸载旧版本,重新安装 1.8+。## 二、第二步:查看核心日志(定位问题关键)Mycat 启动失败的详细原因会记录在日志中,优先查看以下 2 个核心日志文件(默认路径:`/usr/local/mycat/conf/logs/`):### 1. 主日志:mycat.log(记录配置加载、数据源连接、启动流程错误)```bash# 查看日志最后 100 行(聚焦最新错误)tail -100 /usr/local/mycat/conf/logs/mycat.log | grep -E "ERROR|WARN|Exception"# 若日志过大,搜索关键词定位grep -n "Failed to" /usr/local/mycat/conf/logs/mycat.log # 搜索失败相关记录```### 2. 启动器日志:wrapper.log(记录 JVM 启动、进程启动失败原因)```bashtail -100 /usr/local/mycat/conf/logs/wrapper.log | grep -E "ERROR|FATAL"```#### 日志常见错误与对应解决:| 日志错误关键词 | 问题原因 | 快速解决 ||-----------------------------|-----------------------------------|-----------------------------------|| Invalid JSON syntax | 配置文件(.json)语法错误 | 检查对应 JSON 文件的逗号、引号闭合 || Could not connect to datasource | 数据源(MySQL)连接失败 | 验证 MySQL 地址、账号密码、网络连通性 || Address already in use: 8066 | 8066/9066 端口被占用 | 查找并停止占用进程,或修改 Mycat 端口 || Permission denied | Mycat 目录/文件权限不足 | 赋予读写权限:chmod -R 755 /usr/local/mycat || Missing jar包名 | 依赖 jar 包缺失 | 从安装包复制缺失 jar 到 lib 目录 |## 三、第三步:排查配置文件错误(最常见原因)Mycat 启动时会加载 `datasources`(数据源)、`clusters`(集群)、`schemas`(逻辑库)、`users`(用户)四类核心配置文件,JSON 语法错误、参数配置错误是主要诱因。### 1. 检查配置文件语法(JSON 格式必须严格)Mycat 2.x 配置文件均为 JSON 格式,逗号、引号、大括号不闭合会直接导致启动失败,用 `jq` 工具验证:```bash# 1. 安装 jq 工具(JSON 语法校验)yum -y install jq# 2. 逐个校验核心配置文件(以 datasources 为例)# 校验数据源配置(所有 .datasource.json 文件)for file in /usr/local/mycat/conf/datasources/*.json; doecho "校验文件:$file"jq . $file # 语法错误会直接提示行号done# 3. 同理校验集群、逻辑库、用户配置for file in /usr/local/mycat/conf/clusters/*.json; do jq . $file; donefor file in /usr/local/mycat/conf/schemas/*.json; do jq . $file; donefor file in /usr/local/mycat/conf/users/*.json; do jq . $file; done```#### 语法错误示例与修复:- 错误:`{"name":"masterA", "password":"123"}`(末尾多逗号)- 修复:`{"name":"masterA", "password":"123"}`(删除末尾逗号)### 2. 检查关键配置参数(参数错误导致启动失败)重点核对以下核心参数(配置文件中最易出错):#### 2.1 数据源配置(datasources/*.json)```json{"url": "jdbc:mysql://192.168.90.61:3306?serverTimezone=Asia/Shanghai&useUnicode=true", // 确保 IP、端口正确"user": "mycat_user", // MySQL 账号存在且有权限"password": "Mycat@123", // 密码正确"instanceType": "WRITE", // 取值只能是 WRITE/READ/READ_WRITE(大小写敏感)"dbType": "mysql" // 不能写错(如写成 "mysql8" 无效)}```#### 2.2 集群配置(clusters/*.json)```json{"name": "dual_master_dual_slave","masters": ["masterA", "masterB"], // 数据源名称必须与 datasources 中一致"replicas": ["slaveA", "slaveB"], // 同上,不能拼写错误"clusterType": "MASTER_SLAVE", // 取值只能是 MASTER_SLAVE/SINGLE/CLUSTER"writeBalanceType": "BALANCE_ALL_WRITE" // 取值符合 Mycat 规则}```#### 2.3 逻辑库配置(schemas/*.json)```json{"schemaName": "business","targetName": "dual_master_dual_slave" // 集群名称必须与 clusters 中一致}```#### 2.4 用户配置(users/*.json)```json{"username": "mycat_app","password": "Mycat@666", // 不能包含特殊字符(如 @ 需转义,或直接用简单密码测试)"dialect": "mysql" // 不能写错}```## 四、第四步:排查端口占用问题Mycat 默认占用 2 个端口:- 8066:业务端口(应用连接 Mycat 用)- 9066:管理端口(Mycat 管理命令用)端口被占用会直接导致启动失败,排查流程:```bash# 1. 检查 8066 端口占用情况netstat -tunlp | grep 8066# 或用 lsof(更详细)lsof -i:8066# 2. 检查 9066 端口占用情况netstat -tunlp | grep 9066# 3. 若有占用进程,停止该进程(示例:PID 为 1234)kill -9 1234# 4. 若无法停止占用进程,修改 Mycat 端口(Mycat 2.x 配置)vi /usr/local/mycat/conf/mycat.properties# 修改以下参数(自定义未占用端口)server.port=8067 # 新业务端口manager.port=9067 # 新管理端口# 5. 重启 Mycat 测试/usr/local/mycat/bin/mycat restart```## 五、第五步:排查权限与目录访问问题Mycat 启动时需要读取配置文件、写入日志,权限不足会导致“Permission denied”错误:```bash# 1. 检查 Mycat 安装目录权限ls -ld /usr/local/mycat/# 正常权限:drwxr-xr-x(所有者、组有读写执行权限)# 2. 赋予完整权限(临时测试,生产环境可收紧)chmod -R 755 /usr/local/mycat/# 3. 检查日志目录写入权限(关键!日志写不进去会启动失败)ls -ld /usr/local/mycat/conf/logs/chmod 777 /usr/local/mycat/conf/logs/ # 临时赋予最大权限测试# 4. 检查运行用户(若用非 root 用户启动,需确保用户有目录权限)ps -ef | grep mycat # 查看运行用户chown -R mycat:mycat /usr/local/mycat/ # 若用 mycat 用户,修改目录所有者```## 六、第六步:排查数据源连接问题若数据源(MySQL 主从节点)配置错误或无法连通,Mycat 启动时会因“连接数据源失败”报错:```bash# 1. 手动测试 Mycat 到 MySQL 数据源的网络连通性(以 masterA 为例)telnet 192.168.90.61 3306# 或用 nc 命令nc -zv 192.168.90.61 3306# 正常输出:succeeded!(失败则检查防火墙/安全组)# 2. 手动验证 MySQL 账号密码正确性(用 Mycat 配置的账号)mysql -h 192.168.90.61 -u mycat_user -pMycat@123# 若登录失败,检查:# - MySQL 账号是否存在:SELECT user, host FROM mysql.user WHERE user='mycat_user';# - 账号权限是否足够:GRANT ALL ON *.* TO 'mycat_user'@'%' IDENTIFIED WITH mysql_native_password BY 'Mycat@123';# - MySQL 服务是否正常:systemctl status mysqld# 3. 检查 MySQL 防火墙/安全组(放行 3306 端口)firewall-cmd --zone=public --add-port=3306/tcp --permanentfirewall-cmd --reload```## 七、第七步:排查依赖与元数据问题(Mycat 2.x 特有)Mycat 2.x 依赖“原型库(prototypeDs)”存储元数据,原型库配置错误会导致启动失败:```bash# 1. 检查原型库配置文件cat /usr/local/mycat/conf/datasources/prototypeDs.datasource.json# 核心要求:原型库必须是可连接的 MySQL 实例(可复用主库/独立库)# 2. 验证原型库连接mysql -h 192.168.90.61 -u mycat_user -pMycat@123 # 原型库配置的账号密码# 3. 检查依赖 jar 包(缺失会导致类加载失败)ls /usr/local/mycat/lib/ | grep -E "mycat2|mysql-connector-java"# 若缺失 mysql-connector-java(MySQL 驱动),手动下载放入 lib 目录wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.33/mysql-connector-java-8.0.33.jar -P /usr/local/mycat/lib/```## 八、第八步:极端情况:恢复默认配置,逐步测试若以上排查均无效,可能是配置文件错乱,可通过“恢复默认+逐步添加配置”定位问题:```bash# 1. 备份当前配置(避免丢失)cp -r /usr/local/mycat/conf /usr/local/mycat/conf_bak_$(date +%Y%m%d)# 2. 删除自定义配置(保留默认原型库和用户配置)rm -rf /usr/local/mycat/conf/datasources/*.jsonrm -rf /usr/local/mycat/conf/clusters/*.jsonrm -rf /usr/local/mycat/conf/schemas/*.json# 3. 恢复默认原型库配置(从安装包复制,或手动创建)cat > /usr/local/mycat/conf/datasources/prototypeDs.datasource.json << EOF{"dbType":"mysql","idleTimeout":60000,"initSqls":[],"initSqlsGetConnection":true,"instanceType":"READ_WRITE","maxCon":1000,"maxConnectTimeout":3000,"maxRetryCount":5,"minCon":1,"name":"prototypeDs","password":"Mycat@123","type":"JDBC","url":"jdbc:mysql://192.168.90.61:3306/mysql?serverTimezone=Asia/Shanghai","user":"mycat_user","weight":0}EOF# 4. 启动 Mycat(若能启动,说明默认配置正常,问题在自定义配置)/usr/local/mycat/bin/mycat start# 5. 逐步添加自定义配置(每次添加一个文件,重启测试)# 先添加一个数据源 → 启动测试# 再添加集群 → 启动测试# 最后添加逻辑库 → 启动测试# 定位到导致失败的具体配置文件,针对性修改```## 九、常见故障案例与快速解决| 故障现象 | 排查流程 | 解决方法 ||-----------------------------------|-----------------------------------|-----------------------------------|| 执行 mycat start 无反应,日志无输出 | 1. 检查 JAVA_HOME;2. 检查 wrapper.log | 配置 JAVA_HOME,或重新安装 Mycat 启动器 || 启动提示“数据源连接失败” | 1. telnet 测试 MySQL 端口;2. 验证账号密码 | 放行 3306 端口,重新创建 MySQL 账号并授权 || JSON 语法错误导致启动失败 | 用 jq 工具校验所有配置文件 | 修复逗号、引号、大括号闭合问题 || 8066 端口被占用 | netstat 查找占用进程 | 停止占用进程,或修改 Mycat 端口 || 权限不足“Permission denied” | 检查 Mycat 目录权限 | chmod -R 755 /usr/local/mycat |## 十、排查总结(核心逻辑)Mycat 启动失败排查遵循“**先基础(环境、端口、权限)→ 再日志(定位方向)→ 最后配置(精准修复)** ”的逻辑,90% 的问题集中在:1. JDK 环境未配置或版本过低;2. 配置文件(JSON)语法错误;3. 数据源(MySQL)连接失败(IP/端口/账号/防火墙);4. 8066/9066 端口被占用;5. Mycat 目录权限不足。按以上流程逐步排查,均可定位并解决问题。若仍失败,可提供 `mycat.log` 和 `wrapper.log` 中的错误关键词,进一步精准分析。 -