前言

搭建一个完全新的主从节点,非常容易,直接使用命令就行

但是,当对于一个存在业务的主节点的数据库服务器搭建主从的时候,因为主库存在数据,所以建议你先用热备工具,备份主库的数据,然后把主库的数据恢复到从库中

然后再使用命令,搭建主从

参考文献

主从原理:https://blog.mailjob.net/posts/3006260634.html

数据库热备份:https://blog.mailjob.net/posts/3523564565.html

安装mysql服务

因为我只有一个服务器,所以这里我采用docker去安装mysql服务

# 拉取 mysql 5.7 镜像
docker pull mysql:5.7

复制过程中binlog建议使用row格式,其他格式可能会造成主从数据不一致的情况

对于从服务器,最好在配置文件,配置禁止写操作

# 在宿主机 mysql1(master) 中创建配置文件, 以备后面创建配置文件映射之用
[root@VM-0-15-centos ~]# vim /data/mysql_master_slave/mysql1/conf/my.cnf
# 写入以下内容
[mysqld]
server-id=1 # 设置server_id,注意要唯一
log-bin=mysql-slave-bin # 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
character-set-server=utf8
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8

# 在宿主机 mysql2(slave) 中创建配置文件
[root@VM-0-15-centos ~]# vim /data/mysql_master_slave/mysql2/conf/my.cnf
# 写入以下内容
[mysqld]
server-id=2 # 设置server_id,注意要唯一
log-bin=mysql-slave-bin # 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
relay_log=edu-mysql-relay-bin # relay_log配置中继日志
character-set-server=utf8
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
# 创建 mysql1 容器
docker run -p 33061:3306 --name mysql1 \
-v /data/mysql_master_slave/mysql1/conf/my.cnf:/etc/mysql/my.cnf \
-v /data/mysql_master_slave/mysql1/conf:/etc/mysql \
-v /data/mysql_master_slave/mysql1/logs:/var/log/mysql \
-v /data/mysql_master_slave/mysql1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

# 创建 mysql2 容器
docker run -p 33062:3306 --name mysql2 \
-v /data/mysql_master_slave/mysql2/conf/my.cnf:/etc/mysql/my.cnf \
-v /data/mysql_master_slave/mysql2/conf:/etc/mysql \
-v /data/mysql_master_slave/mysql2/logs:/var/log/mysql \
-v /data/mysql_master_slave/mysql2/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

# 查看得到容器ip信息
[root@VM-0-15-centos ~]# docker container inspect mysql1 mysql2 | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.3",
                    "IPAddress": "172.17.0.3",
  • –name:容器名,此处命名为 mysql1 。后面我还要创建一个 mysql2 作为从节点
  • -e:配置信息,此处配置mysql的root用户的登陆密码
  • -p:端口映射,此处映射 主机3306端口 到 容器的3306端口
  • -d:后台运行容器,保证在退出终端后容器继续运行
  • -v:主机和容器的目录映射关系,":"前为主机目录,之后为容器目录

主库对从库进行账号授权

Tips:

建议在授权该账户的时候,对从库也授权同样的账号和密码,在日后用第三方工具对于数据一致性进行管理的时候,比较方便!

# 进入 mysql1 容器
docker exec -it mysql1 /bin/bash
# 连接mysql服务
mysql -uroot -proot
# 授权一个账号
mysql> GRANT REPLICATION SLAVE ON *.* to 'slave'@'%' identified by 'slave';
Query OK, 0 rows affected, 1 warning (0.00 sec)

所以依据上面的演示,我建立两个mysql服务节点

容器名称 版本 IP 端口 root账号密码 slave账号密码
mysql1(主) 5.7 172.17.0.2 33061->3306 root root slave slave
mysql2(从) 5.7 172.17.0.3 33062->3306 root root

开始搭建主从复制

查看 mysql1 (master)状态

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

配置 mysql2(slave)的从服务

mysql> change master to master_host='172.17.0.2',master_port=3306,master_user='slave',master_password='slave',master_log_file='mysqlbin.000002',master_log_pos=1061;

//启动从服务器复制功能
mysql>start slave;

查看是否配置成功

mysql> show slave status \G;

Slave_IO_Running: Yes
Slave_SQL_Running: Yes
都是yes就说明成功了

遇到的问题:

1、Slave_SQL_Running = no

请重复执行以下内容,直至 yes
mysql>stop slave;
mysql>set GLOBAL SQL_SLAVE_SKIP_COUNTER=1; # 跳过复制错误
mysql>start slave;

2、Slave_IO_Running= no

a、先开始我以为是 auto.cnf 中的 uuid 一样导致的,我用的是docker部署服务,是不是我复用容器导致的。但是我查看后,发现 uuid 并不一致,所以先排除 uuid 冲突问题

# 也可用此方法查看 uuid 情况
mysql> show variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | e9b4346e-7122-11eb-8772-0242ac110002 |
+---------------+--------------------------------------+
1 row in set (0.00 sec)

b,在从节点,查看主从信息,看到了 1236 的错误信息

mysql> show slave status \G;

Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'

c、接着我查看容器的日志,也看到了同样的错误

[root@VM-0-15-centos data]# docker logs -f mysql2

# 得到如下错误信息
2021-02-17T14:53:03.499426Z 7 [ERROR] Slave I/O for channel '': Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file', Error_code: 1236
2021-02-17T14:53:03.499432Z 7 [Note] Slave I/O thread exiting for channel '', read up to log 'mysqlbin.000002', position 1061

# 然后我这样解决
stop slave;
reset slave;
start slave;

# 非常魔幻,两个关键参数都变成了 yes ,都好了
# 查看资料得知,出现这个问题是不正常先重启数据库或者断电

可视化测试

创建数据库,创建表,添加数据,均正常同步

其他问题

1、如何查看 binlog 日志是否开启

mysql> show global variables like '%log_bin%';
+---------------------------------+--------------------------------+
| Variable_name                   | Value                          |
+---------------------------------+--------------------------------+
| log_bin                         | ON                             |
| log_bin_basename                | /var/lib/mysql/mysql-bin       |
| log_bin_index                   | /var/lib/mysql/mysql-bin.index |
| log_bin_trust_function_creators | OFF                            |
| log_bin_use_v1_row_events       | OFF                            |
+---------------------------------+--------------------------------+
5 rows in set (0.00 sec)

2、对于使用 docker 部署mysql主从的要注意

我在上面 run 容器的时候,只是指定了数据卷和配置文件,但是没有指定ip

这就存在一个问题,服务器重启或者docker重启的时候,或许会导致容器的ip发生变化,那么slave库就无法根据ip连接到master节点了

所以在用 docker 做主从的时候,要指定一个网桥,然后根据网桥给定的ip段,再给定 ip 地址,这样再重启的时候,ip信息就不会发生变化了

3、查看 server_id 情况

要求是,server_id 不同

mysql> show variables like '%server_id%';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| server_id      | 1     |
| server_id_bits | 32    |
+----------------+-------+
2 rows in set (0.00 sec)