MySQL主从复制是MySQL高可用架构的基础,也是每个后端开发者和运维人员必须掌握的技能。通过主从复制,可以实现数据备份、读写分离、故障转移、高可用等功能,大大提升数据库的可靠性和性能。但是很多初学者对主从复制的原理和配置不太清楚,不知道从哪里入手。

今天就来写一个MySQL主从复制的入门指南,从零开始,讲清楚主从复制的原理、作用、类型、配置步骤、常见问题和最佳实践,希望能帮到想学习MySQL主从复制的朋友。

一、什么是MySQL主从复制

MySQL主从复制,就是将一台MySQL服务器(主服务器,Master)的数据,复制到另一台或多台MySQL服务器(从服务器,Slave)上的过程。复制是异步进行的,主服务器上的数据变更,会通过二进制日志(binlog)传递到从服务器,从服务器应用这些日志,从而保持和主服务器的数据一致。

主从复制的基本流程是这样的:

  1. 主服务器在数据变更的时候,会将变更记录写入二进制日志(binlog)。
  2. 从服务器的IO线程,会连接到主服务器,请求读取主服务器的binlog,然后将binlog写入到自己的中继日志(relay log)中。
  3. 从服务器的SQL线程,会读取中继日志中的事件,然后在从服务器上执行这些事件,从而将数据变更应用到从服务器上。

这个过程是异步的,主服务器不需要等待从服务器复制完成,就可以继续处理请求,所以主从复制不会影响主服务器的性能。但是因为是异步的,所以从服务器的数据可能会有一定的延迟,特别是在主服务器写入量很大的时候,延迟可能会比较明显。

主从复制是MySQL内置的功能,不需要额外的软件,只需要简单的配置就可以使用,而且非常稳定可靠,是MySQL高可用架构的基础。

二、为什么要用主从复制,它有什么作用

主从复制的作用很多,主要有以下几个方面:

1. 数据备份和容灾

这是主从复制最基本的作用。通过主从复制,可以将主服务器的数据实时复制到从服务器上,相当于有了一个实时的备份。如果主服务器出了故障,比如硬盘损坏、系统崩溃,数据不会丢失,因为从服务器上还有一份完整的数据,可以快速恢复。

而且从服务器可以部署在不同的机房、不同的地域,实现异地容灾,即使主服务器所在的机房整个出了问题,从服务器的数据还在,业务可以快速切换到从服务器,保证业务不中断。

2. 读写分离,提升性能

这是主从复制最常用的作用。通过主从复制,可以实现读写分离,写操作(增删改)在主服务器上执行,读操作(查询)在从服务器上执行。这样可以将读压力分散到从服务器上,大大减轻主服务器的压力,提升整个系统的性能和并发能力。

特别是对于读多写少的应用,比如博客、新闻、电商商品展示等,读操作占了绝大部分,用读写分离的效果非常好,可以加多个从服务器来分担读压力,水平扩展读能力。

3. 高可用和故障转移

通过主从复制,可以实现MySQL的高可用。如果主服务器出了故障,可以快速将一个从服务器提升为主服务器,继续提供服务,从而实现故障转移,保证业务不中断。

当然,主从复制本身不能自动实现故障转移,需要配合其他工具,比如MHA、Keepalived、Orchestrator等,来实现自动故障检测和转移。但是主从复制是高可用的基础,没有主从复制,就无法实现快速的故障转移。

4. 数据分析和报表

可以用一个从服务器专门用来做数据分析、报表统计、数据挖掘等操作,这些操作通常查询量很大,很消耗资源,如果在主服务器上执行,会影响主服务器的性能。放在从服务器上执行,就不会影响主服务器,而且从服务器的数据和主服务器是一致的,分析结果也是准确的。

5. 数据分发

可以将主服务器的数据复制到多个从服务器,分布在不同的地域,供不同的业务使用,实现数据的就近访问,提升访问速度。比如全国性的业务,可以在不同的地区部署从服务器,当地的用户读当地的从服务器,速度更快,体验更好。

总的来说,主从复制的作用非常多,是MySQL架构中不可或缺的一部分,不管是小项目还是大项目,都建议用主从复制,至少有一个从服务器做备份,保证数据安全。

三、主从复制的类型

MySQL主从复制有几种不同的类型,根据复制的方式和数据格式,可以分为以下几种:

