Intro
主从备份是容灾的一种手段, 模拟主从备份可以有下面几种方式:
- 不差钱方式, 买几台主机测试, 这种方式也比较接近线上环境.
- 通过创建几台虚拟机来模拟. 这种方式对本机性能要求相对较高. 相对不差钱可以选这种方式, 但安装几台虚拟机也不是一件效率高的事.
- 在一台主机上创建多个数据库实例. 缺点是环境无法隔离, 需要额外加多一些配置
- 通过 Docker-compose 直接创建多个数据库容器, 暴露端口访问即可.
binlog
是MySQL数据库的二进制日志,用于记录用户对数据库操作的SQL语句(不包括 SELECT
),可以在配置文件开启,也可以在 MySQL 客户端开启. 可以在客户端键入show plugins;
查看 binlog
是否已安装开启( Active )
+----------------------------+----------+--------------------+---------+---------+
| Name | Status | Type | Library | License |
+----------------------------+----------+--------------------+---------+---------+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
| mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| sha256_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| PERFORMANCE_SCHEMA | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL |
| CSV | ACTIVE | STORAGE ENGINE | NULL | GPL |
环境准备
0.1 测试环境
必须安装有 docker
及 docker-compose
用于构建容器环境, 本测试在 Ubuntu 16.04 及下列版本下进行, 使用其他版本可能会有使用差异.
docker-compose 1.25.4
docker 19.03.6
有关安装的细节, 请搜索相关关键词, 或者直接根据 Docker 官方文档 进行安装
0.2 Docker 加速
由于众所周知的原因, 拉取镜像时可能会很慢, 推荐设置国内的镜像源进行加速
在 Ubuntu/Centos/Debian
下修改或创建此文件 /etc/docker/daemon.json
示例文件内容如下, 可以自由添加镜像源. 镜像源有可能会宕机, 镜像源测试请参阅docker-registry-cn-mirror-test
{
"registry-mirrors":[
"https://dockerhub.azk8s.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://reg-mirror.qiniu.com"
]
}
一. Docker 文件准备
1.1 文件目录
-
Dockerfile
是一个文本文件, 只需要touch Dockerfile
创建即可. -
docker-compose.yml
是用于运行多个 Docker 容器的配置文件, 使用yaml
语言.
如只准备测试一主一从, 那么移除 slave02
目录, 添加多个从服务器则相应增加文件夹.
├── docker-compose.yml
├── master
│ ├── Dockerfile
│ └── my.cnf
├── slave01
│ ├── Dockerfile
│ └── my.cnf
└── slave02
├── Dockerfile
└── my.cnf
1.2 docker-compose 文件及解释
-
environment
在创建 MySQL 密码时, 测试用途用root
没问题, 其他时候记得创建复杂密码, 至少可以使用uuidgen
命令生成.
支持在创建时同时创建一个数据库, 创建多个或进行其他数据初始化, 建议依靠外部SQL
文件. -
links
这个不是推荐的配置方式, 不利于扩展, 但在此处我们只是用于测试. 可以自由添加你要的从服务器名称, 用于容器间的连接. 更推荐配置networks
-
ports
冒号左边为暴露的端口, 右边为容器内部的端口号, 在不配置网络的情况下(此时默认为127.0.0.1
), 为了避免端口冲突, 必须使暴露的端口号不一致.
version: '2'
services:
mysql-master:
build:
context: ./ # 声明构建的文件夹
dockerfile: master/Dockerfile # 声明 Docker 文件目录
environment: # 环境变量, 支持数组或列表方式
- "MYSQL_ROOT_PASSWORD=root"
- "MYSQL_DATABASE=db0" # 初始创建的数据库
links:
- mysql-slave01
- mysql-slave02
ports:
- "33065:3306"
restart: always
hostname: mysql-master
mysql-slave01:
build:
context: ./
dockerfile: slave/Dockerfile
environment:
- "MYSQL_ROOT_PASSWORD=6954D5F0"
- "MYSQL_DATABASE=db0"
ports:
- "33066:3306"
restart: always
hostname: mysql-slave01
mysql-slave02:
build:
context: ./
dockerfile: slave02/Dockerfile
environment:
- "MYSQL_ROOT_PASSWORD=6954D5F0"
- "MYSQL_DATABASE=db0"
ports:
- "33067:3306"
restart: always
hostname: mysql-slave02
1.3 Dockerfile 文件及解释
-
FROM
指定了基础镜像, 可以根据需求更改 MySQL 镜像版本 -
COPY
将源文件复制到目标容器, 从服务器相应地创建Dockerfile
, 修改源文件位置. 也可以使用ADD
这个更高级的复制命令, 但没必要.
FROM mysql:5.7.17
COPY ./master/my.cnf /etc/mysql/my.cnf
二. MySQL 配置文件准备
2.1 Master 节点配置
# master/my.cnf
[mysqld]
## 设置server_id,注意要唯一
server_id=100
## 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
binlog-ignore-db=mysql
## 开启二进制日志功能,可以随便取,最好有含义
log-bin=replicas-mysql-bin
## 为每个session分配的内存,在事务过程中用来存储二进制日志的缓存
binlog_cache_size=1M
## 主从复制的格式(mixed,statement,row,默认格式是statement)
binlog_format=mixed
## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
2.2 Slave 节点配置
Slave 节点的配置与 Master 相似, 但每个节点的 server_id
必须不同, 此外增加了 relay_log
中继日志的配置以及只读的设置
[mysqld]
## 设置server_id,注意要唯一
server_id=101
# ... 省略配置
## relay_log配置中继日志
relay_log=replicas-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## 防止改变数据(除了特殊的线程)
read_only=1
三. 构建容器并运行
进入有 docker-compose.yml
的目录, 执行以下命令
该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作, -d
表示后台运行镜像.
docker-compose up -d
之后执行docker ps
查看正在运行的镜像, 如果是一主一从, 可以看到至少两个正在运行的镜像
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ef799b7d8cf8 mstest_mysql-master "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:33065->3306/tcp mstest_mysql-master_1
9d7ea93b7a85 mstest_mysql-slave "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 0.0.0.0:33066->3306/tcp mstest_mysql-slave_1
键入 docker exec -it [name/id] /bin/bash
进入容器, 可以是容器名称也可以是容器 id, 如下方示例:
docker exec -it mysql-master_1 /bin/bash
四. 配置主从
可以直接进入容器再进入 mysql
配置, 也可以不进入, 直接在终端键入下方命令, port
就是 docker-compose.xml
设置的端口号, 例如前面 master
的 33065
mysql -uroot -p -P[port] -h127.0.0.1
4.1 获取主节点状态
键入 show master status;
记住当前 File
的名称和 Position
, 这是从节点进行 binlog
复制找点用的.
mysql> show master status
-> ;
+---------------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------------+----------+--------------+------------------+-------------------+
| replicas-mysql-bin.000003 | 154 | | mysql | |
+---------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec
4.2 开启从节点复制
这里设置复制主节点的相关信息, 在前面文件用的是 root
密码,因此这里也是 root
用户, 将MASTER_LOG_FILE
和 MASTER_LOG_POS
填上相应信息
CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='root', MASTER_PASSWORD='root', MASTER_LOG_FILE='replicas-mysql-bin.000003', MASTER_LOG_POS=154;
接着启动复制.
- 键入
start slave;
- 键入
show slave status\G;
查看是否启用成功, 关注Slave_IO_Running
和Slave_SQL_Running
是否为Yes
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G;
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
同样地, 如果有多个 Slave 节点, 就这一步多做几次.
4.3 验证是否成功
回到 Master 节点, 创建一个数据库 或者 往已经创建好的 db0
写入数据,
mysql> create database db1;
回到 Slave 节点, 查看两边是否同步.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db0 |
| db1 |
五. 后话——另一种主从复制 GTID
GTID 自 MySQL 5.6.MySQL 5.6.5 便引入了,中文叫全局事务 ID(Global Transaction ID)
在本文的基于二进制日志复制中,从库需要告知主库要从哪个偏移量(就是 Log File 的 Position)进行增量同步,如果指定错误会造成数据的遗漏,从而造成数据的不一致。
但有了 GTID,发生主备切换时,MySQL 的其它从库可以自动在新主库上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于 GTID 的复制还可以忽略已经执行过的事务。
参考
公众号:程序员的碎碎念
Github:github.com/FesonX