在高并发业务场景中,MySQL数据库单节点往往会面临读写压力失衡的问题------写操作(INSERT/UPDATE/DELETE)需保证数据一致性,无法轻易横向扩展;而读操作(SELECT)占比通常更高,成为性能瓶颈。MySQL读写分离通过"主从复制"实现数据同步,再通过路由组件分发读写请求,让主库专注于写操作,从库承担读操作,从而提升整体并发能力、降低单节点负载。本文将从原理、部署准备、分步配置、测试验证到优化建议,完整讲解MySQL读写分离的落地流程。
一、读写分离核心原理
1. 核心架构组成
MySQL读写分离架构主要包含三个核心组件,协同实现请求分发与数据同步:
-
主库(Master):唯一处理写请求的节点,同时通过二进制日志(binlog)记录所有数据变更操作,作为数据同步的数据源。
-
从库(Slave):1个或多个从节点,通过IO线程读取主库的binlog,再通过SQL线程重放日志,实现与主库数据一致;仅处理读请求,分担主库读压力。
-
路由中间件:接收应用层请求,根据SQL类型分发至对应节点(写请求→主库,读请求→从库),常见组件有MyCat、ProxySQL、Sharding-JDBC等。
2. 数据同步流程(主从复制)
主从复制是读写分离的基础,基于binlog实现异步/半同步数据同步,流程如下:
-
主库开启binlog,每执行一次写操作,都会将操作记录到binlog中(按事件格式存储)。
-
从库启动后,通过IO线程连接主库,请求主库发送binlog日志(从指定位置开始)。
-
主库的dump线程接收请求,将binlog日志增量推送给从库IO线程,从库IO线程将日志写入本地中继日志(relay log)。
-
从库的SQL线程读取中继日志,按顺序重放日志中的操作,同步主库数据。
3. 路由分发逻辑
路由中间件通过解析SQL语句的类型,实现请求分发:
-
写请求(含事务类操作):直接路由至主库,确保数据一致性(避免写操作分散导致的数据冲突)。
-
读请求:路由至从库(可配置负载均衡策略,如轮询、加权轮询),若从库异常,可自动切换至主库兜底。
二、部署前准备
1. 环境规划
本次部署采用"1主2从+MyCat中间件"架构,服务器配置如下(生产环境建议独立节点,避免资源竞争):
|-------------|---------------|------------------|---------------|----------------------|
| 节点角色 | IP地址 | 操作系统 | MySQL版本 | 核心作用 |
| 主库(Master) | 192.168.1.100 | Ubuntu 20.04 LTS | MySQL 8.0 | 处理写请求,生成binlog |
| 从库1(Slave1) | 192.168.1.101 | Ubuntu 20.04 LTS | MySQL 8.0 | 处理读请求,同步主库数据 |
| 从库2(Slave2) | 192.168.1.102 | Ubuntu 20.04 LTS | MySQL 8.0 | 处理读请求,同步主库数据,实现读负载均衡 |
| MyCat节点 | 192.168.1.103 | Ubuntu 20.04 LTS | MyCat 1.6.7.6 | 请求路由,读写分离分发 |
2. 基础环境配置
所有节点需完成以下基础配置,避免部署过程中出现异常:
-
关闭防火墙/开放端口:Ubuntu 20.04默认使用ufw防火墙,开放MySQL(3306)、MyCat(8066)端口,或直接关闭ufw(生产环境建议精准开放端口)。
# 开放指定端口并启用
sudo ufw allow 3306/tcp
sudo ufw allow 8066/tcp
sudo ufw enable
# 若需临时关闭防火墙(测试环境)
sudo ufw disable
# Ubuntu无SELinux,无需额外关闭操作
-
安装依赖:主从节点安装MySQL 8.0(Ubuntu 20.04 apt源自带),MyCat节点安装JDK 1.8。
# 主从节点安装MySQL 8.0 sudo apt update sudo apt install -y mysql-server mysql-client # MyCat节点安装JDK 1.8 sudo apt install -y openjdk-8-jdk # 验证JDK安装 java -version -
时钟同步:Ubuntu 20.04默认搭载systemd-timesyncd服务,启用即可实现时间同步,避免因时间差导致binlog同步失败。
# 启用时间同步服务 sudo timedatectl set-ntp on # 验证同步状态 timedatectl status
三、分步部署配置
第一步:配置主库(Master)
主库核心配置是开启binlog,设置唯一节点ID,授权从库同步账号。
-
修改MySQL配置文件:
[mysqld] # 开启binlog,指定日志存储路径 log_bin = /var/lib/mysql/mysql-bin.log # binlog日志格式(建议ROW,避免语句级同步的一致性问题) binlog_format = ROW # 主库唯一ID(1-2^32-1,不可与从库重复) server-id = 1 # 仅同步指定数据库(可选,按需配置,不配置则同步所有库) binlog_do_db = test_db # 忽略同步的数据库(可选) binlog_ignore_db = mysql binlog_ignore_db = information_schema # 确保binlog写入磁盘(提升数据可靠性,生产环境建议开启) sync_binlog = 1 # 禁止从库写入(从库需配置,主库可选) read_only = 0 # 允许超级用户在read_only模式下写入(主库必备) super_read_only = 0 -
重启MySQL服务:Ubuntu 20.04 MySQL服务名为mysql,命令如下:
sudo systemctl restart mysql && sudo systemctl enable mysql -
创建从库同步账号并授权:登录MySQL,创建专门用于主从复制的账号,授予复制权限。
-- 登录MySQL mysql -u root -p -- 创建同步账号(slave_user为账号,192.168.1.%为从库IP段,可限制具体IP) CREATE USER 'slave_user'@'192.168.1.%' IDENTIFIED BY 'Slave@123456'; -- 授予复制权限 GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'192.168.1.%'; -- 刷新权限 FLUSH PRIVILEGES; -- 查看主库binlog状态(记录File和Position值,从库配置需用到) SHOW MASTER STATUS;执行结果需记录:File(如mysql-bin.000001)、Position(如156),后续从库配置需以此为起点同步。
第二步:配置从库(Slave1/Slave2)
两个从库配置流程一致,核心是指定主库信息,开启同步线程。
-
修改MySQL配置文件:编辑/etc/my.cnf,添加以下配置(两个从库server-id需不同):
[mysqld] # 从库唯一ID(Slave1设为2,Slave2设为3,不可重复且不等于主库) server-id = 2 # 开启中继日志(存储主库binlog,用于重放) relay_log = /var/lib/mysql/relay-bin.log # 中继日志索引文件 relay_log_index = /var/lib/mysql/relay-bin.index # 从库只读(禁止写操作,确保数据与主库一致) read_only = 1 # 超级用户也只读(生产环境建议开启) super_read_only = 1 # 忽略同步错误(可选,避免因小错误导致同步中断) slave_skip_errors = 1062 -
重启MySQL服务:
sudo systemctl restart mysql && sudo systemctl enable mysql -
配置主从同步参数:登录MySQL,指定主库IP、同步账号、binlog文件及位置,启动同步线程。
-- 登录MySQL mysql -u root -p -- 停止现有同步(首次配置可忽略) STOP SLAVE; -- 配置主库信息 CHANGE MASTER TO MASTER_HOST='192.168.1.100', -- 主库IP MASTER_USER='slave_user', -- 同步账号 MASTER_PASSWORD='Slave@123456', -- 同步密码 MASTER_LOG_FILE='mysql-bin.000001', -- 主库binlog文件名(第一步记录的File) MASTER_LOG_POS=156; -- 主库binlog位置(第一步记录的Position) -- 启动同步线程 START SLAVE; -- 查看同步状态 SHOW SLAVE STATUS -
验证同步状态:执行SHOW SLAVE STATUS\G后,需满足两个核心条件,说明同步正常:Slave_IO_Running: Yes(IO线程正常,能读取主库binlog)
-
Slave_SQL_Running: Yes(SQL线程正常,能重放中继日志)
第三步:配置MyCat中间件(路由分发)
MyCat作为路由中间件,通过配置文件实现读写分离规则,应用层只需连接MyCat,无需感知主从节点。
-
安装MyCat:Ubuntu 20.04解压安装步骤一致,补充依赖检查命令:
# 确认JDK已安装 java -version # 下载MyCat压缩包 wget http://dl.mycat.org.cn/1.6.7.6/20220524173829/Mycat-server-1.6.7.6-release-20220524173829-linux.tar.gz # 解压至/usr/local目录 sudo tar -zxvf Mycat-server-1.6.7.6-release-20220524173829-linux.tar.gz -C /usr/local/ # 配置环境变量(可选) echo "export MYCAT_HOME=/usr/local/mycat" | sudo tee -a /etc/profile source /etc/profile # 授权MyCat目录权限 sudo chmod 755 -R /usr/local/mycat -
核心配置文件修改:MyCat的读写分离规则主要通过3个文件配置,均位于/usr/local/mycat/conf目录。 (1)schema.xml(定义逻辑库、数据源、读写规则
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <!-- 逻辑库名称(应用层连接时使用),与物理库test_db对应 --> <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/> <!-- 数据节点,指定物理数据库 --> <dataNode name="dn1" dataHost="localhost1" database="test_db"/> <!-- 数据源配置,指定主从节点信息 --> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- 主库配置(写节点) --> <writeHost host="hostM1" url="192.168.1.100:3306" user="root" password="Root@123456"> <!-- 从库配置(读节点),两个从库依次配置 --> <readHost host="hostS1" url="192.168.1.101:3306" user="root" password="Root@123456"/> <readHost host="hostS2" url="192.168.1.102:3306" user="root" password="Root@123456"/> </writeHost> </dataHost> </mycat:schema>关键参数说明:(2)server.xml(配置应用层访问账号)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:server SYSTEM "server.dtd"> <mycat:server xmlns:mycat="http://io.mycat/"> <user name="mycat_user" defaultAccount="true"> <property name="password">Mycat@123456</property> <property name="schemas">TESTDB</property><!-- 关联逻辑库TESTDB --> </user> </mycat:server>应用层将通过账号mycat_user、密码Mycat@123456连接MyCat。(3)rule.xml(分片规则,读写分离无需修改,默认即可)若无需分库分表,保持默认配置,仅用于定义路由规则占位。
-
balance="1":读请求分发至所有从库,实现读负载均衡。
-
writeType="0":写请求仅分发至第一个writeHost(主库)。
-
switchType="1":主库故障时,自动切换至从库(需配合心跳检测)。
-
-
启动MyCat:Ubuntu 20.04下启动命令一致,补充日志权限说明:
# 启动MyCat sudo /usr/local/mycat/bin/mycat start # 查看启动状态 sudo /usr/local/mycat/bin/mycat status # 日志位置(排查启动异常用,若权限不足可加sudo) sudo tail -f /usr/local/mycat/logs/wrapper.logMyCat默认端口为8066(数据端口)、9066(管理端口)。
四、读写分离测试验证
测试核心是验证"写请求走主库、读请求走从库",且主从数据同步正常。
1. 连接MyCat测试
# 应用层连接MyCat(使用MyCat账号密码,端口8066)
mysql -u mycat_user -pMycat@123456 -h 192.168.1.103 -P 8066
2. 写操作测试(验证走主库)
-- 连接MyCat后,执行写操作(插入数据)
USE TESTDB;
INSERT INTO user (id, name, age) VALUES (1, 'test_user', 25);
-- 分别登录主库、从库,查看数据是否同步
-- 主库查询
mysql -u root -p -h 192.168.1.100 -e "SELECT * FROM test_db.user;"
-- 从库1查询
mysql -u root -p -h 192.168.1.101 -e "SELECT * FROM test_db.user;"
结果:主库、从库均能查询到新增数据,说明写操作成功路由至主库,且主从同步正常。Ubuntu 20.04可通过以下命令快速验证主从数据(无需交互输入密码):
# 主库查询(需提前配置MySQL免密或输入密码)
sudo mysql -u root -p -h 192.168.1.100 -e "SELECT * FROM test_db.user;"
# 从库1查询
sudo mysql -u root -p -h 192.168.1.101 -e "SELECT * FROM test_db.user;"
3. 读操作测试(验证走从库)
通过开启MySQL慢查询日志,验证读请求是否分发至从库:
-
在两个从库开启慢查询日志(记录所有读请求):
SET GLOBAL slow_query_log = 1; SET GLOBAL slow_query_log_file = '/var/lib/mysql/slow.log'; SET GLOBAL long_query_time = 0; -- 记录所有查询(包括快速查询) -
连接MyCat执行读操作:
SELECT * FROM test_db.user; -
查看从库慢查询日志:
tail -f /var/lib/mysql/slow.log结果:从库1或从库2的日志中会出现该查询记录,主库慢查询日志无记录,说明读请求成功路由至从库。
4. 负载均衡测试(多从库场景)
多次执行读操作,观察两个从库的慢查询日志,会发现请求按轮询方式分发至两个从库,实现读负载均衡。
五、常见问题排查
1. 主从复制失败(IO/SQL线程为No)
-
IO线程失败:检查主从网络是否通(ping、telnet 3306端口)、同步账号密码是否正确、主库binlog文件/位置是否错误。
-
SQL线程失败:通常是主从数据不一致(如从库已有相同主键数据),可通过slave_skip_errors跳过错误,或重新初始化从库数据(备份主库数据导入从库)。
2. 读写分离路由异常(读请求走主库)
-
检查MyCat的schema.xml中balance参数是否为1(非0),readHost配置是否正确。
-
确认SQL语句是否为纯读操作(若包含事务,MyCat会路由至主库)。
3. 数据不一致(主从数据不同步)
可能是主库binlog格式设置不当(建议ROW格式),或从库同步延迟。可通过调整sync_binlog、innodb_flush_log_at_trx_commit参数提升同步可靠性,或开启MySQL半同步复制(需额外配置)。
六、生产环境优化建议
1. 性能优化
-
主库参数优化:调整binlog相关参数(sync_binlog=1、innodb_flush_log_at_trx_commit=1),平衡性能与可靠性。
-
从库参数优化:关闭binlog(从库无需生成binlog)、调整join_buffer_size、sort_buffer_size提升读性能。
-
MyCat优化:调整maxCon(最大连接数)、优化心跳检测频率,避免频繁检测占用资源。
2. 高可用优化
-
主库高可用:通过MHA、Keepalived实现主库故障自动切换,避免主库单点故障。
-
从库高可用:增加从库节点,避免单个从库故障导致读请求中断。
-
MyCat高可用:部署多个MyCat节点,通过Keepalived实现VIP漂移,避免中间件单点故障。
3. 监控告警
通过Prometheus+Grafana、Zabbix等工具,监控主从同步状态(IO/SQL线程、同步延迟)、MyCat连接数、主从库负载,设置告警阈值(如同步延迟超过30秒告警),及时发现异常。
七、总结
MySQL读写分离通过"主从复制+路由中间件"的组合,有效解决了高并发场景下的读写压力失衡问题,是数据库水平扩展的基础方案。本文基于MySQL 8.0+MyCat实现了读写分离部署,核心在于主从复制的稳定配置和路由规则的精准定义。生产环境中,需结合业务场景优化参数、保障高可用、完善监控,才能充分发挥读写分离的性能优势。
后续可进一步探索分库分表(与读写分离结合)、MySQL 8.0新特性(如GTID复制)对读写分离的优化,适配更复杂的业务场景。