MySQL主从复制详解

目录

  • 1 MySQL主从复制原理
  • 2 MySQL主从复制原理图
  • 3 MySQL主从复制小结
  • 4 MySQL多实例主从复制
  • 5 MySQL主从复制步骤小结
  • 6 快速添加MySQL从库
  • 7 MySQL主从复制故障解决

1 MySQL主从复制原理

1、MySQL的主从复制是一个异步的复制过程(虽然一般情况下感觉是实时的),数据将从一个MySQL数据库(我们称之为Master)复制到另一个MySQL数据库(我们称之为Slave),在Master与Salve之间实现整个主从复制的过程是由三个线程参与完成的。其中有两个线程(SQL线程IO线程)在Slave端,另外一个线程(I/O线程)在Master端。
2、要实现MySQL的主从复制,首先必须打开Master端的binlog记录功能,否则就无法实现。因为整个复制过程实际上就是Slave从Master端获取binlog日志,然后再在Slave上以相同顺序执行获取的binlog日志中所记录的各种SQL操作。注意binlog日志只记录增删改(不记录查询语句)
3、从库IO在第一次把信息放入到relay中后会触发SQL线程,然后后边就交给SQL线程来处理,把binlog文件中的SQL语句解析出来后变成SQL语句放入数据库中

2 MySQL主从复制原理图

3 MySQL主从复制小结

1)主从复制是异步的逻辑的SQL语句级的复制。
2)复制时,主库有一个I/O线程,从库有两个线程,I/O和SQL线程
3)实现主从复制的必要条件是主库要开启记录binlog功能
4)作为复制的所有MySQL节点的server-id都不能相同(0)
5)binlog文件只记录对数据库有更改的SQL语句(来自主数据库内容的变更,不记录任何查询(select,show)语句。

主从复制条件
1)主库开启binlog功能(从库除非做双向复制)
2)主库建立同步账号
3)从库配置master.info(CHANGE MASTER TO …来实现)
4)复制开关:start slave

需要了解一下概念
1)3线程,主库(IO),从库IO和SQL,及作用
2)master.info作用
3)relay-log作用
4)异步复制和同步复制的区别
5)binlog作用

4 MySQL多实例主从复制

主库:

# 1、查看binlog功能是否开启
[root@db02 ~]# grep log-bin /data/{3306,3307}/my.cnf
/data/3306/my.cnf:log-bin = /data/3306/mysql-bin
/data/3307/my.cnf:log-bin = /data/3307/mysql-bin

# 2、查看监听端口及server-id是否一样
[root@db02 ~]# netstat -lntup |grep 330*
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      47293/mysqld
tcp        0      0 0.0.0.0:3307                0.0.0.0:*                   LISTEN      5804/mysqld
[root@db02 ~]# grep server-id /data/{3306,3307,3308}/my.cnf
/data/3306/my.cnf:server-id = 1
/data/3307/my.cnf:server-id = 3
/data/3308/my.cnf:server-id = 8