1. 基于语句的复制(Statement-Based Replication,SBR)

这种复制方式,主服务器会将执行的SQL语句写入binlog,从服务器执行这些SQL语句,从而实现数据复制。优点是binlog文件小,传输快,而且便于审计,因为记录的是原始的SQL语句。缺点是有些SQL语句可能有不确定性,比如UUID()、NOW()、AUTO_INCREMENT等,在主服务器和从服务器上执行的结果可能不一样,导致数据不一致。还有一些复杂的SQL,比如存储过程、触发器,也可能有问题。

2. 基于行的复制(Row-Based Replication,RBR)

这种复制方式,主服务器会将数据行的变更写入binlog,记录的是哪一行数据被修改了,修改成了什么样子,从服务器直接应用这些行变更。优点是数据准确,不会有不确定性的问题,任何数据变更都能准确复制,包括存储过程、触发器等。缺点是binlog文件比较大,特别是批量更新的时候,会记录很多行的变更,传输慢,而且不便于审计,因为看不到原始的SQL语句。

3. 混合模式复制(Mixed-Based Replication,MBR)

这种复制方式,结合了上面两种方式的优点,一般情况下用基于语句的复制,当遇到有不确定性的SQL语句时,自动切换到基于行的复制。这样既保证了数据的准确性,又兼顾了binlog的大小和传输效率,是目前推荐使用的复制方式。

MySQL 5.7及以上版本,默认的binlog格式是ROW,也就是基于行的复制,因为这种方式最安全,数据最准确。当然,也可以根据自己的需求选择其他格式,但是一般推荐用ROW格式,或者MIXED格式。

除了按数据格式分类,主从复制还可以按拓扑结构分类,常见的有:

  • 一主一从:一个主服务器,一个从服务器,最简单的架构,适合小项目。
  • 一主多从:一个主服务器,多个从服务器,适合读多写少的场景,可以分担读压力。
  • 多主复制:多个主服务器,互相复制,适合多机房部署,但是配置复杂,容易有冲突,一般不推荐。
  • 级联复制:主服务器复制到一个从服务器,这个从服务器再复制到其他从服务器,也就是从服务器同时也是主服务器,适合从服务器很多的场景,可以减轻主服务器的压力。

初学者建议从一主一从开始,掌握了基本原理和配置之后,再尝试更复杂的架构。

四、主从复制的配置步骤

讲完了原理和类型,现在来讲讲具体怎么配置MySQL主从复制。以一主一从为例,MySQL版本5.7,操作系统Linux。

第一步:准备两台服务器

准备两台服务器,一台做主,一台做从,都安装好MySQL,版本最好一致,或者从服务器的版本不低于主服务器。两台服务器网络互通,主服务器的3306端口对从服务器开放。

假设主服务器IP是192.168.1.10,从服务器IP是192.168.1.20。

第二步:配置主服务器

编辑主服务器的MySQL配置文件my.cnf(一般在/etc/my.cnf或者/etc/mysql/my.cnf),在[mysqld]部分添加以下配置:

[mysqld]
# 服务器唯一ID,主从服务器不能重复
server-id = 1
# 开启二进制日志
log-bin = mysql-bin
# binlog格式,推荐ROW
binlog_format = ROW
# 需要复制的数据库,如果不配置就是复制所有数据库
# binlog-do-db = testdb
# 不需要复制的数据库
binlog-ignore-db = mysql
binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema

配置好之后,重启MySQL服务:service mysqld restart

然后登录MySQL,创建一个用于复制的用户,给从服务器使用:

CREATE USER 'repl'@'192.168.1.20' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.20';
FLUSH PRIVILEGES;

然后查看主服务器的binlog状态,记录下File和Position的值,后面配置从服务器的时候要用:

SHOW MASTER STATUS;

输出大概是这样的:

+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      154 |              | mysql            |
+------------------+----------+--------------+------------------+

记录下File是mysql-bin.000001,Position是154。

第三步:配置从服务器

编辑从服务器的MySQL配置文件my.cnf,在[mysqld]部分添加以下配置:

[mysqld]
# 服务器唯一ID,不能和主服务器重复
server-id = 2
# 开启中继日志
relay-log = relay-bin
# 从服务器只读,防止误写(超级用户还是可以写)
read_only = 1
# 复制的数据库,如果不配置就是复制所有
# replicate-do-db = testdb
# 不复制的数据库
replicate-ignore-db = mysql
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema

配置好之后,重启MySQL服务:service mysqld restart

然后登录从服务器的MySQL,配置主服务器的信息,开始复制:

CHANGE MASTER TO
MASTER_HOST='192.168.1.10',
MASTER_USER='repl',
MASTER_PASSWORD='repl_password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;

这里的MASTERLOGFILE和MASTERLOGPOS就是刚才在主服务器上查到的File和Position的值。

然后启动从服务器的复制:

START SLAVE;

然后查看从服务器的复制状态:

SHOW SLAVE STATUS\G

重点看这两个值:

  • SlaveIORunning: Yes:IO线程运行正常
  • SlaveSQLRunning: Yes:SQL线程运行正常

如果这两个都是Yes,说明主从复制配置成功了。如果有一个是No,或者有错误信息,就需要排查问题。

第四步:测试主从复制

配置成功之后,可以测试一下。在主服务器上创建一个数据库,创建一张表,插入一条数据,然后去从服务器上查看,看看数据是不是已经复制过来了。如果复制过来了,说明主从复制正常工作。

如果主服务器上已经有数据了,需要先把主服务器的数据导出,导入到从服务器,然后再配置复制,不然从服务器没有历史数据,只有配置之后的新数据。导出数据可以用mysqldump,注意要加--master-data参数,记录binlog的位置,导入到从服务器之后,直接用这个位置配置复制就行。

五、常见问题和排查方法

主从复制配置过程中,经常会遇到各种问题,这里总结几个常见的问题和排查方法。

1. SlaveIORunning是No

这说明IO线程有问题,一般是连接主服务器失败,常见的原因有:

  • 主服务器IP、端口、用户名、密码配置错误
  • 从服务器网络不通,连不上主服务器
  • 主服务器的防火墙没有开放3306端口
  • 复制用户没有权限,或者IP限制不对
  • 主服务器的binlog文件不存在,或者位置不对

排查方法:先在从服务器上用mysql命令行连接主服务器,看看能不能连上,用户名密码对不对,权限够不够。如果连不上,检查网络、防火墙、端口。如果能连上,检查CHANGE MASTER TO的配置对不对,特别是MASTERLOGFILE和MASTERLOGPOS是不是和主服务器的一致。

2. SlaveSQLRunning是No

这说明SQL线程有问题,一般是执行中继日志的时候出错了,常见的原因有:

  • 主从数据不一致,主服务器上有的数据从服务器没有,或者反过来
  • 从服务器上有人手动写了数据,和主服务器复制过来的数据冲突
  • 主键冲突,重复插入
  • 表结构不一致,主服务器上的表和从服务器上的表结构不一样
  • 执行了不支持的SQL语句

排查方法:看SHOW SLAVE STATUS里的Last_Error信息,会告诉你具体是什么错误,在哪个文件哪个位置出错了。根据错误信息去排查,一般是数据不一致导致的。如果错误不严重,可以跳过这个错误,继续复制:

STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;

但是这个方法只是跳过错误,不能解决根本问题,如果数据不一致,后面还会出错。最好的方法是重新配置主从复制,把主服务器的数据重新导出导入到从服务器,保证数据一致。

3. 主从延迟大

这是很常见的问题,从服务器的数据比主服务器慢很多,常见的原因有:

  • 主服务器写入量太大,从服务器跟不上
  • 从服务器性能差,CPU、内存、磁盘IO不够
  • 网络带宽不够,binlog传输慢
  • 从服务器上有大量的查询,占用了资源,影响了SQL线程的执行
  • 大事务,主服务器上执行了一个很大的事务,从服务器执行的时候需要很长时间
  • 表没有主键,基于行的复制的时候,从服务器更新数据需要全表扫描,很慢

排查和解决方法:

  • 优化从服务器的性能,提升硬件配置
  • 减少从服务器上的查询,或者加更多的从服务器分担读压力
  • 优化网络,保证主从服务器之间的带宽
  • 避免大事务,把大事务拆分成小事务
  • 确保所有表都有主键,这对基于行的复制很重要
  • 用并行复制,MySQL 5.7支持基于组的并行复制,可以提升复制速度

