MySQL主从复制与读写分离

MySQL主从复制与读写分离

文章目录


前言

本文围绕这一核心架构,从原理拆解到实操落地展开:先剖析主从复制的 "两日志、三线程" 核心机制与同步方式,再详解基于 CentOS 环境的 1 主 2 从部署实验;继而延伸至读写分离,对比不同实现方案,并通过 Amoeba 代理完成实操验证,同时覆盖常见故障排查方法,旨在帮助读者不仅理解 "是什么",更能掌握 "怎么做",为企业级 MySQL 架构落地提供可复用的技术指南。


一、主从复制

(一)核心原理

主从复制是实现数据多节点同步、为读写分离打基础的核心机制,其核心可总结为两日志、三线程,同时支持多种同步方式。

  1. 复制类型

    • 基于语句的复制(STATEMENT,默认):直接记录执行的SQL语句,日志量小,但对函数、触发器等场景可能存在同步不一致。
    • 基于行的复制(ROW):记录数据行的变更(如某行数据从A改成B),同步精度高,适合复杂业务,但日志量较大。
    • 混合类型的复制(MIXED):自动切换两种模式,简单操作用STATEMENT,复杂操作切换为ROW,兼顾效率与一致性。
  2. 核心组件:两日志+三线程

    • 两日志
      1. 二进制日志(Binary log):主库特有,记录所有修改数据的SQL操作(不记录SELECT等读操作),是主从同步的数据源。
      2. 中继日志(Relay log):从库特有,从主库同步二进制日志后,会先写入中继日志,再由SQL线程重放执行。
    • 三线程
      1. dump线程:主库端线程,负责响应从库I/O线程的请求,将主库二进制日志的事件发送给从库。
      2. I/O线程:从库端线程,负责连接主库、拉取二进制日志事件,并写入本地中继日志。
      3. SQL线程:从库端线程,负责读取中继日志中的事件,重放SQL操作以同步主库数据。
  3. 同步方式

    同步方式 核心逻辑 优缺点
    异步复制(默认) 主库写入二进制日志后直接响应客户端,不等待从库同步 性能最优,但主库宕机可能丢失未同步数据
    同步复制 主库需等待所有从库完成数据同步并执行成功后,才响应客户端 数据安全性最高,但性能损耗极大,几乎不用于生产
    半同步复制(MySQL5.5+) 主库等待至少1个从库将日志写入中继日志后,再响应客户端 兼顾性能与安全性,超时会自动切回异步
    增强半同步复制(MySQL5.7+,无损复制) 将等待从库ACK的时机放在主库事务提交前,避免主从切换的数据不一致 生产常用,是半同步的优化版本
  4. 主从复制延迟及解决

    • 延迟原因:主库高并发事务堆积、网络延迟、主从硬件性能差异、异步复制的机制特性。
    • 优化方案 :从库加大内存缓存(如调大innodb_buffer_pool_size)、使用高性能物理机和SSD磁盘、优化网络(避免跨机房同步);也可开启并行复制 解决从库串行执行的瓶颈,开启半同步复制解决数据丢失问题。

(二)主从复制实验(详细部署与操作)