# 3、登录3306主数据库,授权3307 slave登录用户
mysql> grant replication slave on *.* to rep@'172.16.1.%' identified by '123456';
Query OK, 0 rows affected (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> select user,host from mysql.user;
+---------+------------+
| user    | host       |
+---------+------------+
| root    | 127.0.0.1  |
| rep     | 172.16.1.% |
| oldboy2 | localhost  |
| root    | localhost  |
| test    | localhost  |
| test2   | localhost  |
+---------+------------+
6 rows in set (0.00 sec)

mysql> show grants for rep@'172.16.1.%';
+-------------------------------------------------------------------------------------------------------------------------+
| Grants for [email protected].%                                                                                               |
+-------------------------------------------------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO 'rep'@'172.16.1.%' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |
+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

# 4、锁表,查看binlog文件及位置点
mysql> flush table with read lock;
Query OK, 0 rows affected (0.00 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 |     2892 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

# 5、新开窗口全备数据(下边可能会报错,由于mysql5.5之后添加了新特性,实验环境可以不锁表操作)
[root@db02 ~]# mysqldump -uroot -p123456 -A -B --events -S /data/3306/mysql.sock |gzip >/server/backup/req_$(date +%F).sql.gz
mysqldump: Got error: 1142: SELECT,LOCK TABL command denied to user 'root'@'localhost' for table 'cond_instances' when using LOCK TABLES
[root@db02 backup]# ll
total 152
-rw-r--r-- 1 root root 152756 Jun  9 14:02 req_2018-06-09.sql.gz

# 6、解锁
mysql> unlock table;
Query OK, 0 rows affected (0.00 sec)

从库:

# 确保server-id不同
[root@db02 ~]# grep log-bin /data/{3306,3307}/my.cnf
/data/3306/my.cnf:log-bin = /data/3306/mysql-bin
/data/3307/my.cnf:log-bin = /data/3307/mysql-bin

# 开启服务
/data/3307/mysql start

# 把主库的全备导入到从库
[root@db02 backup]# gzip -d /server/backup/req_2018-06-09.sql.gz
[root@db02 backup]# ls
req_2018-06-09.sql
[root@db02 backup]# mysql -uroot -p123456 -S /data/3307/mysql.sock 
[root@db02 backup]# mysql -uroot -p123456 -S /data/3307/mysql.sock

# 找位置点,配置master.info文件
# (若change master内容有误,不要修改master.info文件,直接reset slave all)
CHANGE MASTER TO
MASTER_HOST='172.16.1.52',
MASTER_PORT=3306,
MASTER_USER='rep',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000010',
MASTER_LOG_POS=2892;
[root@db02 ~]# ll /data/3307/data/master.info
-rw-rw---- 1 mysql mysql 77 Jun  9 14:15 /data/3307/data/master.info
[root@db02 ~]# cat /data/3307/data/master.info
18
mysql-bin.000010
2892
172.16.1.52
rep
123456
3306
60
0





0
1800.000

0

# 开启从库开关
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.1.52
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000010
          Read_Master_Log_Pos: 3194
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 555
        Relay_Master_Log_File: mysql-bin.000010
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB: mysql
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 3194
              Relay_Log_Space: 705
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
1 row in set (0.00 sec)

mysql>

测试:

# 主库创建数据库
mysql> create database rsq123;
Query OK, 1 row affected (0.00 sec)

# 从库查看
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| oldboy             |
| oldgirl            |
| performance_schema |
| rsq123             |
| test               |
+--------------------+
7 rows in set (0.00 sec)

5 MySQL主从复制步骤小结

和上边实验不同步,此为后来添加的
主库:

1、开启binlog功能
2、确保所有实例server-id不同
3、授权复制的用户rep(grant replication slave on . to rep@’172.16.1.%’ identified by ‘123456’;)
4、锁表(flush table with read lock;),查看binlog文件及位置点(show master status;/–master-data=2)
5、新开窗口导出全备(mysqldump -uroot -p123456 -A -B –events -S /data/3306/mysql.sock |gzip >/server/backup/req_$(date +%F).sql.gz)
6、解锁,开放用户写入功能(unlock table)

从库

1、确保所有实例server-id不同
2、把主库的全备导入到从库
3、找位置点,配置master.info
CHANGE MASTER TO
MASTER_HOST=’172.16.1.52’,
MASTER_PORT=3306,
MASTER_USER=’rep’,
MASTER_PASSWORD=’123456’,
MASTER_LOG_FILE=’mysql-bin.000010’,
MASTER_LOG_POS=2892;
4、start slave;show slave status\G
若出现slave中的两线程状态为YES,基本上就成功了

6 快速添加MySQL从库

# 先备份前一个从库数据,用--master-data=2参数,可以省去锁表的步骤
mysqldump -uroot -p123456 -S /data/3306/mysql.sock -A -B -R -F -x --master-data=2 --events|gzip >/server/backup/rep3308_$(date +%F).sql.gz

# 解压后导入新的从库
gzip -d /server/backup/rep3308_2018-06-09.sql.gz
mysql -uroot -p123456 -S /data/3308/mysql.sock 06-09.sql

# 查找解压后的sql文件,查找CHANGE,复制出来
vim /server/backup/rep3308_2018-06-09.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000011', MASTER_LOG_POS=107;

# 分别执行两条CHANGE
CHANGE MASTER TO
MASTER_HOST='172.16.1.52',
MASTER_PORT=3306,
MASTER_USER='rep',
MASTER_PASSWORD='123456';

CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000011', MASTER_LOG_POS=107;

# 开启slave
start slave;
show slave status\G

# 完事

7 MySQL主从复制故障解决

# 出现SQL线程问题
mysql> show slave status\G
... ...
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
... ...
               Last_SQL_Errno: 1008
               Last_SQL_Error: Error 'Can't drop database 'rsq'; database doesn't exist' on query. Default database: 'rsq'. Query: 'drop database rsq'
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1

stop slave;
set global sql_slave_skip_counter = 1;   # 将同步指针向下移动一个,如果多次不同步,可以重复操作,增大指针值都可以。
start slave;

# 方法二:把Last_SQL_Errno值给提前加入配置文件中,这样再有类似错误值的报错就直接忽略了
grep slave-skip /data/3306/my.cnf
slave-skip-errors = 1032,1062,1007

Last_SQL_Errno错误代码集

其他可能引起复制故障的问题:

  • 1、MySQL自身的原因及人为重复插入数据。
  • 2、不同的数据库版本会引起不同步,低版本到高版本可以,但是高版本往往不能往低版本复制
  • 3、MySQL的运行错误或者程序BUG
  • 4、binlog记录模式,例如:row level模式就比默认的语句要好

你可能感兴趣的:(DataBase)