使用docker-compose搭建mysql主从复制:
Mysql的主从【快速】搭建
- 编写脚本
- 编写 master.sh 脚本
- 编写 slave.sh 脚本
- 编写docker-compose.yml文本
- 测试阶段
- 主从同步效果
- 主从环境重启
- 容器被删除,重新启动
- 从节点关闭,主节点继续写入数据
- 从节点删除,主节点继续写入数据,从节点重新创建
编写脚本
在Linux中编写Shell脚本,目的:
此脚本主要是根据环境变量,创建出用于主从同步的用户。关于为什么要创建出master,slave脚本,是为了区分master和slave环境,
因为只要把sql和sh文件放到master目录下面,master在第一次初始化的时候,会自动执行里面的文件内容
编写 master.sh 脚本
在创建docker.compose.yml目录位置下创建init目录,接着分别编写shell脚本
mkdir -p ./init/master
cat > ./init/master/master.sh <<EOF
master.sh
#!/bin/bash
#定义用于同步的用户名
MASTER_SYNC_USER=\${MASTER_SYNC_USER:-sync_admin}
#定义用于同步的用户密码
MASTER_SYNC_PASSWORD=\${MASTER_SYNC_PASSWORD:-123456}
#定义用于登录mysql的用户名
ADMIN_USER=\${ADMIN_USER:-root}
#定义用于登录mysql的用户密码
ADMIN_PASSWORD=\${ADMIN_PASSWORD:-123456}
#定义运行登录的host地址
ALLOW_HOST=\${ALLOW_HOST:-%}
#定义创建账号的sql语句
CREATE_USER_SQL="CREATE USER '\$MASTER_SYNC_USER'@'\$ALLOW_HOST' IDENTIFIED BY '\$MASTER_SYNC_PASSWORD';"
#定义赋予同步账号权限的sql,这里设置两个权限,REPLICATION SLAVE,属于从节点副本的权限,REPLICATION CLIENT是副本客户端的权限,可以执行show master status语句
GRANT_PRIVILEGES_SQL="GRANT SELECT,REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO '\$MASTER_SYNC_USER'@'\$ALLOW_HOST';"
#定义刷新权限的sql
FLUSH_PRIVILEGES_SQL="FLUSH PRIVILEGES;"
#执行sql
mysql -u"\$ADMIN_USER" -p"\$ADMIN_PASSWORD" -e "\$CREATE_USER_SQL \$GRANT_PRIVILEGES_SQL \$FLUSH_PRIVILEGES_SQL"
EOF
编写 slave.sh 脚本
mkdir -p ./init/slave
cat > ./init/slave/slave.sh <<EOF
slave主要是去master查询最新的pos位置和binlog文件名称,然后创建同步需要的相关信息,然后执行start slave;
slave.sh
#定义连接master进行同步的账号
SLAVE_SYNC_USER="\${SLAVE_SYNC_USER:-sync_admin}"
#定义连接master进行同步的账号密码
SLAVE_SYNC_PASSWORD="\${SLAVE_SYNC_PASSWORD:-123456}"
#定义slave数据库账号
ADMIN_USER="\${ADMIN_USER:-root}"
#定义slave数据库密码
ADMIN_PASSWORD="\${ADMIN_PASSWORD:-123456}"
#定义连接master数据库host地址
MASTER_HOST="\${MASTER_HOST:-%}"
#连接master数据库,查询二进制数据,并解析出logfile和pos,这里同步用户要开启 REPLICATION CLIENT权限,才能使用SHOW MASTER STATUS;
RESULT=\`mysql -u"\$SLAVE_SYNC_USER" -h\$MASTER_HOST -p"\$SLAVE_SYNC_PASSWORD" -e "SHOW MASTER STATUS;" | grep -v grep |tail -n +2| awk '{print \$1,\$2}'\`
#解析出logfile
LOG_FILE_NAME=\`echo \$RESULT | grep -v grep | awk '{print \$1}'\`
#解析出pos
LOG_FILE_POS=\`echo \$RESULT | grep -v grep | awk '{print \$2}'\`
#设置连接master的同步相关信息
SYNC_SQL="change master to master_host='\$MASTER_HOST',master_user='\$SLAVE_SYNC_USER',master_password='\$SLAVE_SYNC_PASSWORD',master_log_file='\$LOG_FILE_NAME',master_log_pos=\$LOG_FILE_POS,get_master_public_key=1;"
#开启同步
START_SYNC_SQL="start slave;"
#查看同步状态
STATUS_SQL="show slave status\G;"
mysql -u"\$ADMIN_USER" -p"\$ADMIN_PASSWORD" -e "\$SYNC_SQL \$START_SYNC_SQL \$STATUS_SQL"
EOF
编写docker-compose.yml文本
version: '3'
services:
master:
image: mysql:8.0.28
container_name: mysql-master
ports:
- '3306:3306'
restart: always
hostname: mysql-master
environment:
MYSQL_ROOT_PASSWORD: "123456"
MASTER_SYNC_USER: "sync"
MASTER_SYNC_PASSWORD: "123456"
ADMIN_USER: "root"
ADMIN_PASSWORD: "123456"
TZ: "Asia/Shanghai"
deploy:
resources:
limits:
memory: 512M
cpus: 50m
healthcheck:
test: ["CMD","mysqladmin","-uroot","-p$${MYSQL_ROOT_PASSWORD}","ping","-h","localhost"]
timeout: 2s
interval: 10s
retries: 5
start_period: 5s
logging:
options:
max-file: '1'
max-size: '128k'
command:
- "--server-id=1"
- "--character-set-server=utf8mb4"
- "--collation-server=utf8mb4_unicode_ci"
- "--log-bin=mysql-bin"
- "--sync_binlog=1"
- "--binlog-ignore-db=mysql"
- "--binlog-ignore-db=sys"
- "--binlog-ignore-db=performance_schema"
- "--binlog-ignore-db=information_schema"
- "--sql_mode=NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT,ANSI_QUOTES"
volumes:
- ./init/master:/docker-entrypoint-initdb.d
- ./data/master:/var/lib/mysql
slave:
image: mysql:8.0.28
container_name: mysql-slave
ports:
- '3307:3306'
restart: always
hostname: mysql-slave
environment:
MYSQL_ROOT_PASSWORD: "123456"
SLAVE_SYNC_USER: "sync"
SLAVE_SYNC_PASSWORD: "123456"
ADMIN_USER: "root"
ADMIN_PASSWORD: "123456"
MASTER_HOST: "mysql-master"
TZ: "Asia/Shanghai"
healthcheck:
test: ["CMD","mysqladmin","-uroot","-p$${MYSQL_ROOT_PASSWORD}","ping","-h","localhost"]
timeout: 2s
interval: 10s
retries: 5
start_period: 5s
deploy:
resources:
limits:
memory: 512M
cpus: 50m
logging:
options:
max-file: '1'
max-size: '128k'
depends_on:
master:
condition: service_healthy
command:
- "--server-id=2"
- "--character-set-server=utf8mb4"
- "--collation-server=utf8mb4_unicode_ci"
- "--sql_mode=NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT,ANSI_QUOTES"
volumes:
- ./init/slave:/docker-entrypoint-initdb.d
- ./data/slave:/var/lib/mysql
启动准备,最终结构如下图所示:
执行脚本
docker-compose up -d
通过docker logs -f mysql-slave 查看从mysql日志如下图所示:看到以下两个yes,就代表成功了
测试阶段
注意:这里由于用到了Mysql8.0+版本的数据库,采用老版Navicate是连接不上的,主要是还不支持Mysql8新增加的加密方式caching_sha2_password,所以这里最直接的方式就是去官网下载最新的navicate16,亲测有效,另外一种方式就是修改mysql的加密方式为老版navicate支持的加密方式。
这里我直接下载最新,目的是快速测试mysql的主从效果
连接master
.
连接slave
.
主从同步效果
在master中创建test数据库,slave中同步出现test数据库
创建表及添加数据测试
主从环境重启
docker-compose restart
重新连接数据库,查看从节点同步状态
SHOW SLAVE STATUS;
可以看到,重启之后,同步也是正常的
当修改数据和新增数据,也是可以正常同步
.
容器被删除,重新启动
容器已经被删除了,数据库也无法正常连接
重启容器,查看同步状态,
在从节点执行。可以看到,同步也是正常的
从节点关闭,主节点继续写入数据
这里测试,当从节点被关闭,然后主节点继续写入数据,然后从节点启动
测试结果显示:同步也是正常开启的
从节点删除,主节点继续写入数据,从节点重新创建
节点容器已经被删除,也无法正常连接
主节点操作数据
创建从节点,启动容器
注意:在从节点中删除或修改数据的方式试图保持和主节点数据一致,这样子是没用的,后续操作还是没有同步
这种无法进行同步的情况下,需要将slave数据库删除,再执行一下命令即可恢复同步
这里同步点正常开启,但是同步失败,
此时需要执行sql语句:
STOP SLAVE;
RESET SLAVE;
CHANGE MASTER TO master_log_pos=0;
START SLAVE;
SHOW SLAVE STATUS;
后续在刷新slave数据库,可以看到,数据已经同步过来了
基于docker-compose搭建mysql主从已经结束,这里主要演示了如何一键搭建mysql主从,同时测试在各种环境下,还能保证主从同步。但是单主从同步肯定也无法满足企业的需求,有兴趣的同学可以研究一些主主双写同步,然后通过nginx搭建主备模式,达到高可用