本实验基于CentOS7.9环境,搭建1主(192.168.10.16)2从(192.168.10.14/15,均为MySQL5.7)的同步架构。

  1. 前置步骤:主从服务器时间同步

    时间不一致会导致日志同步时序混乱,因此需先完成时间校准。

    • Master服务器配置

      1. 安装NTP工具:yum -y install ntpdate ntp

      2. 同步阿里云公共时间源:ntpdate ntp.aliyun.com

      3. 修改NTP配置文件(vi /etc/ntp.conf),添加本机为内网时间源:

        conf 复制代码
        fudge 127.127.1.0 stratum 10  # 本机时间层级(非0级,不对外提供公共时间)
        server 127.127.1.0  # 本机作为内网时间源
      4. 启动NTP服务并关闭防火墙/SELinux:

        bash 复制代码
        systemctl start ntpd
        systemctl stop firewalld
        setenforce 0
    • Slave服务器配置

      1. 安装NTP工具:yum install ntp ntpdate -y
      2. 关闭防火墙/SELinux,同步Master的时间:ntpdate 192.168.10.16
      3. 配置定时任务,每10分钟同步一次:crontab -e,添加*/10 * * * * /usr/sbin/ntpdate 192.168.10.16
  2. 核心步骤:配置主从同步

    • Master服务器配置
      1. 修改MySQL配置文件(vi /etc/my.cnf),在mysqld模块添加如下内容,开启二进制日志并设置唯一ID:

        conf 复制代码
        log_bin=master-bin  # 二进制日志文件名前缀
        log_slave-updates=true  # 允许从库同步日志
        server_id = 1  # 主库ID,需唯一
      2. 重启MySQL服务:systemctl restart mysqld

      3. 登录MySQL,创建同步专用账号并授权(允许192.168.10.0网段的从库连接):

        sql 复制代码
        GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.10.%' IDENTIFIED BY '123456';
        flush privileges;  # 刷新权限
      4. 查看主库状态,记录二进制日志文件名和偏移量(后续从库需用到):

        sql 复制代码
        show master status;

        示例结果中,Filemaster-bin.000001Position412,这两个值是从库同步的"起点"。

    • Slave服务器配置(两台从库配置一致,以192.168.10.14为例)
      1. 修改MySQL配置文件(vi /etc/my.cnf),开启中继日志并设置唯一ID:

        conf 复制代码
        log-bin=master-bin
        server_id = 22  # 从库ID,不可与主库/其他从库重复(另一台从库设为23)
        relay-log=relay-log-bin  # 中继日志文件名前缀
        relay-log-index=slave-relay-bin.index  # 中继日志索引文件
      2. 重启MySQL服务,登录MySQL后配置主库连接信息,指定同步起点:

        sql 复制代码
        change master to 
        master_host='192.168.10.16',  # 主库IP
        master_user='myslave',  # 同步专用账号
        master_password='123456',  # 账号密码
        master_log_file='master-bin.000001',  # 主库二进制日志文件名
        master_log_pos=412;  # 主库日志偏移量
      3. 启动从库同步功能并查看状态:

        sql 复制代码
        start slave;
        show slave status\G;  # 注意结尾的\G用于格式化输出

        关键状态指标:Slave_IO_Running=YesSlave_SQL_Running=Yes,表示从库I/O线程和SQL线程均正常运行,同步链路已打通。

  3. 测试步骤:验证数据同步

    这里选取创建数据库的示例进行验证:

    • 在Master服务器登录MySQL,执行create database work;创建名为work的数据库;
    • 分别在两台Slave服务器登录MySQL,执行show databases;,可看到work数据库已自动同步,证明主从复制生效。

(三)主从同步故障排查(常见问题)

  1. 主从不一致 :可在从库执行stop slave; SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE;跳过当前错误继续同步(生产需谨慎,需先定位错误根源)。
  2. I/O线程一直Connecting :大概率是二进制日志位置不匹配,可在主库执行flush logs;生成新日志,再重新获取主库日志文件名和偏移量,在从库执行change master to指定新的同步起点。

二、读写分离

(一)核心原理

  1. 定义 :让主库处理增删改等写操作 (INSERT/UPDATE/DELETE),从库处理查询等读操作(SELECT),通过主从复制同步写操作产生的数据变更,从而分担数据库压力。

  2. 实现方式

    实现方式 核心逻辑 优缺点
    程序代码内部实现 在代码中根据SQL类型路由(SELECT走从库,写操作走主库) 性能优、无额外硬件成本;但需开发人员实现,对大型应用代码改动大
    中间代理层实现 代理服务器接收客户端请求,自动分发到对应数据库 无需改动业务代码;需部署代理服务,有一定性能损耗(常用工具:Amoeba/Atlas/MySQL-Proxy)

(二)读写分离实验(基于Amoeba代理,详细部署)

