双主模式的主动复制在真实环境中应该是比较少的,虽然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。
至此测试完成!