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

* Replication:
优点:异步复制,速度快,高效
缺点:数据弱一致性,比如:主库更新了,从库还没同步,然后从从库读的就是旧数据,不是更新后的新数据
应用场景:新闻,日志,发帖,历史数据(数据的正确性要求不高)
* PXC(Percona XtraDB Cluster):
优点:数据强一致性
缺点:为啥强一致性?因为所有库要么同时提交,要么同时失败,以此速度慢,低效
应用场景:财务,订单,账户(钱弄错了,这是要命的,数据正确性要求极高)
由于公司的这部分数据主要是一些历史,记录性的数据,所以我选择的 Replication,目的在于高效
先说下,主从不代表读写分离,所以先来解决主从

1.安装 mysql 镜像

我选择从 dockerhub 下载最新镜像:mysql 镜像 <https://hub.docker.com/_/mysql?tab=tags>
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
<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 了,所以要注意下!这是我的理解,我没求证,呵呵!!!!!!

你可能还会出现这种情况

Slave_IO_Running 始终是 No 该怎么办?

这种情况一般出现在你的 master,slave 都挂了,然后你把容器 start 后,重新 slave start 发现无法同步,查看 status
发现 Slave_IO_Running 启动后为 No

解决方法:
1.查看你的 master 容器的 ip 地址是否产生了变化,重启容器后的 ip 可能改变
2.查看你的 master 的日志文件是否产生变化,比如原来是 mysql-bin.000003,重启后可能变为 mysql-bin.000004 了

保证这两个正确,基本可以解决问题

友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信