十分钟,带你了解 MySQL 主从原理,手把手教你使用 Docker 搭建 MySQL 主从复制

mysql-logo

一、前言

项目初期,很多都是单体架构,业务代码写在一起,数据表也都在一个数据库中;

随着项目的发展,访问量越来越大、数据量越来越多,数据库大概率会首先成为性能的瓶颈;这个时候一般都会升级项目架构为读写分离,以缓解主库的压力,提高系统的性能。MySQL 的主从复制是读写分离的前提。

二、原理

MySQL 主从复制流程图

可以看到,当主库接收到客户端的更新(insert/update/delete)请求后,执行内部事务的更新逻辑,同时写 binlog。

备库 slave 跟主库 master 之间维持了一个长连接。主库 master 内部有一个线程,专门用于服务备库 slave 的这个长连接。一个事务日志同步的完整过程是这样的:

  1. 在备库 slave 上通过 change master 命令,设置主库 master 的 IP、端口、用户名、密码,以及要从哪个位置开始请求 binlog,这个位置包含文件名和日志偏移量;
  2. 在备库 slave 上执行 start slave 命令,这时候备库会启动两个线程,就是图中的 io_thread 和 sql_thread。其中 io_thread 负责与主库建立连接;
  3. 主库 master 校验完用户名、密码后,开始按照备库 slave 传过来的位置,从本地读取 binlog,发给 slave;
  4. 备库 slave 拿到 binlog 后,写到本地文件,称为中转日志(relay log);
  5. sql_thread 读取中转日志,解析出日志里的命令,并执行。这里需要说明,后来由于多线程复制方案的引入,sql_thread 演化成为了多个线程。

三、实现

以下方法是基于 Docker 搭建的 MySQL 8.0 一主两从环境。容器名分别为 mysql-master、mysql-slave1、mysql-slave2。

创建 mysql master 服务

打开命令行,使用 docker 创建 mysql master 服务:

$ docker run -p 3300:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0

进入 docker 容器:

$ docker exec -it mysql-master /bin/bash

/etc/mysql/my.cnf 文件中 [mysqld] 下添加如下配置(需安装 vim,不会的拉到最后):

[mysqld]
# 同一局域网内唯一
server-id=3300
# binlog 文件名
log-bin=master-bin
# 同步的数据库
binlog-do-db=shop
# binlog 格式 statement、mixed、row,默认为 statement,议为 mixed、row
binlog_format=row

# 身份验证插件、和主从无关
default_authentication_plugin=mysql_native_password

重启 mysql 服务(退出并重启 docker 容器):

$ exit
$ docker restart mysql-master

# 非 docker 环境用如下命令重启即可
$ service mysql restart

进入 docker 容器,登录 mysql ,在 master 数据库创建一个用户 slave,授予 REPLICATION SLAVE 和 REPLICATION CLIENT 权限,用于在主从库之间同步数据:

$ docker exec -it mysql-master /bin/bash
$ mysql -uroot -p123456
# 创建一个账号
mysql> CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.00 sec)
# 授予这个账号权限
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
Query OK, 0 rows affected (0.00 sec)
# 刷新权限
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

通过命令行 show master status 查看当前 binlog 日志的信息,后面有用:

mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 |      848 | shop         |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

创建 mysql slave1 服务

打开新的命令行,使用 docker 创建 mysql slave1 服务:

$ docker run -p 3301:3306 --name mysql-slave1 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0

进入 docker 容器:

$ docker exec -it mysql-slave1 /bin/bash

/etc/mysql/my.cnf 文件中 [mysqld] 下添加如下配置:

[mysqld]
# 同一局域网内唯一
server-id=3301
# 从库只读 (1.只读 0.读写)
read_only=1     

# 身份验证插件、和主从无关
default_authentication_plugin=mysql_native_password

重启 mysql 服务(退出并重启 docker 容器):

$ exit
$ docker restart mysql-slave1

# 非 docker 环境用如下命令重启即可
$ service mysql restart

进入 docker 容器,登录 mysql ,设置主库信息:

master_host:master 服务的地址,使用容器独立的 ip ,用 docker inspect --format='{{.NetworkSettings.IPAddress}}' mysql-master 查询

$ docker exec -it mysql-slave1 /bin/bash
$ mysql -uroot -p123456

# 设置主库信息
mysql> change master to 
master_host='172.17.0.2',         -- master mysql 服务地址 
master_port=3306,                         -- master mysql 服务端口,使用容器的端口,即:3306
master_user='slave',                     -- master mysql 提供的账号
master_password='123456',         -- master mysql 提供的密码
master_log_file='master-bin.000001',     -- master mysql 服务 show master status 的 File 字段值
master_log_pos=848,                                     -- master mysql 服务 show master status 的 Position 字段值
master_connect_retry=30;

# 开启主从复制
mysql> start slave;        

show slave status 检测是否配置成功,Slave_IO_RunningSlave_SQL_Running 为 Yes 说明配置成功:

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.17.0.2
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 30
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 848
               Relay_Log_File: 5180d9b88f01-relay-bin.000002
                Relay_Log_Pos: 325
        Relay_Master_Log_File: master-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

创建 mysql slave2 服务

再打开一个新的命令行,使用 docker 创建 mysql slave2 服务:

$ docker run -p 3302:3306 --name mysql-slave2 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0

进入 docker 容器:

$ docker exec -it mysql-slave2 /bin/bash

/etc/mysql/my.cnf 文件中 [mysqld] 下添加如下配置:

[mysqld]
# 同一局域网内唯一
server-id=3302
# 从库只读 (1.只读 0.读写)
read_only=1     

# 身份验证插件、和主从无关
default_authentication_plugin=mysql_native_password

重启 mysql 服务(退出并重启 docker 容器):

$ exit
$ docker restart mysql-slave2

# 非 docker 环境用如下命令重启即可
$ service mysql restart

进入 docker 容器,登录 mysql ,设置主库信息:

$ docker exec -it mysql-slave2 /bin/bash
$ mysql -uroot -p123456

# 设置主库信息
mysql> change master to 
master_host='172.17.0.2',         -- master mysql 服务地址 
master_port=3306,                         -- master mysql 服务端口,使用容器的端口,即:3306
master_user='slave',                     -- master mysql 提供的账号
master_password='123456',         -- master mysql 提供的密码
master_log_file='master-bin.000001',     -- master mysql 服务 show master status 的 File 字段值
master_log_pos=848,                                     -- master mysql 服务 show master status 的 Position 字段值
master_connect_retry=30;

# 开启主从复制
mysql> start slave;        

show slave status 检测是否配置成功,Slave_IO_RunningSlave_SQL_Running 为 Yes 说明配置成功:

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.17.0.2
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 30
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 848
               Relay_Log_File: e34e0c0fcd86-relay-bin.000002
                Relay_Log_Pos: 325
        Relay_Master_Log_File: master-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

创建 mysql slave N 服务

如需创建更多从库,只需更改 slave1 配置步骤中容器的端口、名称以及 server-id 即可。

测试主从复制

主从复制环境是否真正搭建成功,只需在 master 服务创建 shop 库,执行 insert/update/delete 语句,看从库是否同步这些操作即可,如果同步说明搭建成功。

四、杂记

安装 vim

$ apt-get update
$ apt-get install vim

本文首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:https://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

标签: none

不错,不错,对我有帮助! 我要打赏他!GO ->

添加新评论