SpringCloud 之 MySQL 集群(一):Docker 搭建 MySQL,MySQL 主从同步搭建及踩坑

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

开始研究这个主要是公司的应用场景,数据库分为海内和海外,考虑到后面海量的数据以及压力,因此使用数据库集群。
数据库集群方案主要分为两种

  1. Replication:
    优点:异步复制,速度快,高效
    缺点:数据弱一致性,比如:主库更新了,从库还没同步,然后从从库读的就是旧数据,不是更新后的新数据
    应用场景:新闻,日志,发帖,历史数据(数据的正确性要求不高)
  2. PXC(Percona XtraDB Cluster):
    优点:数据强一致性
    缺点:为啥强一致性?因为所有库要么同时提交,要么同时失败,以此速度慢,低效
    应用场景:财务,订单,账户(钱弄错了,这是要命的,数据正确性要求极高)

由于公司的这部分数据主要是一些历史,记录性的数据,所以我选择的 Replication,目的在于高效
先说下,主从不代表读写分离,所以先来解决主从

1.安装 mysql 镜像

我选择从 dockerhub 下载最新镜像:mysql 镜像

docker pull mysql

2.配置主从所需的配置文件

如果说只是单纯的跑个 mysql,只要把容器 run 起来就行了,但是要是要配置主从就要先准备下配置文件,启动时需要把配置挂载到容器里
本人喜欢把自己配置的,安装的都丢到 /data/ 下面,这样找起来好找,没有的目录可以通过 mkdir 命令创建
这里只弄了一主一从,master 是主数据库, slave 是从数据库
目录:

# master 数据库
/data/mysql/master/conf/

# slave 数据库
/data/mysql/slave/conf/

创建配置文件:

# master 配置文件
cat << EOF > /data/mysql/master/conf/my.cnf
[mysqld]
log-bin=mysql-bin    #日志文件命名
server-id=1     #注意这个id>0且要唯一
default_authentication_plugin=mysql_native_password #解决 mysql 2059 错误,没有此问题的不加
EOF

# slave 配置文件
cat << EOF > /data/mysql/slave/conf/my.cnf
[mysqld]
log-bin=mysql-bin   #日志文件命名
server-id=2     #注意这个id>0且要唯一
default_authentication_plugin=mysql_native_password #解决 mysql 2059 错误,没有此问题的不加
EOF

到这准备工作就做好了,很简单
PS 踩坑:Navicat连接MySql8+出现 2059 错误,上面加上配置后就省了还要跑到容器里去改,麻烦死了
就我这 1G 的服务器根本连容器都进不去,直接卡死,没有这问题的就不用加这个配置了

3.启动镜像,生成 mysql 容器

# master 容器启动
docker run -d -p 7000:3306 --name master \
--privileged=true \
-v /data/mysql/master/conf:/etc/mysql \
-v /data/mysql/master/logs:/var/log/mysql \
-v /data/mysql/master/data:/var/lib/mysql \
-v /data/mysql/master/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql

# slave 容器启动
docker run -d -p 7001:3306 --name slave \
--privileged=true \
-v /data/mysql/slave/conf:/etc/mysql \
-v /data/mysql/slave/logs:/var/log/mysql \
-v /data/mysql/slave/data:/var/lib/mysql \
-v /data/mysql/slave/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
  • --privileged=true    容器内的 root 拥有真正的 root 权限
  • -v /data/mysql/master/conf:/etc/mysql    刚的配置要挂载进去
  • -v /data/mysql/master/logs:/var/log/mysql     日志目录,挂载
  • -v /data/mysql/master/data:/var/lib/mysql     这个目录很重要,数据什么的都在这个目录下,否则容器挂了,数据也没了
  • -v /data/mysql/master/mysql-files:/var/lib/mysql-files    
    PS 踩坑:卡在这很久,不挂载这个目录,容器启动会报 Failed to access directory for --secure-file-priv 错误,然后启动失败,应该是没权限,没这个问题的就不用挂载这个目录了
  • -e MYSQL_ROOT_PASSWORD=123456   都看得懂,设置数据库初始密码的

4.容器启动失败排错

# 查看容器是否启动成功
docker ps

# 没成功的,查看失败的容器
docker ps -a

# 然后查看具体容器为啥启动失败,xxxxx 为容器 ID
docker logs xxxxx

