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 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
0xDevNull5 小时前
MySQL数据冷热分离详解
后端·mysql
科技小花6 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸6 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain6 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希6 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神6 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员7 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java7 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿7 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb