docker环境创建mysql主备复制模式,一主多从
前言
最近心血来潮,一直看网上文章说mysql读写分离,一主多从,从来没尝试过,考虑到后续服务慢慢容器化,本次我们用docker环境搭建。本文采用windows版本docker。
准备镜像
查看官方镜像
docker search mysql
拉取镜像
docker pull mysql:5.7
启动容器
一主两从
docker run -p 3300:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
docker run -p 3301:3306 --name mysql-slave1 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
docker run -p 3302:3306 --name mysql-slave2 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
创建同步账号
在主库中创建主从复制账号,赋权
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
添加配置
主库配置
[mysqld]
##
server-id=100
##
log-bin=mysql-bin
从库1配置
[mysqld]
##
server-id=101
##
log-bin=mysql-slave-bin
##
relay_log=mysql-relay-bin
从库2配置
[mysqld]
##
server-id=102
##
log-bin=mysql-slave2-bin
##
relay_log=mysql-s2-relay-bin
配置方式
以上配置可直接启动容器后,进入到运行中的每个容器中用vim编辑配置文件,也可以在本地配置结束,复制到容器目录中,然后启动。
容器中配置
docker exec -it mysql-master /bin/bash
vi /etc/mysql/mysql.cnf
本地配置
切到文件所在的目录,拷贝文件到容器目录中(容器未启动时)
docker cp mysql.cnf mysql-master:/etc/mysql/
mysql-master,mysql-slave1,mysql-slave2 依次配置完成,且依次启动容器。
执行主备关联
在两个从库中执行如下语句:
change master to master_host='172.17.0.2', master_user='slave', master_password='123456', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos=617, master_connect_retry=30;
说明
master_host 为主库ip,由于是本地docker容器,虚拟ip查看可用以下语句
docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql-master
master_user和 master_password 为上面步骤创建的主从复制账号
master_port 为虚拟局域网内可访问的端口,非宿主机对外端口。
master_log_file和master_log_pos 在master库中执行如下语句查看:
show master status
master_log_pos 此参数决定从库复制主库binlog的起始位置。
启动从库拷贝
在从库中执行语句
start slave
然后查看主从复制状态
show slave status \G;
如果一切正常,显示如下
主要关注几个关键状态,如红色方框部分,如信息不对,请参照前几步重新配置。
演示
主库中创建数据库 mydb
create database mydb
主库
从库1
从库2
异常排查
由于主库一般执行读写操作,从库只能执行读操作,涉及到数据库的更新操作,从库产生拷贝异常时,如何排查和恢复。
为了说明问题,我们在从库1中,删除这个数据库,然后在主库中添加表。看从库是否报错。
删除从库1数据库 mydb
在主库中,数据库mydb创建表 t_test
查看从库1状态
查看从库2状态
列出从库1报的错
Error 'Unknown database 'mydb'' on query. Default database: 'mydb'. Query: 'CREATE TABLE `t_test` ( `id` BIGINT(10) NOT NULL, `name` VARCHAR(200) DEFAULT NULL, `create_time` DATETIME DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=INNODB DEFAULT CHARSET=utf8mb4'
此时报错原因是因为,从库1不存在数据库 mydb 导致创建表语句执行发生错误。
我们继续在主库中创建数据库 mydb2,看从库1是否在报错情况下创建数据库 mydb2
此时查看从库1和从库2,结果分别如下:
由此推知,从库1是在报错情况下不会继续执行主库操作了。mysql备库是通过监听主库binlog按顺序执行每次操作,如执行过程产生异常,后续新的请求不再继续执行。直到错误修复,才会按照执行日志顺次继续执行。
故,主备同步过程,必须实时监控备库运行状态和执行情况,否则同步一旦失败,后续所有更新操作则不会执行,这会导致很大的产线事故。
那么刚才的问题如何修复呢,为了保证所有主从库数据一致,我们采用恢复备库1中的数据库mydb,恢复后查看效果:
为何已经恢复了数据库mydb,从库1怎么还在报错。
mysql不会自动检测并恢复,通过如下语句可重新触发同步:
start slave
由此,异常已经重新恢复,且最新的语句已经同步。这就是我们通常规定主库承担读写操作,从库仅承担读操作,来适应大量读操作的系统级应用。