本实验基于CentOS7.6环境,在已搭建1主2从的基础上,增加Amoeba代理服务器(192.168.10.80,需JDK1.6)和客户端服务器(192.168.10.13)实现读写分离。

  1. 前置要求:已完成1主2从的主从复制搭建,确保主从数据同步正常。

  2. Amoeba服务器配置

    Amoeba基于Java开发,需先配置Java环境,再安装和配置Amoeba。

    • 步骤1:安装JDK1.6环境
      1. 将JDK安装包上传到/opt目录,移动到/usr/local并赋予执行权限:

        bash 复制代码
        cd /opt
        cp jdk-6u14-linux-x64.bin /usr/local/
        cd /usr/local
        chmod +x jdk-6u14-linux-x64.bin
        ./jdk-6u14-linux-x64.bin  # 按提示输入yes并回车完成安装
      2. 重命名JDK目录并配置环境变量(vi /etc/profile):

        bash 复制代码
        mv jdk1.6.0_14/ /usr/local/jdk1.6
        vi /etc/profile

        添加如下环境变量:

        conf 复制代码
        export JAVA_HOME=/usr/local/jdk1.6
        export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
        export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
        export AMOEBA_HOME=/usr/local/amoeba
        export PATH=$PATH:$AMOEBA_HOME/bin
      3. 生效环境变量并验证:source /etc/profile; java -version,能显示JDK1.6版本即配置成功。

    • 步骤2:安装Amoeba软件
      1. 创建安装目录并解压安装包:

        bash 复制代码
        mkdir /usr/local/amoeba
        tar zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
        chmod -R 755 /usr/local/amoeba/
      2. 验证安装:执行/usr/local/amoeba/bin/amoeba,输出amoeba start|stop即安装成功。

    • 步骤3:配置Amoeba读写分离
      1. 先在主从库授权Amoeba访问:在Master、Slave1、Slave2的MySQL中执行grant all on *.* to test@'192.168.10.%' identified by '123456';,允许Amoeba服务器用test账号访问。
      2. 修改Amoeba主配置文件(vi /usr/local/amoeba/conf/amoeba.xml):
        • 30行:修改客户端连接Amoeba的账号为amoeba
        • 32行:修改客户端连接密码为123456
        • 115行:设置默认连接池为master
        • 117行:取消注释,指定writePool=master(写操作走主库)、readPool=slaves(读操作走从库池)。
      3. 修改数据库服务器配置文件(vi /usr/local/amoeba/conf/dbServers.xml):
        • 23行:注释掉<property name="schema">test</property>(避免无test库时报错);
        • 26行:修改访问数据库的账号为test
        • 28行:取消注释,设置数据库访问密码为123456
        • 45行:设置主库节点名为master,48行填写主库IP192.168.10.16
        • 52行:设置从库1节点名为slave1,55行填写IP192.168.10.14
        • 58行:复制从库1配置,新增从库2节点slave2,IP为192.168.10.15
        • 65行:设置从库池slaves为虚拟节点,71行指定池内节点为slave1,slave2(实现读负载均衡)。
      4. 启动Amoeba:/usr/local/amoeba/bin/amoeba start&,用netstat -anpt | grep java查看8066端口(Amoeba默认端口)是否开启。
  3. 测试步骤:验证读写分离

    在客户端服务器安装MariaDB,执行mysql -u amoeba -p123456 -h 192.168.10.80 -P8066通过Amoeba访问数据库,进行如下验证:

    • 主库创建测试表:在Master的MySQL中执行use db_test; create table test (id int(10),name varchar(10),address varchar(20));
    • 从库关闭同步并插入专属数据:Slave1执行stop slave; insert into test values('1','zhangsan','this_is_slave1');,Slave2执行stop slave; insert into test values('2','lisi','this_is_slave2');;主库执行insert into test values('3','wangwu','this_is_master');
    • 客户端执行select * from test;,只会读取到Slave1/Slave2的专属数据(读操作走从库);执行insert into test values('4','qianqi','this_is_client');,仅主库会新增该数据(写操作走主库);
    • 从库重启同步后(start slave;),客户端插入的数据会同步到从库,实现数据最终一致。

三、核心总结

  1. 主从复制是读写分离的基础,核心依赖二进制日志+中继日志dump/I/O/SQL线程 ,生产常用增强半同步复制保障数据安全;
  2. 读写分离通过代理层(如Amoeba)实现读写请求分流,有效提升数据库并发处理能力;
  3. 实验中需重点关注时间同步、主从配置参数、代理层权限与节点映射,故障排查优先检查日志和线程状态。

总结

MySQL 主从复制与读写分离,是企业从 "单库架构" 迈向 "高可用、高并发架构" 的关键一步,二者相辅相成、缺一不可 ------ 主从复制是基础,通过二进制日志与中继日志的联动、dump/I/O/SQL 线程的协作,实现了数据跨节点同步,既解决了单点故障风险,也为读写分离提供了数据一致性保障;读写分离是延伸,通过 "主库写、从库读" 的请求分流,有效化解了 "写操作耗时拖累读性能" 的矛盾,显著提升数据库并发承载能力。

相关推荐
白羊无名小猪1 小时前
正则表达式(捕获组)
java·mysql·正则表达式
羑悻的小杀马特1 小时前
Redis之Set:从无序唯一到智能存储,解锁用户画像/社交/统计全场景应用
数据库·redis·set
San301 小时前
从 Mobile First 到 AI First:用 Python 和大模型让数据库“开口说话”
数据库·python·sqlite
doris6101 小时前
2025年零门槛设备管理系统测评
数据库
小时候没少挨打1 小时前
从0到1安装NVIDIA驱动(NVSwitch+Driver+IB网络驱动)
运维·服务器·数据库
卿雪1 小时前
MySQL【存储引擎】:InnoDB、MyISAM、Memory...
java·数据库·python·sql·mysql·golang
即随本心0.o1 小时前
大模型springai,Rag,redis-stack向量数据库存储
java·数据库·redis
晴栀ay1 小时前
AI TO SQL:AIGC时代数据库操作的革命性变革
数据库·llm·aigc
Hello.Reader2 小时前
Flink SQL 中的 SELECT DISTINCT批流一体下的去重与状态管理
数据库·sql·flink