双主模式的主动复制在真实环境中应该是比较少的,虽然mysql5.0之后增加了auto_increment_increment和auto_increment_offset选项的设置,解决了自增长主键的问题,不过允许向两台主为同时写入仍然比较危险。如果两台机器同时更改同张表上的同一笔数据,就会出现问题,更可怕的是这样的问题服务器并不会报错。这样的结构称之为主动模式的主主复制 。
被动模式下的主主复制就是在主动主主复制的前提下,让其中一台机器设为只读状态,如果其中有一台机器出现问题的话,可能快速的切换服务器;alter操作对数据库的影响比较大,可以通过暂停其中一台的备库复制线程,在另一台上做好alter后,交换角色后再开启备库的复制线程,这样可以对服务器的影响最小化。这样的环境应该是比较常见并且重要的拓扑结构。
下面做个测试:
环境说明 :
master1 server IP:172.17.61.131
master 2 server IP:172.17.61.132
mysql version: mysql-5.7.21-linux
测试目的: 对表进行alter操作,对数据库的影响最小化。
master1:
mysql> show create table test_emp\G
*************************** 1. row ***************************
Table: test_emp
Create Table: CREATE TABLE `test_emp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c1` int(10) NOT NULL DEFAULT '0',
`c2` int(10) unsigned DEFAULT NULL,
`c5` int(10) unsigned NOT NULL DEFAULT '0',
`c3` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`c4` varchar(90) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_c1` (`c1`),
KEY `idx_c2` (`c2`)
) ENGINE=InnoDB AUTO_INCREMENT=1100001 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
记住当前应到到master2的log_file和pos
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.61.132
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql_bin.000002
Read_Master_Log_Pos: 1163
Relay_Log_File: qht131-relay-bin.000003
Relay_Log_Pos: 1118
Relay_Master_Log_File: mysql_bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
。。。
Exec_Master_Log_Pos: 1163
Relay_Log_Space: 1326
Until_Condition: None
。。。
Master_Server_Id: 10001
Master_UUID: 744cfcde-3a9b-11e8-b299-000c2900d025
Master_Info_File: /u01/mysql/master.info
SQL_Delay: 0
。。。
1 row in set (0.00 sec)
关闭master1上面的复制进程,以免master2在later table时对master有影响:
mysql> stop slave;
Query OK, 0 rows affected (0.06 sec)
master2:
mysql> alter table test_emp change c4 c6 varchar(100);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table test_emp\G
*************************** 1. row ***************************
Table: test_emp
Create Table: CREATE TABLE `test_emp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c1` int(10) NOT NULL DEFAULT '0',
`c2` int(10) unsigned DEFAULT NULL,
`c5` int(10) unsigned NOT NULL DEFAULT '0',
`c3` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`c6` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_c1` (`c1`),
KEY `idx_c2` (`c2`)
) ENGINE=InnoDB AUTO_INCREMENT=1100001 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
表alter成功之后可以将应用直接切换到master2上面。
master1:
这里重新指定一下之前stop slave时的master_log_files和master_log_pos的位置,接着开启slave线程。
mysql> change master to
-> master_host='172.17.61.132',
-> master_user='repl',
-> master_password='repl',
-> master_log_file='mysql_bin.000002',
-> master_log_pos=1163;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show create table test_emp\G
*************************** 1. row ***************************
Table: test_emp
Create Table: CREATE TABLE `test_emp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c1` int(10) NOT NULL DEFAULT '0',
`c2` int(10) unsigned DEFAULT NULL,
`c5` int(10) unsigned NOT NULL DEFAULT '0',
`c3` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`c6` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_c1` (`c1`),
KEY `idx_c2` (`c2`)
) ENGINE=InnoDB AUTO_INCREMENT=1100001 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
master1 重新开始master2的日志应用线程后,master所做的alter操作已同步到master1了,这时可以将应用的连接恢复到master1。
至此测试完成!