前言
MySQL 的主从复制是实现应用的高性能, 高可用的基础. 对于数据库读操作较密集的应用, 通过使数据库请求负载均衡分配到不同 MySQL 服务器, 可有效减轻数据库压力. 当遇到 MySQL 单点故障中, 也能在短时间内实现故障切换. 本文就 MySQL 的内建的复制功能进行阐述.
版本
- MySQL: 5.7.17
- CentOS: 7.4.1708
- Docker: 1.13.1
概述
MySQL 复制数据流程:
主库在数据更新提交事务之前, 将事件异步记录到 binlog 二进制日志文件中, 日志记录完成后存储引擎提交本次事务
从库启动一个 I/O 线程与主库建立连接, 用来请求主库中要更新的 binlog. 这时主库创建的 binlog dump 线程, 这是二进制转储线程, 如果有新更新的事件, 就通知 I/O 线程; 当该线程转储二进制日志完成, 没有新的日志时, 该线程进入 sleep 状态.
从库的 I/O 线程接收到新的事件日志后, 保存到自己的 relay log(中继日志)中
从库的 SQL 线程读取中继日志中的事件, 并执行更新保存.
配置主从库
主库 my.cnf 配置
在主库的 my.cnf 中打开二进制日志, 并设置服务 Id.
- log-bin = MySQL-bin
- server-id = 1
注意 server-id 必须是一个唯一的数字, 必须主从不一致, 且主从库必须设置项.
从库 my.cnf 配置
- log-bin = MySQL-bin
- server-id = 2
- log-slave-updates = 1
- read-only = 1
从库也开启 log-bin,log-slave-updates 设置为从库重放中继日志时, 记录到自己的二进制日志中, 可以让从库作为其他服务器的主库, 将二进制日志转发给其他从库, 在做一主多从方案时可考虑该种方案.
Dockerfile 构建 MySQL 镜像
构建所需文件
这里 master 和 slave 文件各自保存不共用, 先创建文件夹 /usr/local/MySQL 然后在目录创建 master 和 slave 两个目录, 再各自创建 data 文件夹
data 目录用来保存数据文件的目录
Dockerfile 保存 Dockerfile 内容
init.sql 初始化数据库的 SQL
my.cnf 数据库配置文件, 配置方式上面已提到
start.sh Dockerfile 构建 MySQL 时的脚本
Dockerfile 内容
- # 利用 MySQL 镜像创建新的镜像
- FROM MySQL:5.7.17
- ENV MYSQL_ROOT_PASSWORD ytao
- COPY start.sh /MySQL/start.sh
- COPY my.cnf /etc/MySQL/my.cnf
- COPY init.sql /MySQL/init.sql
- EXPOSE 3306
- CMD ["sh", "/mysql/start.sh"]
这里的 master 和 slave 都是基于同一个镜像构建, 使用的存储引擎和其他的组件最好是同一中, 不然在复制过程中可能会出现异常.
init.sql 初始化数据
-- 创建 data_copy 数据库
- DROP DATABASE IF EXISTS `data_copy`;
- CREATE DATABASE `data_copy` /*!40100 DEFAULT CHARACTER SET utf8mb4 collate utf8mb4_general_ci */;
-- 创建 person 表
- USE `data_copy`;
- DROP TABLE IF EXISTS `person`;
- CREATE TABLE `person` (
- `id` int(32) NOT NULL,
- `name` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
创建 data_copy 数据库和 person 表.
start.sh 脚本
- #!/bin/sh
- echo '启动 mysql'
- service MySQL start
- sleep 5
- echo '初始化数据库'
- MySQL -uroot -pytao < /MySQL/init.sql
- echo '初始化完成!'
- tail -f /dev/null
构建 master 和 slave 镜像并运行容器
构建 master 镜像
docker build -t master/MySQL .
构建 slave 镜像
docker build -t slave/MySQL .
构建成功会返回 Successfuly, 或通过 docker images 命令查看镜像
使用刚构建的镜像来运行容器
- # master 容器
- docker run --name master -p 3306:3306 -v /usr/local/MySQL/master/data/:/var/lib/MySQL -d master/MySQL
- # slave 容器
- docker run --name slave -p 3307:3306 -v /usr/local/MySQL/slave/data/:/var/lib/MySQL -d slave/MySQL
指定 master 端口为 3306,slave 端口为 3307, 挂载 data 目录为保存数据的目录.
连接到数据库后验证数据库是否初始化成功
查看 log-bin 是否开启
创建复制账号
前面有提到从库 I/O 线程要与主库建立连接, 所以需要用到账号进行验证. 账号除了要有连接权限(REPLICATION CLIENT), 同时还要有复制权限(REPLICATION SLAVE).
GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO muser@'%' IDENTIFIED BY 'ytao';
这里设置的访问地址是开放的, 实际使用过程中安全起见一定要指定访问地址.
从库启动复制
从库连接到主库, 获取到二进制日志后重放. 这里首先要配置上面创建的账号进行连接, 使用命令进行相应的设置.
- CHANGE MASTER TO
- MASTER_HOST = '47.107.xx.xxx',
- MASTER_PORT = 3306,
- MASTER_USER = 'muser',
- MASTER_PASSWORD = 'ytao',
- MASTER_LOG_FILE = 'mysql-bin.000006';
到这里复制还没有启动, 需要再从库中启动
START SLAVE;
使用 SHOW SLAVE STATUS\G; 命令查看启动后的情况
上面标记的输出信息 Slave_IO_Running: Yes 和 Slave_SQL_Running: Yes 可以看到 I/O 线程和 SQL 线程已启动运行中.
测试同步数据
如果在主库中添加, 更新或删除一个数据, 那么从库中应该也有与主库对应的数据变化.
向主库添加一条数据
INSERT INTO `data_copy`.`person` (`id`, `name`) VALUES ('1', 'ytao');
查询从库数据, 数据已被同步过来.
总结
上述是最简单最基本的配置, 但是理解上面的配置过程, 就可以根据自身情况定制不同方案, 实现一主多从, 主主复制 (主动 - 主动或主动 - 被动模式) 等等来满足自身需求.
MySQL 的复制虽然使用简单方便, 但也伴随着一些问题需要我们在使用中进行解决, 比如: 不能从服务器异常停止中恢复, 数据同步的延迟等等, 还好现在遇到的大部分问题在行业中已得到相应的解决. 对这方面感兴趣的可以去了解下现在解决这些问题的中间件实现方案.
来源: http://www.linuxidc.com/Linux/2019-11/161421.htm