MySQL主从复制
一、概念
MySQL主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
MySQL数据库的主从复制方案,是其自带的功能,MySQL数据库支持单向、双向、链式级联,等不同业务场景的复制。
一台MySQL服务器一旦启用二进制日志后,其作为主服务器(Master),它的数据库中所有操作都会以"事件"的方式记录在二进制日志中,其他数据库作为从服务器(Slave)通过一个I/O线程与主服务器保持通信,并监控Master的二进制日志文件的变化,如果发现Master二进制日志文件发生变化,则会把变化复制到自己的中继日志中,然后Slave的一个SQL线程会把相关的"事件"执行到自己的数据库中,以此实现从数据库和主数据库的一致性,也就实现了主从复制。
在生产环境中,MySQL主从复制都是异步的复制方式,即不是严格的实时复制,但是给用户的体验都是实时的。MySQL主从复制集群功能使得MySQL数据库支持大规模高并发读写成为可能,且有效的保护了服务器宕机的数据备份。
主从复制的逻辑有以下几种:
一主一从:单向主从同步模式,只能在Master端写入数据。
一主多从:提高系统的读性能。
双主复制:此架构可以在Master1或Master2进行数据写入,或者两端同时写入(特殊设置)。
多主一从(MySQL5.7开始支持)
级联复制
应用场景:
利用复制功能,当Master服务器出现问题时,我们可以人工的切换到从服务器继续提供服务,此时服务器的数据和宕机时的数据几乎完全一致。
复制功能也可用作数据备份,但是如果人为的执行drop,delete等语句删除,那么从库的备份功能也就失效了。
主从机制实现原理:
MySQL主从复制涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread、SQL thread)运行在从节点,如下图所示:
主库 binary log dump 线程:
当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送binlog内容到从库。对于每一个即将发送给从库的sql事件,此线程会将其锁住。一旦该事件被线程读取完之后,该锁会被释放,即使在该事件完全发送到从库之前,该锁也会被释放。
从库 I/O 线程:
当从节点执行"start slave"命令之后,从节点会创建一个I/O线程用来连接主节点,请求主节点发送binlog里面的更新记录到从节点上。I/O线程接收到主节点binlog dump线程发来的更新之后,保存在本地relay log中。
从库SQL线程:
SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。
对于每一个主从连接,都需要三个线程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 线程,而每个从节点都有自己的I/O线程,SQL线程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时I/O进程可以很快从主节点获取更新,尽管SQL线程还没有执行。如果在SQL线程执行之前从节点服务停止,至少I/O线程已经从主节点拉取到了最新的变更并且保存在本地relay log中,当服务再次起来之后,就可以完成数据的同步。
二、配置
master主库配置
# 查看数据库状态 service mysqld status # 停止运行mysql service mysqld stop # 修改配置文件 vim /etc/my.cnf # 修改内容 # 解释:server-id服务的唯一标识(主从之间都必须不同);log-bin启动二进制日志名称为mysql-bin [mysqld] server-id=1 log-bin=mysql-bin # 重新启动mysql service mysqld start
master主库添加从库账号
# 1、新建用于主从同步的用户pd,允许登录的从库是"10.0.0.0" mysql> create user "pd"@"192.168.1.105" identified by "123456"; # 2、如果提示密码太简单不复合策略加在前面加这句 mysql> set global validate_password_policy=0; # 给从库账号授权,说明给pd从库复制的权限,在"10.0.0.0"机器上复制 mysql> grant replication slave on *.* to "pd"@"192.168.1.105"; # 3、检查主库创建的复制账号 mysql> select user,host from mysql.user; # 检查授权账号的权限 mysql> show grants for "pd"@"192.168.1.105"; # 实现对主数据库锁表只读,防止数据写入,数据复制失败 mysql> flush table with read lock; # 4、检查主库的状态 mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000002 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) # File是二进制日志文件名,Position是日志开始的位置。后面从库会用到!!! # 5、锁表后,一定要单独再打开一个ssh窗口,导出数据库的所有数据 mysqldump -uroot -p --all-databases > /all.sql # 6、确保数据导出后,没有数据插入,完毕再查看主库状态 mysql> show master status; # 7、导出数据完毕后,解锁主库,恢复可写 mysql> unlock tables; # 8、将备份导出的数据sql至Slave数据库 scp /all.sql root@192.168.1.105:/all.sql
slave从库配置
# 1、设置server-id值并关闭binlog功能参数 # 数据库的server-id在主从复制体系内是唯一的,slave的server-id与主库以及其他从库不同,并且注释掉slave的binlog参数 # 2、修改slave的配置:vim /etc/my.cnf [mysqld] server-id=2 # 3、重启数据库 service mysqld restart # 4、检查slava从数据库的各项参数 mysql> show variables like "log_bin"; mysql> show variables like "server_id"; # 5、将master库的数据导入到slave库(注意sql文件的路径) 方法一: mysql>source /all.sql; 方法二: mysql -uroot -p < all.sql # 6、配置复制的参数,slave从库连接master主库的配置 mysql> change master to master_host="192.168.1.106", master_user="pd", master_password="123456", master_log_file="mysql-bin.000002", master_log_pos=154; # 7.启动从库的同步开关,测试主从复制的情况 mysql> start slave; # 8、查看复制状态 mysql> show slave status\G
检查主从复制是否成功,如下所示即为成功:
注意:
此时还未配置从库的只读模式,只需在slave服务器上配置/etc/my.cnf,加入read-only=true,并且在slave上创建普通用户,使用普通用户主从同步即可达到只读的效果;如果用root用户,无法达到readonly!!!
[mysqld] read-only=true