环境
Mac Intel-64
MySQL:5.7
如果是Mac M1/M2处理器,查询mysql镜像
docker pull --platform linux/x86_64 mysql:5.7
安装Docker
参见菜鸟教程 www.runoob.com/docker/maco…
如果已安装请跳过
搭建Mysql集群
拉取镜像
#拉取镜像
docker pull mysql:5.7
#查看镜像
docker images
看到如下镜像列表
启动节点
如果要使用文件挂载,注意事项参见Docker启动mysql。
使用不挂载文件的方式启动:
#主节点对外映射的端口是3310,root账户密码是root
docker run -p 3310:3306 --name master -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
#从节点1对外映射的端口是3311,root账户密码是root
docker run -p 3311:3306 --name slave1 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
#从节点2对外映射的端口是3312,root账户密码是root
docker run -p 3312:3306 --name slave2 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
#从节点3对外映射的端口是3313,root账户密码是root
docker run -p 3310:3306 --name slave3 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
可以使用docker logs containerName/containerId(比如,master)
查看日志
确认容器是否启动成功。
-p表示接口映射,比如这里将master容器的3306端口映射给宿主机(就是你的电脑)的3310(也可以是其他端口)端口;
-e表示设置环境变量,比如这里是将master容器的root账号密码设置为root(也可以是其他的,自己能记住就行);
--name表示给容器命名;
-d表示让容器后台运行。
使用docker ps
查看运行中的容器:
测试连接
可以使用cmd/navicat(当然也可以是别的,哈哈),使用映射的宿主机端口号,比如上面的3310等,默认root用户,密码就是上面节点启动配置的123456
配置主从
挂载文件方式
直接在宿主机挂载的~/docker/mysql/slave4/conf/
(目录名自己随便取)目录下编辑my.cnf
。
非挂载文件方式
进入master容器
docker exec -it master /bin/bash
进入etc
目录下,看到下面的my.cnf
文件:
使用vim编辑
my.cnf
文件。(如果提示找不到vim命令,参见解决docker里面显示bash: vim: command not found)
修改主从配置
使用vim打开my.cnf
文件后,
进入编辑模式,在
[mysqld]
下添加如下内容:
对于master节点:
log-bin=mysql-bin #名称没限制,一般都这么叫
server-id=1 #数字是多少没限制,但是从1开始是习惯吧
对于slave节点:
log-bin=mysql-bin #名称没限制,见名知意
relay-log=mysql-relay #名称没限制,见名知意
server-id=2 #数字是多少没限制,最好连续吧,不重复就行,几个slave依次2,3,4
保存并退出,然后重启容器
docker restart master salve1 slave2 slave3
查看是否启动成功
docker ps
未启动成功的使用docker logs containerName(比如master)
查看日志。
搭建主从复制+读写分离
主从复制(宿主机操作)
master节点设置
登录master数据库
mysql -uroot -P3310 -h127.0.0.1 -p #回车后输入密码,然后再次回车
然后创建账户并授权
-- 表示任意主机都可以使用账号密码slave/123456对master进行主从复制。
GRANT REPLICATION SLAVE,SELECT ON *.* TO 'slave'@'%' IDENTIFIED BY '123456';
-- 刷新授权
FLUSH PRIVILEGES;
对于上面的授权,如果只授予REPLICATION SLAVE,使用slave账户登录slave数据库节点后,会发现只能看到
information_schema
库所以需要加上
SELECT
权限,特别是要做读写分离时
对mysql授权不太了解的参见老板:让你添加一个mysql用户并给予权限这么费劲吗?
查看master状态
show master status;-- 查看master状态
Binlog_Do_DB
:需要复制的数据库。
Binlog_Ignore_DB
:不需要复制的数据库。
注意:File 和 Position 字段的值后面将会用到,在后面的操作完成之前,需要保证 Master 库不能做任何操作,否则将会引起状态变化,File 和 Position 字段的值变化。
slave节点设置
进入slave节点
mysql -uroot -P3311 -h127.0.0.1 -p #回车后输入密码,然后再次回车
查看slave节点状态
正常情况下,
SlaveIORunning
和 SlaveSQLRunning
都是 No,因为我们还没有开启主从复制过程。
在slave数据库的终端中,将slave配置为master的从节点
CHANGE MASTER TO master_host = '172.17.0.2',-- 容器的ip
master_user = 'slave',-- 上文创建的账号名称
master_password = '123456',-- 上文创建的账号密码
master_port = 3306, -- 容器的端口号,默认3306
master_log_file = 'mysql-bin.000028',-- 修改成上文中的File字段的值
master_log_pos = 5254, -- 修改成上文中的Position字段的值
master_connect_retry = 30;
注意事项:如果执行上面的命令出现错误,先重置。执行完下面两条命令。
stop slave; -- 停止从库复制
reset master; -- 重置master
启动从服务器复制功能
start slave;
命令说明:
master_host
:Master 的地址,指的是容器的独立 ip, 可以通过docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称 | 容器 id
查询容器的 ip
master_port
:Master 的端口号,指的是容器的端口号
master_user
:用于数据同步的用户
master_password
:用于同步的用户的密码
master_log_file
:指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值(mysql-bin.000028)
master_log_pos
:从哪个 Position 开始读,即上文中提到的 Position 字段的值(5254)
master_connect_retry
:如果连接失败,重试的时间间隔,单位是秒,默认是 60 秒
再次查看slave节点状态
SlaveIORunning
和 SlaveSQLRunning
都是 Yes,说明主从复制已经开启。此时可以测试数据同步是否成功。
主从复制排错:
使用 start slave 开启主从复制过程后,如果 SlaveIORunning 一直是 Connecting,则说明主从复制一直处于连接状态,这种情况一般是下面几种原因造成的,我们可以根据 Last_IO_Error 提示予以排除。
- 网络不通
- 检查 ip, 端口
- 密码不对
- 检查是否创建用于同步的用户和用户密码是否正确
- pos 不对
- 检查 Master 的 Position
测试主从复制
我们在master创建一个数据库
create database test;
查看slave节点
重置主从配置
如何停止从服务复制功能
stop slave;
如何重新配置主从 (即清除之前的主从配置)
stop slave;
reset master;
原理简述
relay log
很多方面都跟 binary log
差不多。区别是:从服务器 I/O 线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后 SQL 线程会读取 relay-log
日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致。
完整的主备流程图
最后让我们来看一下,一个 update 语句在节点 A 执行,然后同步到节点 B 的完整流程图。
可以看到:主库接收到客户端的更新请求后,执行内部事务的更新逻辑,同时写入 binlog
。
备库 B 跟主库 A 之间维持了一个长连接。主库 A 内部有一个线程,专门用于服务备库 B 的这个长连接。
一个事务日志同步的完整过程是这样的:
1、在备库 B 上通过 change master
命令,设置主库 A 的 IP、端口、用户名、密码、以及要从哪个位置开始请求 binlog
,这个位置包含文件名和日志偏移量。
2、在备库 B 上执行 start slave
命令,这时侯备库会启动两个线程,io_thread
和 sql_thread
。其中, io_thread
负责与主库建立连接。
3、主库 A 校验完用户名、密码后,开始按照备库 B 传过来的位置,从本地读取 binlog
,发给 B。
4、备库 B 拿到 binlog
后,写到本地文件,称为中转日志(relay log)
。
5、sql_thread
读取中转日志,解析日志里的命令,并执行。