Docker中配置MySQL主从同步

主从同步优势

  • 实时灾备,用于故障切换
  • 读写分离,提供查询服务
  • 备份,避免影响业务

复制模式

这里搭建的是传统复制模式

master用户写入数据,生成event记到binary log中

slave接收master上传来的binlog,然后按顺序应用,重现master上的用户操作。

记录最小的单位是一个event,日志前4个字节是一个magic number,接下来19个字节记录formatt desc event:FDE

实际上还有一种基于GTID(Global Transaction ID):

  • 一个事务对应一个唯一ID
  • 一个GTID在一个服务器上只会执行一次
  • 相对于行复制来讲数据安全性更高
  • 故障切换更简单

MySQL 5.6之后开始支持

创建MySQL配置文件

我创建了一个名为 mysql_conf 的文件夹,然后在其中分别创建了名为 master 和 slave 的两个文件夹。

master 配置

在 master 文件夹中创建 master.cnf 作为 master db 的配置文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# master数据库的my.cnf
[mysqld]
# 下列2项为必须设置
server-id = 1001
log-bin = mysql-bin
default-time_zone = '+8:00'
max_allowed_packet = 8M
lower_case_table_names = 1
character_set_server = utf8mb4
max_connections = 200
max_connect_errors = 100
slow_query_log = 1
long_query_time = 1

slave 配置

在 slave 文件夹中创建 slave.cnf 作为 salve db 的配置文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# slave数据库的my.cnf
[mysqld]
# 下列2项为必须设置
server-id = 2001
log-bin = mysql-bin
default-time_zone = '+8:00'
max_allowed_packet = 8M
lower_case_table_names = 1
character_set_server = utf8mb4
max_connections = 200
max_connect_errors = 100
slow_query_log = 1
long_query_time = 1

构建镜像

拉取MySQL官方镜像

我拉取的是MySQL:5.7.22

1
docker pull mysql:5.7.22

查看已有的镜像

1
docker images

编写 Dockerfile

分别cd到 master 和 slave 两个文件夹中执行命令:

1
touch Dockerfile

会在目录下创建Dockerfile。

基础内容如下:

1
2
3
4
FROM mysql:5.7.22
COPY master.cnf /etc/mysql/
EXPOSE 3306
CMD ["mysqld"]

保存。

使用Dockerfile构建镜像

在 master 文件夹中执行:

1
docker build -t master/mysql_5_7 .

切记命令最后有个. ,代表当前目录,也可以是其他Dockerfile所在的目录

其中-t指代的是分配一个tag,指定镜像名

-f参数是显示指定Dockerfile,不使用-f,则默认将上下文路径下的名为Dockerfile的文件认为是构建镜像的”Dockerfile”。

同理 slave 的镜像构建方式也是差不多的:

1
docker build -t slave/mysql_5_7 .

创建容器运行

Docker run:

1
docker run --name mysql_master -p 3400:3306 -e MYSQL_ROOT_PASSWORD=root_pwd -d master/mysql_5_7

数据库设置

创建Slave复制用户

在master上创建专门用户同步的用户并授权:

1
GRANT REPLICATION SLAVE ON *.* TO 'username'@'%' IDENTIFIED BY 'password'

查看主容器数据库状态

1
2
3
4
5
6
7
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000004 | 87484 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)

记录mysql-bin的值和pos的值。

在这之后请不要对主库进行任何操作,不然会让bin-log更新。

配置 slave 从库

执行下面的命令给 slave 指定与 master 的同步信息

1
2
3
4
5
6
7
mysql> change master to
> master_host='172.17.0.2', //master的ip
> master_user='user_copy', //复制用户的用户名
> master_log_file='mysql-bin.000004', //主库记录的值
> master_log_pos=87484, //主库的pos值(大于等于)
> master_port=3306, //master的端口(容器的端口,而不是映射到宿主机的端口)
> master_password='password'; //当然就是主库要连接的用户的密码了

查看容器的ip:

1
docker network inspect bridge

返回的是一个JSON对象,找到其中的 Containers :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"Containers": {
"0784732aee425ab65637934de3fb939b3c44d7219b4ed7d0aeb854d79e2dc5ab": {
"Name": "mysql_slave",
"EndpointID": "30f76a98d9f6fb015312cd19e14fd4156e7b20276da2ab74a4a4e46c2b477ed1",
"MacAddress": "02:42:ac:11:00:06",
"IPv4Address": "172.17.0.6/16",
"IPv6Address": ""
},
"25762c7ddc3e363d82214f5d6d1c25785bb3596587922fe9cb127dd14f79ce3a": {
"Name": "mysql_master",
"EndpointID": "9be99efd25986f670c89c68e2e72d017e4331224acb9ef70ca80cfc7d763c8d1",
"MacAddress": "02:42:ac:11:00:05",
"IPv4Address": "172.17.0.5/16",
"IPv6Address": ""
}
}

启动主从同步

启动和停止

启动:

1
mysql> start slave

停止:

1
mysql> stop slave

查看 slave 状态

键入命令:

1
mysql> show slave status\G

\G指代将查询结果旋转90度,看起来更整齐

得到结果:

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
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.0.5
Master_User: user_copy
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 87484
Relay_Log_File: 0784732aee42-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
...
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 87484
Relay_Log_Space: 534
Until_Condition: None
...
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1001
Master_UUID: 25cb8d59-9610-11e8-800c-0242ac110005
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
...
1 row in set (0.00 sec)

重点关注

1
2
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

全部为 Yes 代表主从服务器配置完毕

其他注意

master开启二进制日志后默认记录所有库所有表的操作,可以通过配置来指定只记录指定的数据库甚至指定的表的操作,具体在mysql配置文件的[mysqld]可添加修改如下选项:

1
2
3
4
5
# 不同步哪些数据库
binlog-ignore-db = information_schema
# 只同步哪些数据库,除此之外,其他不同步
binlog-do-db = game

还有,注意到有一个名为log_slave_updates的参数,MySQL默认是OFF的。

1主1从的环境下似乎并不会有什么。

但是如果2主的话或者级联复制的情况下,会导致从库不能完全同步。需要设置为ON

参考文章