Featured image of post 在Docker中测试MySQL 8.x 主从复制

在Docker中测试MySQL 8.x 主从复制

使用Docker容器便捷测试Mysql的主备,过程还是很简单的,就是Mysql的一些设计理念需要理解一下

在Docker中测试MySQL 8.x 主从复制

最近在学习MySQL的主从复制,就闲来无事在docker里面练练手,记录一下学习过程.

Source Replication配置

拉镜像

拉默认最新版本的MySQL即可

1
 docker pull mysql

创建docker network

保证Source/Replica可以成功同步的前提是网络得通,那么第一步就是重新创建一个单独的docker network,当然默认的也可以,但是我不太喜欢大锅饭.

1
docker network create mysql_bridge #创建MySQL专用的docker网络

创建容器

我文件夹下面的mysql_01_confmysql_02_conf的MySQL配置文件,照抄即可,能自己写更好.

1
2
3
4
5
6
7
# mysql_01_conf/source.cnf
[mysqld]
server-id=1 #唯一ID
log_bin=mysql-bin#开启binlog
binlog_format=ROW#行级复制
gtid_mode=ON#开启GTID
enforce_gtid_consistency=ON #强制GTID一致性

注意哈!文件必须是.cnf结尾的.

1
2
3
4
5
6
7
# mysql_02_conf/replica.cnf 
[mysqld]
server-id=2 #唯一ID 必须和其他的server-id不一样
relay-log=relay-bin #中继日志
gtid_mode=ON #启用gtid模式,不用老的binlog+pos
enforce_gtid_consistency=ON #强制GTID一致性
read_only=ON #防止误写

我默认是只持久化配置文件,那些/var/lib/mysql我就没有同步了,毕竟是测试数据都不重要,但是生产环境还是要做好数据持久化的,bind mount或者 volume mount都可以.

1
2
 docker run -d --rm -v $PWD/mysql_01_conf:/etc/mysql/conf.d --name mysql_01 --network mysql_bridge -e MYSQL_ROOT_PASSWORD=123456 mysql #这个用来做主数据库
 docker run -d --rm -v $PWD/mysql_02_conf:/etc/mysql/conf.d --name mysql_02 --network mysql_bridge -e MYSQL_ROOT_PASSWORD=123456 mysql #这个用来做从数据库

主库(Source)

先进容器

1
docker exec -it mysql_01 mysql -uroot -p
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
create user 'repl'@'%' identified by '123456';#创建一个用于同步的用户
grant replication slave on *.* to 'repl'@'%';#给予所有数据库权限
flush privileges;

show binary log status;#查看一下
+------------------+----------+--------------+------------------+------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000003 |      198 |              |                  | 39e8fe3d-5913-11f1-a31e-3af1c8c7e730:1-5 |
+------------------+----------+--------------+------------------+------------------------------------------+

从库(Replication)

先进容器

1
docker exec -it mysql_02 mysql -uroot -p
1
2
3
4
5
change replication source to 
source_host='mysql_01',#docker创建的第一个容器名称即可
source_user='repl',
source_password='123456',
source_auto_position=1;#开启GTID自动同步,必须要开的
1
2
start replica;#开始主从备份
show replica status\G #查看一下,看到 Replica_IO_Running: Yes,Replica_SQL_Running: Yes 就是正常成功同步啦

完整步骤

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# mysql_01 Source
docker exec -it mysql_01 mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 9.7.0 MySQL Community Server - GPL

Copyright (c) 2000, 2026, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
mysql>
mysql>
mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 |       181 | No        |
| mysql-bin.000002 |   2997943 | No        |
| mysql-bin.000003 |       198 | No        |
+------------------+-----------+-----------+
3 rows in set (0.002 sec)

mysql> show binary log status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000003 |      198 |              |                  | 39e8fe3d-5913-11f1-a31e-3af1c8c7e730:1-5 |
+------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.001 sec)

mysql> create user 'repl'@'%' identified by '123456';
Query OK, 0 rows affected (0.076 sec)

mysql> grant replication slave on *.* to 'repl'@'%';
Query OK, 0 rows affected (0.017 sec)

mysql> flush privileges;
Query OK, 0 rows affected, 1 warning (0.018 sec)

mysql> show binary log status;
+------------------+----------+--------------+------------------+------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000003 |      899 |              |                  | 39e8fe3d-5913-11f1-a31e-3af1c8c7e730:1-8 |
+------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.001 sec)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# mysql_02 Replication
docker exec -it mysql_02 mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 9.7.0 MySQL Community Server - GPL

Copyright (c) 2000, 2026, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> change replication source to
    -> source_host='mysql_01',
    -> source_user='repl',
    -> source_password='123456',
    -> source_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.090 sec)

mysql> start replica;
Query OK, 0 rows affected (0.068 sec)

mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: mysql_01
                  Source_User: repl
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin.000003
          Read_Source_Log_Pos: 899
               Relay_Log_File: relay-bin.000003
                Relay_Log_Pos: 1116
        Relay_Source_Log_File: mysql-bin.000003
           Replica_IO_Running: Yes #
          Replica_SQL_Running: Yes #
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 899
              Relay_Log_Space: 2999300
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: Yes
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 1
                  Source_UUID: 39e8fe3d-5913-11f1-a31e-3af1c8c7e730
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 10
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set: 39e8fe3d-5913-11f1-a31e-3af1c8c7e730:1-8
            Executed_Gtid_Set: 39e8fe3d-5913-11f1-a31e-3af1c8c7e730:1-8,
48d2ce30-5913-11f1-aad7-7ae654cbeca4:1-5
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Source_TLS_Version:
       Source_public_key_path:
        Get_Source_public_key: 0
            Network_Namespace:
1 row in set (0.002 sec)

至此结束了,操作还是很简单的,主要还是要理解Mysql主从同步的原理.

验证

其他知识

主从复制核心日志

Source Replication
Binlog relay log

从库同步数据原理:

从库有两个重要的线程:IO和SQL,

  • IO线程负责拉取主库binlog,然后写入本地relay log
  • SQL线程执行relay log才是真正的数据同步

主从延迟:

show replica status\G查看,有时候发现Seconds_Behind_Source:60,落后主库60s,这个是正常的,有可能是

  • 大事务,一次几百万行数据
  • SQL慢,从库执行不过来
  • 锁等待,卡住
  • 单线程复制,老版本问题
  • 磁盘差,IO跟不上
  • 也可能是刻意配置的

binlog三种格式

STATEMENT

记录sql,执行SQL,哪都好,问题是:uuid(),now(),rand()大概率(99.99… …%)不一样

ROW

记录数据变化,最安全,生产环境主流。

MIXED

我不知道谁在用

生产环境重要配置

半同步复制

异步(默认):主库写完直接返回,风险点是:主库突然挂了,从库可能没同步到.

建议至少一个从库收到才返回,更安全.

常见命令:

1
2
3
4
5
6
stop replica; #停止复制
start replica; #启动复制
reset replica all;#重置复制,生产环境勿用,会导致事务报错,清空复制信息。
show variables like '%gtid%';#查看GTID
show binary logs;#查看binlog
show relaylog events;#查看relaylog

主从复制的模式

基于位置Position

是传统模式,例如:mysql-bin.000001 + pos=157,

  • binlog切换容易错
  • 恢复麻烦

很多老系统还在用。

基于GTID

MySQL8 主流方案,

  • 自动定位
  • 自动续传
  • 故障恢复方便
  • 主从切换简单

生产环境都GTID。