随着业务的增加,数据量逐渐扩大,数据的安全性就变得尤为重要。虽然我们可以定期备份数据来达到保护的效果,但是 MySQL 提供了 复制 功能可以有效的实现这个目的。
主从复制
复制 顾名思义,就是定期的将一个 MySQL 上的变更,同步到其他的 MySQL 上。这不仅解决了因为单个数据库崩溃而导致数据丢失的问题。也给数据库的 读写分离 提供了方便,避免了单个数据库性能的降低而产生对外服务能力不足的问题。
主从复制 的原理:主节点的所有变更会记录到一个二进制日志(binlog)中,从节点会启动两个线程:I/O,SQL。I/O 用于请求主节点的二进制文件,同步变化到从节点的中继日志(relay log)中。SQL 线程则读取中继文件(relay log),并解析成集体步骤,完成数据的一致。如下图:
二进制日志 作为数据同步的载体,在这个过程中尤为重要。二进制日志只记录数据的改动,不改变数据的语句则不会被记录。MySQL 的复制除了基于 SQL,还有一种是基于行,这里不作讨论。二进制日志并不是一个单独的文件,而是由一系列易于管理的文件组成。
下面,我们介绍一下使用 Docker 搭建一个主从复制的示例。
Docker 启动多个 MySQL 容器
Docker 的安装这里不多作介绍。
获取镜像
首先我们先去镜像仓库拉取一个 MySQL 的镜像。
docker pull hub.c.163.com/library/mysql:latest
完成之后,可以通过 docker images
查看本地的镜像。
生成容器并启动
接下来启动容器,关于 镜像和容器的区别 可以网上查询资料详细了解。
1 | # 主节点 master |
这里简单说明一下这两个命令:
docker run [imageId]
是启动一个包含指定镜像的容器。这个命令会建立一个新的容器,如果我们只需要启动,重启,关闭已有的容器。可以使用 docker start/restart/stop container
。
--name
给容器指定名称
--link
进行容器间的通信。docker 的容器之间默认是隔离的。master:master
是指在 slave
容器中,可以通过 master:3306
直接访问 master
容器。根据之前原理的介绍,这在主从复制中是必须的,因为从节点要启动一个 I/O 线程去同步二进制日志的变更。这点需要特别注意。
-p
进行本机和容器的端口映射。访问本地的 3306
端口直接映射到 master 的 3306
端口。
-e
指定容器的环境变量。MYSQL_ROOT_PASSWORD=123456
指定 MySQL root 用户的密码是 123456。
-d
容器后台运行。
9e641
MySQL 镜像 id。
Master Slave 配置
首先进入到容器内,修改 MySQL 的配置文件。
修改主节点配置
docker exec -it master /bin/bash
进入容器。
vim /etc/mysql/mysql.conf.d/mysql.conf
修改配置。
1 | # 追加下面配置 |
在主节点添加用户
mysql -uroot -p123456
登录。然后执行下列语句:
1 | create user repl_user; # 创建用户 repl_user |
修改从节点配置
docker exec -it slave/bin/bash
进入容器。
vim /etc/mysql/mysql.conf.d/mysql.conf
修改配置。
1 | # 追加下面配置 |
连接 Master 和 Slave
在从节点 Slave 的 MySQL 控制台执行:
1 | change master to master_host = 'master', master_port = 3306, master_user = 'repl_user', master_password = 'repl_user'; # 指定主节点 |
完成上面的步骤之后,我们重启 docker 容器,使上面的 MySQL 配置生效。
1 | docker restart master |
主节点 Master 可以在 MySQL 控制台执行 show master status;
查看当前状态信息。
从节点 Slave 可以在 MySQL 控制台执行 show slave status;
查看当前状态信息。其中,Slave_IO_Running
和 Slave_SQL_Running
分别对应 slave 的两个工作线程。都为 Yes
表示配置成功。Slave_IO_State
是 Waiting for master to send event
表示等待主节点的变更。
现在大功告成,我们可以在 Master
执行以下测试语句。
1 | create database Hello; # 创建数据库 Hello |
不出意外,从节点 Slave
上应该会同步出 数据库 Hello
。
遇到的问题
This operation cannot be performed with a running slave io thread; run STOP SLAVE IO_THREAD FOR CHANNEL ‘’ first.
执行 change master to ...
时没有关闭同步,需要先执行 stop slave
;
Slave_IO_Running 为 No
Slave 的 I/O 进程出现错误,应先验证节点之间是否可以正常通信。这个示例中,docker 的容器之间未配置 link
会出现这个问题。