4. 主服务器宕机了怎么办

如果主服务器宕机了,需要把从服务器提升为主服务器,继续提供服务。步骤是:

  1. 确认从服务器已经把所有的中继日志都执行完了,数据是最新的
  2. 在从服务器上执行STOP SLAVE,然后RESET MASTER,清除从服务器的复制状态
  3. 修改应用的数据库连接,指向新的主服务器
  4. 如果原来的主服务器修好了,可以把它改成新的主服务器的从服务器,继续复制

当然,手动故障转移比较麻烦,而且需要时间,生产环境建议用自动故障转移工具,比如MHA、Orchestrator等,可以自动检测主服务器故障,自动提升从服务器为主,自动切换,大大提升可用性。

六、最佳实践和注意事项

最后,总结一些主从复制的最佳实践和注意事项,帮助大家用好主从复制。

1. 主从服务器版本尽量一致

主从服务器的MySQL版本最好一致,或者从服务器的版本不低于主服务器。如果版本差太多,可能会有兼容性问题,导致复制失败。

2. 所有表都要有主键

特别是用基于行的复制的时候,表一定要有主键,不然从服务器更新数据的时候需要全表扫描,性能很差,延迟会很大。而且没有主键的表,在主从切换的时候也容易出问题。

3. 从服务器设置read_only

从服务器一定要设置read_only=1,防止普通用户误写数据,导致主从数据不一致。当然,超级用户还是可以写的,所以也要注意不要在从服务器上用超级用户写数据。

4. 定期检查主从状态

要定期检查主从复制的状态,看看IO线程和SQL线程是不是正常,有没有延迟,有没有错误。可以写个监控脚本,自动检查,出问题了及时告警,不要等数据不一致很久了才发现。

5. 不要在从服务器上手动写数据

除非是特殊情况,否则不要在从服务器上手动写数据,因为这样会导致主从数据不一致,后面复制的时候很容易出错,而且很难排查。如果需要写数据,在主服务器上写,然后复制到从服务器。

6. 备份要定期做

主从复制不是备份的替代品,虽然从服务器有一份数据,但是还是要定期做物理备份或者逻辑备份,因为主从复制只能复制数据变更,如果主服务器上误删了数据,从服务器上也会被删掉。所以定期备份还是很有必要的,备份是数据安全的最后一道防线。

7. 读写分离要注意延迟

用读写分离的时候,要注意主从延迟的问题,刚写入主服务器的数据,可能还没复制到从服务器,这时候去从服务器查询,可能查不到。对于一致性要求高的场景,比如刚注册完马上登录,刚下单马上查订单,这些读操作应该走主服务器,或者等复制完成了再查。

8. 从服务器不要太多

一主多从的架构,从服务器不要太多,一般不要超过5个,因为每个从服务器都要从主服务器拉取binlog,从服务器太多了,主服务器的网络和IO压力会很大,影响主服务器的性能。如果需要更多的从服务器,可以用级联复制的方式,减轻主服务器的压力。

七、写在最后

MySQL主从复制入门指南:从零开始学习。

以上就是MySQL主从复制的入门指南,从原理、作用、类型,到具体的配置步骤、常见问题、最佳实践,都做了比较详细的介绍。希望这篇文章能帮到想学习MySQL主从复制的朋友,让大家从零开始,快速掌握主从复制的配置和使用。

MySQL主从复制是MySQL高可用架构的基础,也是每个后端开发者和运维人员必须掌握的技能。虽然现在有很多云数据库,自带主从复制、高可用、自动备份等功能,不用我们自己配置,但是了解主从复制的原理和使用,还是很有必要的,能帮助我们更好地理解数据库架构,更好地使用和优化数据库。

当然,这篇文章只是入门指南,讲的都是基础的内容,主从复制还有很多深入的内容,比如并行复制、半同步复制、GTID、多源复制、组复制等等,这些都需要大家在实际工作中继续学习和实践。技术是学无止境的,希望大家都能保持学习的热情,不断提升自己。

最后用一句话结尾:"主从复制不是万能的,但是没有主从复制是万万不能的。掌握好主从复制,给你的数据上一份保险。"

祝大家都能配置好自己的MySQL主从复制,数据库稳定运行,数据永不丢失!