MySQL:单/多服务器 Docker 容器下 MySQL 的主从复制
1. 主从数据库概念
主从复制数据库集群:
主库,负责写入数据(insert,update,delete),我们称为写库;
从库,负责数据的读取(select),我们称为读库;
实现数据库的读写分离。
2. 准备工作
主从两台服务器 都需要关闭防火墙和selinux,避免后续配置出现问题。
2.1 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
2.2 关闭selinux
临时关闭:setenforce 0
永久关闭:sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
2.3 安装docker
3. 运行mysql
3.1 拉取mysql镜像
主库服务器和从库服务器 运行命令
docker pull mysql:5.7
等待镜像拉取完成
3.2 运行docker容器
主库服务器 执行命令
docker run --name mysql-master -p 3339:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 --restart=unless-stopped -d mysql:5.7
从库服务器 执行命令
docker run --name mysql-slave -p 3340:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 --restart=unless-stopped -d mysql:5.7
参数解释:
--name mysql-master 设置容器名称为mysql-master
-p 3339:3306 设置端口在容器外的映射(暴露给主机)为3339
--privileged=true 设置root用户为 root权限,不加这个参数 root用户为普通用户权限
-e MYSQL_ROOT_PASSWORD=123456 设置容器内环境变量
--restart=unless-stopped 重启策略,容器非正常停止 重启容器。避免主从节点中有一个停止导致同步失败
-d mysql:5.7 设置 后台 启动mysql:5.7镜像
查看是否创建数据库,命令
docker ps | grep mysql
4. 主从配置
4.1 查看主从服务器ip
4.1.1 若主从服务器为同一台服务器
主库服务器执行 docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql-master
查看mysql-master容器的ip
从库服务器执行 docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql-slave
查看mysql-slave容器的ip
测试两个容器是否能够互通,进入容器命令docker exec -it <容器的名称或id> bash
(举例 进入主库容器docker exec -it mysql-master bash
)
进入容器后 ping 另一台容器ip,看是否能通
4.1.2 若主从服务器分属两台服务器
主从服务器查看ip 命令 ifconfig
(如果是阿里云、华为云、腾讯云,直接用公网ip)
测试两服务器是否互通
4.2 主从配置实现
4.2.1 主库配置
1、在主服务器 进入mysql-master容器,docker exec -it mysql-master bash
。
2、修改配置文件 vim /etc/mysql/my.cnf
没有vim 需要安装vim【Ubuntu命令】
更新软件列表命令:apt-get update
安装vim命令:apt-get install vim
my.cnf配置文件中添加:
[mysqld]
# 设定服务id,同一局域网内 此id唯一
server-id=100
# 启动二进制日志,并定义日志位置名称;将操作命令记录到日志中,同步数据
# 可在主节点执行 show variables like '%log_bin%'; 查看日志位置
log-bin=mysql-bin
3、重启mysql服务 使修改内容生效 service mysql restart
重启mysql服务之后,会使docker容器停止,需要重新启动(加上--restart这里就不用了)
docker start mysql-master
4、创建数据同步用户 并 授权
进入容器 docker exec -it mysql-master bash
进入mysql的root用户 mysql -uroot -p123456
创建slave用户 :
# 创建用户slave 密码为 123456,% 允许任何远程主机登录此用户
create user 'slave'@'%' identified by '123456';
为slave用户赋予权限:
# replication client 用户的复制权限
# replication slave 监视管理复制用户权限
# 赋予slave用户 对于 *.*(所有库的所有表 格式:database_name.table_name) 的权限
grant replication slave, replication client on *.* to 'slave'@'%';
4.2.2 从库配置
1、在从服务器 进入mysql-slave容器:docker exec -it mysql-slave bash
2、编辑配置文件 vim /etc/mysql/my.cnf
(没有vim,同上)
my.cnf配置文件添加:
[mysqld]
# server-id ,意义同上
server-id=101
# 如果此从库 作为 主库,开启二进制日志功能
# log-bin=mysql-slave-bin
# 定义中继日志位置和名称;将主机的二进制日志记录到中继日志,SQL线程读取中继日志SQL 用于同步数据
# 可在从节点执行 show variables like '%relay_log%'; 查看日志位置
relay_log=mysql-relay-log
3、重启服务,启动docker(加上--restart就不用重启容器了)
service mysql restart
docker start mysql-slave
4.2.3 链接主从数据库
1、查看主节点状态信息
在mysql-master容器的mysql控制台root用户 查看主库状态信息,记录File和Position,sql:
show master status;
执行完之后,主节点服务器不要在进行任何操作,否则可能会使Position变动,导致配置失败
2、在从节点 配置同步数据参数信息
sql语句:
change master to master_host='192.168.44.156', \
master_user='slave', \
master_password='123456', \
master_port=3339, \
master_log_file='mysql-bin.000001', \
master_log_pos= 617, \
master_connect_retry=30;
配置说明:
master_host:主节点的地址,同一台服务器用主库容器mysql-master的ip
mster_user:主节点创建授权的账户
master_password:用户密码
master_port:主节点的端口号,指的是容器的端口号,我mysql-master映射出来的端口是3339;同一台服务器使用3306
master_log_file:上述主节点状态信息中的File,指定slave从哪个日志文件复制数据
master_log_pos:上述的Position,从哪个Positon开始读取
master_connect_retry:连接失败时的重试 时间间隔,单位是秒,默认60s
3、开启主从复制
在从节点执行sql:
start slave;
4、查看主从复制状态信息
从节点执行SQL:
# 注意末尾没有分号
show slave status \G
当 Slave_IO_Running 和 Slave_SQL_Running 都为 YES,说明主从复制配置成功。
Slave_IO_Running 为 Connecting 的 可能原因
5、测试
主数据库 root用户 创建数据库 db_test
create database db_test;
从数据 root用户 查看数据库
show databases;
从数据库 有db_test数据库,说明成功。
5. 后续问题
5.1 Slave_IO_Running 为 Connecting
Slave_IO_Running 为 Connecting 的 可能原因
问题起因:
由于我在主节点 查看主节点状态信息 show master status;
,之后又在主节点进行部分无关操作,导致主节点状态信息的Position发生改变。
解决方案:
从节点停止同步服务 stop slave;
,主节点查看状态信息show master status;
时不要进行别的操作 ,后续步骤按流程操作。
5.2 Slave_SQL_Running: No
问题起因:
容器启动时没有添加参数--restart=unless-stopped
,从节点mysql意外关闭,导致后续同步失败。
解决方案:
1、从节点停止slave服务 stop slave;
2、从节点跳过一个事务SQL(InnoDB事务表则跳过事务组的SQL,MyISAM非事务表跳过单条SQL) set global sql_slave_skip_sounter=1;
3、开启slave服务 start slave;
4、查看信息 show slave status\G
5.3 不要对从库进行写入操作
对从库进行 insert 操作,由于不是双写,从库的写入操作无法同步到主库,导致主库插入相同主键的数据 发生错误。