17.1 MySQL主从介绍
MySQL主从又叫做Replication、AB复制。简单讲就是A和B两台机器做主从后,在A上写数据,另外一台B也会跟着写数据,两者数据实时同步的。也就是说,当你在A机器写入一个表,再次查看B机器也会同步一个表。
MySQL主从是基于binlog的,主上须开启binlog才能进行主从。
主从过程大致有3个步骤:
- 主将更改操作记录到binlog里。
- 从将主的binlog事件(sql语句)同步到从本机上并记录在relaylog里。
- 从根据relaylog里面的sql语句按顺序执行 主上有一个log dump线程,用来和从的I/O线程传递binlog 从上有两个线程,其中I/O线程用来同步主的binlog并生成relaylog,另外一个SQL线程用来把relaylog里面的sql语句落地。
主从原理图:
Master:主mysql Slave:备mysql
当有数据写进主mysql中的时候,就出自动生成一个log dump thread,记录到如上讲的binlog中,然后从数据库就会和主mysql有个线程进行交互,从服务器就会读取binlog日志到Slave,然后再次生成一个relay log(中继日志),然后再次和从服务器中的SQL thread线程进程交互执行。
简单的说,就是 从服务器把主服务器上的binlog弄到自己服务器上去,然后根据这个binlog生成自己的relay日志,根据这个relay日志进行更改数据库,最终达到两边数据一致。
主从的作用;
1.数据的备份;
假如A服务器(主)突然硬件问题,宕机了。但是线上跑了很多重要的数据,我们完全可以使用B服务器(从)直接顶上。
2. 负载均衡;
我们线上的所有数据均是从A上面读取,由于压力比较大,我们可以使用B服务器分享一部分用户到自己的服务器,但是只是可以读,不可以写入数据。看图可知,数据的读取是有方向性的,如果首先从B上读取那就混乱了,数据肯定不一致了。就会导致主从失败!
17.2 准备工作
因为是实验环境,直接准备了一台虚拟机,装好MYSQL后,再克隆一台虚拟机,避免其他变量影响。
17.3 配置主
编辑配置文件添加如下参数:
[root@localhost ~]# vim /etc/my.cnf
……
server-id=180
#自定义
log_bin=yuntai01
#自定义定log前缀
编辑完成后重启mysql服务:
[root@localhost ~]# /etc/init.d/mysqld restart
Shutting down MySQL...... SUCCESS!
Starting MySQL.................. SUCCESS!
查看mysql库文件:
[root@localhost ~]# ls -lt /data/mysql/
总用量 110684
-rw-rw----. 1 mysql mysql 50331648 12月 14 15:30 ib_logfile0
-rw-rw----. 1 mysql mysql 12582912 12月 14 15:30 ibdata1
-rw-rw----. 1 mysql mysql 56288 12月 14 15:30 localhost.localdomain.err
-rw-rw----. 1 mysql mysql 5 12月 14 15:30 localhost.localdomain.pid
drwx------. 2 mysql mysql 4096 12月 12 18:13 zrlog
-rw-rw----. 1 mysql mysql 143 12月 12 17:45 yuntai.000001 #重要
-rw-rw----. 1 mysql mysql 16 12月 12 12:07 yuntai.index #重要
-rw-rw----. 1 mysql mysql 56 11月 7 17:27 auto.cnf
drwx------. 2 mysql mysql 4096 11月 7 17:24 mysql
drwx------. 2 mysql mysql 4096 11月 7 17:24 performance_schema
-rw-rw----. 1 mysql mysql 50331648 11月 7 17:24 ib_logfile1
drwx------. 2 mysql mysql 6 11月 7 17:23 test
说明: 重启后生成两个前缀为yuntai01的二进制文件是实现主从的重要文件。
新建一个数据库为试验做准备:
备份一个数据库:
[root@localhost ~]# mysqldump -uroot -p123456 zrlog > /tmp/zrlog.sql
Warning: Using a password on the command line interface can be insecure.
新建几个数据库:
[root@localhost ~]# mysql -uroot -p123456
mysql> create database yuntai01;
Query OK, 1 row affected (0.00 sec)
mysql> create database yuntai02;
Query OK, 1 row affected (0.00 sec)
mysql> quit
Bye
将备份的数据恢复到新建的数据库中:
[root@localhost mysql]# mysql -uroot -p123456 yuntaitest < /tmp/test.sql
创建一个用于同步数据的用户:
[root@localhost mysql]# mysql -uroot -p123456
Welcome to the MySQL monitor.
mysql> grant replication slave on *.* to 'repl'@'192.168.2.181' identified by '123456';
Query OK, 0 rows affected (0.01 sec)
#IP 192.168.2.181 为“从”的IP
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.12 sec)
#锁定数据表(目的是暂时使其不能继续写,保持现有状态用于同步)
mysql> show master status;
+-----------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| yuntai01.000001 | 542 | | | |
+-----------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
#记住file和position(设置主从同步时会使用)
mysql> quit
Bye
查看当前的数据库,准备备份
[root@localhost ~]# cd /data/mysql
[root@localhost mysql]# ls
auto.cnf ib_logfile0 localhost.localdomain.err mysql test yuntai01 yuntai01.index yuntai.index
ibdata1 ib_logfile1 localhost.localdomain.pid performance_schema yuntai.000001 yuntai01.000001 yuntai02 zrlog
#我们的数据库:yuntai01 yuntai02 zrlog,我们把这几个数据库全部备份并同步。
备份主库中所有数据库:
[root@localhost mysql]# mysqldump -uroot -p123456 zrlog > /tmp/zrlog.sql
[root@localhost mysql]# mysqldump -uroot -p123456 yuntai01 > /tmp/yuntai01.sql
[root@localhost mysql]# mysqldump -uroot -p123456 yuntai02 > /tmp/yuntai02.sql
数据对比
[root@localhost mysql]# ls -lt /tmp/*.sql
-rw-r--r--. 1 root root 1262 12月 14 15:54 /tmp/yuntai02.sql
-rw-r--r--. 1 root root 1262 12月 14 15:54 /tmp/yuntai01.sql
-rw-r--r--. 1 root root 10072 12月 14 15:53 /tmp/zrlog.sql
[root@localhost mysql]# ls -lt
总用量 110692
......
drwx------. 2 mysql mysql 4096 12月 14 15:50 zrlog
drwx------. 2 mysql mysql 20 12月 14 15:38 yuntai02
drwx------. 2 mysql mysql 20 12月 14 15:38 yuntai01
......
17.4 配置从
编辑从MySQL的配置文件添加如下参数:
配置server-id=181,要求和主不一样。bin_log就不需要配置了,二进制文件只需要在主服务器上面配置即可。
[root@localhost ~]# vim /etc/my.cnf
……
server-id=181
#添加到最后
重启配置文件
[root@localhost ~]# /etc/init.d/mysqld restart
Shutting down MySQL...... SUCCESS!
Starting MySQL.............................. SUCCESS!
将主中备份的数据发送到从中
[root@localhost ~]# scp 192.168.2.180:/tmp/*.sql /tmp/ ##此IP为MySQL主的IP地址
The authenticity of host '192.168.2.180 (192.168.2.180)' can't be established.
ECDSA key fingerprint is 17:2a:d4:3f:ff:02:39:05:e4:c2:02:44:73:5e:88:64.
Are you sure you want to continue connecting (yes/no)? yes
#输入yes
Warning: Permanently added '192.168.2.180' (ECDSA) to the list of known hosts.
[email protected]'s password:
#输入180机器的root密码
yuntai01.sql 100% 1262 1.2KB/s 00:00
yuntai02.sql 100% 1262 1.2KB/s 00:00
zrlog.sql 100% 10KB 9.8KB/s 00:00
配置MySQL
配置MySQL环境
[root@localhost ~]# export PATH=$PATH:/usr/local/mysql/bin/
#这是将命令路径暂时加入环境变量,系但是统重启后该变量会失效,最好将其加入环境变量配置文件
[root@localhost ~]# vim /etc/profile
…… #添加
export PATH=$PATH:/usr/local/mysql/bin/
[root@localhost ~]# source /etc/profile //刷新刚刚的配置文件,否则不生效
制定账户,设置密码
[root@localhost ~]# mysqladmin -uroot password '123456'
创建对应的MySQL库
[root@localhost ~]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.6.35 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database yuntai01;
Query OK, 1 row affected (0.00 sec)
mysql> create database yuntai02;
Query OK, 1 row affected (0.00 sec)
mysql> create database zrlog;
Query OK, 1 row affected (0.00 sec)
mysql> quit
Bye
恢复数据库
[root@localhost ~]# mysql -uroot -p123456 zrlog< /tmp/zrlog.sql
[root@localhost ~]# mysql -uroot -p123456 yuntai01< /tmp/yuntai01.sql
[root@localhost ~]# mysql -uroot -p123456 yuntai02< /tmp/yuntai02.sql
[root@localhost mysql]# mysql -uroot -p123456
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| yuntai01 |
| yuntai02 |
| zrlog |
+--------------------+
7 rows in set (0.08 sec)
配置从服务器
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
重要步骤
mysql> change master to master_host='192.168.2.180', master_user='repl', master_password='123456', master_log_file='yuntai01.000001', master_log_pos=542;
Query OK, 0 rows affected, 2 warnings (0.06 sec)
# master_host:主MySQL IP、master_user:主MySQL上交互用的用户名
# master_log_file:主服务器上面show master status的文件名、master_log_pos:show master status的position值
检测主从是否建立成功
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: 192.168.2.180
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: yuntai01.000002
Read_Master_Log_Pos: 120
Relay_Log_File: localhost-relay-bin.000005
Relay_Log_Pos: 282
Relay_Master_Log_File: yuntai01.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
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: 120
Relay_Log_Space: 11178
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: 180
Master_UUID: d14c4924-c39d-11e7-93c6-000c2914f61b
Master_Info_File: /data/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
1 row in set (0.00 sec)
mysql> show slave status\G 看是否有
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
还需关注
Seconds_Behind_Master: 0 //为主从延迟的时间
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
配置中出现过的错误
Slave_IO_Running: No
Slave_SQL_Running: Yes
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 1593
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
#报错中也有显示
主要原因是5.6中引入了UUID的概念,各个mysql service的uuid要保证不能一样。
[root@localhost ~]# cd /data/mysql/
[root@localhost mysql]# ls
auto.cnf ib_logfile0 localhost.localdomain.err localhost-relay-bin.000002 master.info performance_schema test yuntai02
ibdata1 ib_logfile1 localhost.localdomain.pid localhost-relay-bin.index mysql relay-log.info yuntai01 zrlog
[root@localhost mysql]# vim auto.cnf
[auto]
server-uuid=d14c4924-c39d-11e7-93c6-000c2914f68b #随意改动2个字母或数字后保存
[root@localhost mysql]# /etc/init.d/mysqld restart
到主服务器解开锁表
[root@localhost mysql]# mysql -uroot -p123456
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
到这里,MySQL的主从配置就完成了。
17.5 测试主从同步
参数介绍
主服务器:
binlog-do-db= //仅同步指定的库
binlog-ignore-db= //忽略指定的库
从服务器:
replicate_do_db= //同步指定的库
replicate_ignore_db= //忽略指定的库
replicate_do_table= //同步指定的表
replicate_ignore_table= //忽略指定的表
#建议只使用下面2个语句,使用参数“replicate_wild_”,使匹配更精确,提升使用性能。
replicate_wild_do_table= 如yuntai.%,支持通配符
replicate_wild_ignore_table=
#如果想定义的话,将上面语句写入Mysql的my.cnf配置文件中
- 假如在主服务器上面有很多数据库,但是我只想同步yuntai01这个库
# vim /etc/my.cnf
......
binlog-do-db=yuntai01
要是多个的话就用英文状态下的逗号去分隔;
- 或者有时候数据库比较多,我就一个yuntai02库不需要同步
# vim /etc/my.cnf
......
binlog-ignore-db=yuntai02
- 有时候我们需要在同步的时候忽略一些临时的表,这些表对我们的用处不大。我们可以在从服务器上编辑
# vim /etc/my.cnf
......
replicate_wild_do_table=yuntai01.%,yuntai02.%
开始测试
主操作
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| yuntai01 |
| yuntai02 |
| zrlog |
+--------------------+
7 rows in set (0.00 sec)
mysql> use yuntai01
Database changed
mysql> show tables;
Empty set (0.00 sec)
从操作,查看相同数据情况
同上,略
mysql> use yuntai01
Database changed
mysql> show tables;
Empty set (0.00 sec)
主上,尝试往yuntai01库导入内容
mysql> quit
Bye
[root@localhost mysql]# mysql -uroot -p123456 yuntai01 < /tmp/zrlog.sql
Warning: Using a password on the command line interface can be insecure.
[root@localhost mysql]# mysql -uroot -p123456
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9398
Server version: 5.6.35-log MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use yuntai01;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+--------------------+
| Tables_in_yuntai01 |
+--------------------+
| comment |
| link |
| log |
| lognav |
| plugin |
| tag |
| type |
| user |
| website |
+--------------------+
9 rows in set (0.00 sec)
mysql> select count(*) plugin;
+--------+
| plugin |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
再次去从上查看
同上,略
mysql> select count(*) plugin;
+--------+
| plugin |
+--------+
| 1 |
+--------+
1 row in set (0.01 sec)
主上删除表格plugin
mysql> drop table plugin;
Query OK, 0 rows affected (0.00 sec)
从上查看表格plugin
mysql> show tables;
+--------------------+
| Tables_in_yuntai01 |
+--------------------+
| comment |
| link |
| log |
| lognav |
| tag |
| type |
| user |
| website |
+--------------------+
8 rows in set (0.00 sec)
plugin表格果然没有了!
表示测试成功,mysql的确同步了。
千万别在从server上面删除任何数据,一旦删除也就意味着数据不是一致的,主从就失败了!
如果主从这么失败了,如何再次恢复呢?
- 先把主server上面的数据与从server上面的数据保持一致,刚刚从server删除了什么数据,现在也需要把主server上面的数据也删除,为的就是数据一致!
- 首先主server上面操作
mysql> show master status;
+-----------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| yuntai01.000001 | 10863 | | | |
+-----------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
记住Position值
- 从server上操作使用新的Postion值
mysql> stop slave;
mysql> change master to master_host='192.168.2.180', master_user='repl', master_password='123456', master_log_file='yuntai01.000001', master_log_pos=10863;
- 再次启动从,查看状态
mysql> start slave;
mysql> show slave status\G
具体思路
- 保证数据一致性的前提下,如上操作,如果主表格还在写入导致的数据不符,在不影响业务的情况下,可以锁主表
- 实在是数据不一致的前提下,建议直接重新备份,然后再次导入,再次change master即可