基于docker的MySQL主从复制(replication)
MySQL复制技术可以异步地将主数据库的数据同步到从数据库。根据设置可以复制所有数据库、指定数据库甚至可以指定表。本文的主要内容是怎样用docker从零开始搭建mysql主从复制环境,支持binary logging方式和GTIDs方式。
MySQL 5.7支持多种复制方法。传统的方法是master使用binary logging,slave复制并重放日志中的事件。另一种方法是利用GTIDs(global transaction identifiers)将所有未执行的事务在slave重放。
binary logging方式
接下来先用传统的方法试一下。使用MySQL 5.7镜像,将/etc/mysql/conf.d/
复制到主机,然后修改配置:
master的配置在my.cnf
文件中是这样的,改完后另存为/vagrant/mysql/mymaster.cnf
:
slave的配置就更简单了,改完后另存为/vagrant/mysql/myslave.cnf
:
slave没有必要非得用binary logging,但是如果用了,除了binary logging带来的好处以外,还能使这个slave成为其他slave的master。现在我们重新启动mysql master和slave:
在master创建一个复制用的用户:
|
|
在slave用新创建的用户连接master(记得把MASTER_HOST改为自己的主机IP):
|
|
如果一切正常,应该在Last_Error
中能看到Can't create database 'mysql'
的错误。这是因为slave也是像master一样正常地启动,mysql数据库已经被创建了,所以不能再将master的mysql数据库同步过来。有4种解决办法:
通过在slave上运行SQL来跳过这个复制操作的方式来实现。在slave上运行:
1234STOP SLAVE;SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;START SLAVE;SHOW SLAVE STATUS\G不出意外的话,上面的错误应该已经换成了其他错误(例如:
Duplicate entry 'row_evaluate_cost' for key 'PRIMARY'
),都是跟mysql这个数据库有关。反复运行上面的SQL直至错误消失。通过在slave上面配置log文件名及位置的方式来实现。在master上运行:
1docker exec -it master mysql -uroot -p12345612FLUSH TABLES WITH READ LOCK; --防止有人对master做更新操作使Position持续变化,先锁表SHOW MASTER STATUS\G可以看到
File: mysql-bin.000003
和Position: 154
这样的行。删掉这个旧的slave并重新启动一个新的容器,然后运行:1234567docker rm -f slavedocker run -d \--name=slave \-e MYSQL_ROOT_PASSWORD=123456 \-v /vagrant/mysql/myslave.cnf:/etc/mysql/my.cnf \mysql:5.7docker exec -it slave mysql -uroot -p1234561234STOP SLAVE;CHANGE MASTER TO MASTER_HOST='192.168.33.32', MASTER_USER='repl', MASTER_PASSWORD='123456', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154;START SLAVE;SHOW SLAVE STATUS\G我们将会看到
Slave_IO_Running: Yes
和Slave_SQL_Running: Yes
。这两项说明我们的slave已经成功启动了。如果先前锁了master的表,记得在master上运行UNLOCK TABLES;
来恢复。通过不记录
mysql
数据库binary logging的方式来实现。既然mysql
不在binary logging里,那它也无法被同步到slave上。在/vagrant/mysql/mymaster.cnf
里增加一个参数,如果有多个数据库,可以复制多行:1binlog-ignore-db=mysql删除master和slave容器然后再重新创建之:
12345678910111213docker rm -f masterdocker rm -f slavedocker run -d \--net=host \--name=master \-e MYSQL_ROOT_PASSWORD=123456 \-v /vagrant/mysql/mymaster.cnf:/etc/mysql/my.cnf \mysql:5.7docker run -d \--name=slave \-e MYSQL_ROOT_PASSWORD=123456 \-v /vagrant/mysql/myslave.cnf:/etc/mysql/my.cnf \mysql:5.7然后根据上文所述在master创建一个复制用的用户并在slave用新创建的用户连接master,最后观察
Slave_IO_Running
和Slave_SQL_Running
。通过不复制
mysql
数据库binary logging的方式来实现。这种方式很类似上面一种方法,只不过配置在slave端而非master端而已。在/vagrant/mysql/myslave.cnf
里增加一个参数,删除master和slave容器然后再重新创建之:1replicate-ignore-db=mysql其余操作同方法3。
既然slave已经成功启动了,我们便可以测试一下。看看在master上创建一个新数据库是否能同步到slave上:
GTIDs方式
下面介绍一下GTIDs方式的主从复制方法。需要修改/vagrant/mysql/mymaster.cnf
:
还需要修改/vagrant/mysql/myslave.cnf
(MySQL 5.7.4及之前的版本还需要开启log-bin):
启动容器,创建复制的用户都和上面一样,在slave增加MASTER_AUTO_POSITION
参数来连接master(记得把MASTER_HOST改为自己的主机IP):
|
|
搞定!这样就不需要用到MASTER_LOG_FILE
和MASTER_LOG_POS
了,省事儿啊。在START SLAVE
之前master的其它更新也都会被同步到slave。
其他技巧
最后再介绍一些实用技巧:
- 如果master已经有数据了,怎么新增slave:可以先把master的数据导入到slave,再启动slave。具体可以参考这里。
- 如果已经有主从复制了,怎么增加slave:思路同上,不过不需要使用master的数据,直接用已有的slave数据就可以了。不需要停止master,新slave使用新的
server-id
。具体可以参考这里。 slave设置只读操作:在
/vagrant/mysql/myslave.cnf
里增加参数即可。12read-only=1 # 除非有SUPER权限,否则只读super-read-only=1 # SUPER权限也是只读前面介绍的都是主从,如果需要slave也能同步到master就要设置主主复制:也就是说反过来再做一遍。
- 当slave比较多得时候,master的负载可能会成为问题。可以用主从多级复制:以slave为master来再引入新的slave。