MySQL主从搭建
环境
以下所有操作,均是在Macbook上进行的。其他系统请自行做适应性调整。
Docker安装
brew cask install docker
# 安装后验证
docker -v
# 安装成功会输出版本号,本机为:Docker version 19.03.8, build afacb8b
安装之前建议先将brew的源设置为阿里云的,这样下载快一些。
设置指南请参考 https://blog.csdn.net/AWEI1024/article/details/107445498
MySQL镜像下载
docker pull mysql/mysql-server:5.7
到此环境准备完毕。
MySQL主从搭建
创建MySQL网络
# 创建 mysql 网络, 网络请自行定义,与本机不冲突即可
docker network create --subnet 172.170.0.0/16 mysql-cluster
MySQL容器脚本
#!/bin/bash
if [ ! $# -eq 2 ];then
echo -e "请输入参数: Usage: $0 port server_id "
exit
fi
PORT=$1
echo -e "Mysql容器映射端口号 = ${PORT} \n"
BASE_PATH="${HOME}/container/mysql/${PORT}"
echo -e "[目录映射] >>> Mysql容器初始化,工作根目录为: ${BASE_PATH}\n"
if [ ! -d ${BASE_PATH} ]; then
conf_data="\
[mysqld] \n \
skip-host-cache \n \
skip-name-resolve \n \
\n \
\n \
datadir=/var/lib/mysql \n \
socket=/var/lib/mysql/mysql.sock \n \
secure-file-priv=/var/lib/mysql-files \n \
\n \
\n \
user=mysql \n \
symbolic-links=0 \n \
\n \
\n \
log-error=/var/log/mysqld.log \n \
pid-file=/var/run/mysqld/mysqld.pid \n \
\n \
\n \
# 慢查询设置 \n \
slow-query-log=1 #启用慢查询日志 \n \
slow_query_log_file=slow_query.log # 慢查询文件 \n \
long_query_time=10 # 查询时间超过10s 判定为慢查询 \n \
\n \
\n \
# binlog 日志设置 \n \
server-id=$2 \n \
\n
# 原本目录要设定为/var/lib/mysql/binlog/mysql-bin,但由于不会自动创建binlog,因此采用这种简单的方式. \n \
log-bin = /var/lib/mysql/mysql-bin \n \
binlog-format=ROW \n \
# binlog 同步刷盘
sync_binlog=1 \n \
# slave 重放日志时记录binlog
log-slave-updates=on \n \
# 从节点重启禁止自动启动复制,建议设置此选项,改为手动进行
skip-slave-start \n \
enforce-gtid-consistency=on \n \
# 启用GTID模式
gtid_mode=on \n \
\n
\n
# innodb 设置 \n \
#### 1:意味着在事务提交前日志已被写入磁盘, 事务可以运行更长以及服务崩溃后的修复能力. \n \
#### 0:如果你愿意减弱这个安全,或你运行的是比较小的事务处理,以减少写日志文件的磁盘 I/O。这个选项默认设置为 0。 \n \
innodb_flush_log_at_trx_commit=1 \n \
\n \
\n \
#### InnoDB 用来高速缓冲数据和索引内存缓冲大小。 更大的设置可以使访问数据时减少磁盘 I/O \n \
#innodb_buffer_pool_size=8M \n \
\n \
\n \
#### 日志组中的每个日志文件的大小(单位 MB)。可以减少刷新缓冲池的次数,从而减少磁盘 I/O。但是大的日志文件意味着在崩溃时需要更长的时间来恢复数据 \n \
#innodb_log_file_size=48M \n \
"
mkdir -p ${BASE_PATH}
echo -e "[目录映射] 根目录不存在,自动创建根目录: >> ${BASE_PATH}\n"
cd ${BASE_PATH}
curr_dir=$(pwd)
echo -e "[目录映射] 切换到根目录: >> ${curr_dir}\n"
echo -e "[目录映射] >>>>>>>>>>>>>>>> \n"
mkdir data
echo -e "[目录映射] 创建子目录: >> data \n"
# mkdir mysqld
# echo -e "[目录映射] 创建子目录: >> mysqld \n"
# mkdir mysql-files
# echo -e "[目录映射] 创建子目录: >> mysql-files \n"
mkdir log
echo -e "[目录映射] 创建子目录: >> log \n"
# mkdir -p binlog/mysql-bin
# echo -e "[目录映射] 创建子目录: >> binlog/mysql-bin \n"
mkdir conf
echo -e "[目录映射] 创建子目录: >> conf \n"
echo -e "[目录映射] 创建配置文件: my.cnf \n"
echo -e "[目录映射] 配置文件(my.cnf)内容如下:\n"
echo -e ${conf_data}
echo -e ${conf_data} > ./conf/my.cnf
echo -e "[>>>>>>>>>>>>> 开始制作Dockerfile >>>>>>>>>>>>>>>]\n"
df_data=" \
FROM mysql/mysql-server:5.7 \n \
MAINTAINER caoawei@aliyun.com \n \
RUN mkdir -p /var/lib/mysql/binlog \n \
RUN chmod -R a+rw /var/lib/mysql/binlog \n \
"
fi
#容器名
C_NAME="mysql_${PORT}"
echo -e "将要创建的容器名为: >> ${C_NAME} << \n"
# -v ${BASE_PATH}/binlog/mysql-bin:/var/lib/mysql/binlog/mysql-bin \
# -v ${BASE_PATH}/mysqld:/var/run/mysqld \
# -v ${BASE_PATH}/mysql-files:/var/lib/mysql-files \
docker run \
-d \
-v ${BASE_PATH}/data:/var/lib/mysql \
-v ${BASE_PATH}/conf/my.cnf:/etc/mysql/my.cnf \
-v ${BASE_PATH}/log:/var/log \
-p "${PORT}":3306 \
-e MYSQL_ROOT_PASSWORD=root \
--name "${C_NAME}" \
mysql/mysql-server:5.7
请在本地机器创建以下脚本:
# 脚本内容为上面的内容
vim mysql-docker-init.sh
chmod -R +x mysql-docker-init.sh
上述脚本将按照以下目录自动创建
(注意:上述脚本只是根据mysql镜像创建容器,容器的启动和停止请使用docker start 和docker stop)
${HOME}/container/mysql/${port}
# 例如本机为: /Users/dasouche/container/mysql/3601
# 其中 ${HOME} 为/Users/dasouche, 容器端口为3601
# 在上述目录下,脚本会自动创建以下脚本,是为到容器的目录映射
${HOME}\
-----container\
-------------mysql\
-----------------3601\
--------------------conf\
--------------------data\
--------------------log\
-----------------3602\
--------------------conf\
--------------------data\
--------------------log\
# conf: 为my.cnf配置文件所在目录,脚本自动生成
# data: mysql数据目录以及binlog存储所在目录
# log: 为mysql 的运行日志文件所在目录
创建MySQL主从容器
创建MySQL主节点
# 本人已将mysql-docker-init.sh加入到PATH下
# 脚本参数: [端口] [server.id]
# 这里的端口为本地机器的端口, 脚本将此端口映射到mysql容器中3306端口上
mysql-docker-init.sh 3601 1
# 容器名为 mysql_端口号
#进入到主节点容器
docker exec -it mysql_3601 bash
#进入到容器后,登录到mysql,root 密码为root,在容器脚本中有指定
mysql -u root -p
#登录到mysql后,执行以下语句: 目的为了外部可通过3601端口以及root账户访问容器中的mysql
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
# 创建复制账号
create user 'repl'@'%' identified by 'repl';
grant replication slave on *.* to 'repl'@'%' identified by 'repl';
创建MySQL从节点
# 端口和server.id 设置为与主节点不同即可
mysql-docker-init.sh 3602 1001
# 按照上述创建mysql主节点的方式,执行一遍上述操作.推荐也创建复制账号.这里就不过多介绍
加入网络
下面的操作是将MySQL主从节点加入到同一个网络,以能够访问。
# 将MySQL主从节点容器加入到上面所创建的网络中
# 主节点加入到网络中,指定具体的IP地址
docker network connect --ip 172.170.0.10 mysql-cluster mysql_3601
# 从点加入到网络中,指定具体的IP地址
docker network connect --ip 172.170.0.11 mysql-cluster mysql_3602
# 验证一下
docker network inspect mysql-cluster
MySQL主从关系建立
# 登录到mysql 从节点后,执行以下操作
# 设置为只读
SET @@GLOBAL.read_only = ON;
# 建立主从关系
# 下面的host 为主节点在mysql-cluster网络中的IP,端口号为3306,复制账号即为上述创建主节点时所创建的复制账号
CHANGE MASTER TO
> MASTER_HOST = '172.170.0.10',
> MASTER_PORT = 3306,
> MASTER_USER = 'reol',
> MASTER_PASSWORD = 'repl',
> MASTER_AUTO_POSITION = 1;
# 启动复制
start slave;
# 验证是否成功
# 观察下面两项是否为Yes
# Slave_IO_Running: Yes
# Slave_SQL_Running: Yes
show slave status \G;
问题
按照上面的步骤操作,一般不会存在问题。本人在操做过程中,由于失误,导致最后生成的my.cnf配置文件没有开启二进制。紧接着在建立主从关系后,没有查验是否建立成功,就在主节点上创建数据库以及表,结果因没有开启binlog,从节点未进行同步。
发现问题后,就修改了脚本(对已存在容器不会产生影响),并修改主从容器目录下生成的my.cnf配置文件,将binlog进行开启, 然后重启主从节点。登录到从节点,通过 start slave命令启动复制,并查看从节点是否同步主节点之前的数据库及表,结果是没有同步。这是因为,binlog中并没有日志,所以从节点无数据可同步。
然后,删除mysql主节点上的数据库及表(之前手动创建的),然后到从节点重新启动复制,结果依然是失败。通过show slave status命令查看,是因为从节点并没有主节点上被删除的数据库及表,导致复制失败(复制自此之后便会中断)。
由于开启了gtid模式, 本人通过以下方法处理了这个问题:
# 进入到从节点容器
docker exec -it mysql_3602 bash
# 登录到mysql
mysql -u root -p
# 设置会话变量 @@session.gtid_next
# 下面的值为binlog文件中最后一个有效的值,因为在这个案例中,所有的都要忽略掉
set @@session.gtid_next='1ba8300e-3062-11eb-9a93-0242ac110002:1';
# 执行一个空事务
begin;
commit;
# 恢复会话变量 @@session.gtid_next为自动模式
set @@session.gtid_next='AUTOMATIC';
# 启动复制
start slave;
下面的截图为MySQL主节点binlog文件的解析内容(删除数据库产生的binlog)
结束语
大家在操作过程中遇到什么问题,欢迎下方评论,进行探讨。