我启动的时候就失败了,原因就是上面的  Failed to access directory for --secure-file-priv,成功了容器就能直接 run 起来

5.主从同步之 master 配置

上面成功的就可以松口气,一切结束 80%,毕竟后面主从同步基本上是跑 sql 了

-- 创建用户叫 slave,后面从库需要连接到这个用户上,by 后面的密码和数据库密码没关系,自己设
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';

-- 表示可以从任意 ip 使用此用户名和密码连接到主数据库
GRANT REPLICATION SLAVE ON *.* to 'slave'@'%';

-- 刷新配置
flush privileges;

-- 查看日志文件
show master status;

踩坑 PS:create 不可省略,mysql8.0 以前的版本可以使用 grant 在授权的时候隐式的创建用户,8.0以后已经不支持,网上很多博客写的都是一样的,而且 sql 都跑不通也不知道为啥

这个日志文件非常重要,从库根据这个日志文件去同步的
到这里 master 配置结束

6.主从同步之 slave 配置

-- 停止主从连接
stop slave;

-- 配置主从连接关系
change master to master_host='172.17.0.3', master_user='slave', master_password='123456', master_log_file='mysql-bin.000003';

-- 启动主从连接
start slave;

PS:这里的 master_host 所填的 IP 不是服务器的 IP,而是 master 容器的 IP 地址

查看容器 IP 地址

# xxxxx 为容器 ID
docker inspect --format '{{ .NetworkSettings.IPAddress }}' xxxxx

7.验证主从连接成功

-- 查看主从连接情况
show slave status;

这里有三个属性很重要

  • Slave_IO_State:连接状态,要到 “等待主库发送事件”
  • Slave_IO_Running:从服务器是否连接成功,需要 Yes
  • Slave_Sql_Running:Sql 读取是否成功,需要 Yes

都 OK 了,去主库建个库,发现从库有,OK,主从成功

8.要是容器挂了咋办?(踩坑)

之前我们挂载的 data 里有数据,可以自己试试
重启容器,重写配置主从关系,然后 start slave 启动时报错了

Error:Slave failed to initialize relay log info structure from the repository

意思是启动slave时,使用repository中信息初始化relay log结构失败了,由于我使用的是冷备份文件恢复的实例,在mysql库中的slave_relay_log_info表中依然保留之前relay_log的信息,所以导致启动slave报错。因此我们要先 reset 一下

-- 停止主从连接
stop slave;

-- 1、删除slave_master_info ,slave_relay_log_info两个表中数据;
-- 2、删除所有relay log文件,并重新创建新的relay log文件;
-- 3、不会改变gtid_executed 或者 gtid_purged的值
reset slave;

-- 配置主从连接关系
change master to master_host='172.17.0.3', master_user='slave', master_password='123456', master_log_file='mysql-bin.000003';

-- 启动主从连接
start slave;

-- 查看主从连接情况
show slave status;

然后我们再来看下连接状态,然后你会发现 

Slave_Sql_Running 始终是 No,怎么 start 都是 No

解决办法:

-- 停止主从连接
stop slave;

-- 跳过复制错误
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;

-- 启动主从连接
start slave;

--查看主从连接状态
show slave status;

官方解释:https://dev.mysql.com/doc/refman/5.7/en/set-global-sql-slave-skip-counter.html

This statement skips the next N events from the master. This is useful for recovering from replication stops caused by a statement.
When using this statement, it is important to understand that the binary log is actually organized as a sequence of groups known as event groups. Each event group consists of a sequence of events.
• For transactional tables, an event group corresponds to a transaction.
• For nontransactional tables, an event group corresponds to a single SQL statement.
When you use SET GLOBAL sql_slave_skip_counter to skip events and the result is in the middle of a group, the slave continues to skip events until it reaches the end of the group. Execution then starts with the next event group.

PS:不要试着把解决 Slave_Sql_Running 问题的 SQL,连着之前的一起跑,这样你会发现 Yes 了下立刻又 No了,我觉得是因为之前容器挂了后,日志里存在连接报错了,所以导致后面连接失败,而重新建立连接时需要时间的,如果把 SQL 连着跑,会导致连接后又读到那个错,所以又 No 了,所以要注意下!这是我的理解,我没求证,呵呵!!!!!!

猜你喜欢

转载自blog.csdn.net/qq_37143673/article/details/94723044