ubuntu16.04基于docker搭建MySQL8.0 主从同步,搭建不成功算我的

文章目录

  • 1. 环境配置
    • 1.1 docker
    • 1.2 Ubuntu16.04
    • 1.3 MySQL版本是:8.0.16
  • 2. 两台MySQL端口配置10000和10001,确认阿里云开启
    • 2.2 为啥用10000和10001,因为3306已经开启了一个,被占用了
  • 3. 在Linux上配置两台docker的server_id等配置
    • 3.1 新建文件夹 /root/mysql/conf/master 并添加master.cnf文件
    • 3.2 新建文件夹 /root/mysql/conf/slave并添加slave.cnf文件
  • 4. docker 运行两台MySQL
    • 4.1 以10000端口运行第一台《主》,名字是:mysql-master并挂载刚才的配置文件
      • 4.1.1 注意挂载位置一定是刚才你新建配置文件master.cnf的位置
      • 4.1.2 注意MySQL版本是8.0.16并且两台MySQL的版本一定要一致
    • 4.2 以10001端口运行第2台《从》,名字是:mysql-slave并挂载刚才的配置文件
      • 4.2.1 注意两台MySQL的用户名和密码都是root
  • 5. 配置主服务器,在主服务器新建从服务器的连接账号
    • 5.1 推荐直接用下面的这个,因为两台MySQL在一台服务器上面
    • 5.2 获取主服务器相关信息,记录File和Position值
  • 6. 配置从服务器
    • 6.1 注意你的xxxIP一定是你的真实IP,不要因为两个在一台服务器,而设置成127.0.0.1
    • 6.2 MASTER_LOG_FILE 和MASTER_LOG_POS设置成刚才记录的值
  • 7. 最后一步,开启同步
    • 7.1 Slave_IO_Running: Yes Slave_SQL_Running: Yes同时YES才代表主从配置成功
    • 7.2 从库只读设置set global read_only=1
    • 8. 添加数据测试
    • 8.1 测试主从同步
    • 8.2 测试从库只读
    • 8.3 从库不小心插入数据怎么办?
      • 8.3.1 解决方案:
      • 8.3.2 问题解决后再次用主库添加数据测试
      • 8.3.3 制造从库挂掉,主库一直塞入数据的现象
      • 8.3.4 主从库数据不一样的数据太多了怎么解决,怎么解决?
  • 9. 更改MySQL8.0默认的加密方式,不然客户端连接不上
  • N 最后说下,读写分离、分库分表可以在代码层面解决

1. 环境配置

当然如果是win10搭建MySQL8.0,一条主机搭建主从也是可以的,可以参考win10搭建主从
如下是我的主服务器配置

[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
  
[mysqld]
# 设置3308端口
port = 3308
#唯一,要与从机的不同
server-id = 1
# Binary Logging.
#开启二进制日志
log-bin= mysql-bin-master
# 设置mysql的安装目录
basedir=D:\\mysql\\mysqlMaster
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
# datadir=D:\\mysql\\mysqlMaster\\data
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB

从服务器配置

[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
  
[mysqld]
# 设置3309端口
port = 3309
log-bin=mysql-bin-slave
server_id=200
# 设置mysql的安装目录
basedir=D:\\mysql\\mysqlSlave
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
# datadir=D:\\mysql\\mysqlSlave\\data
# 允许最大连接数
max_connections=20
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB

1.1 docker

1.2 Ubuntu16.04

1.3 MySQL版本是:8.0.16

2. 两台MySQL端口配置10000和10001,确认阿里云开启

2.2 为啥用10000和10001,因为3306已经开启了一个,被占用了

阿里云

3. 在Linux上配置两台docker的server_id等配置

3.1 新建文件夹 /root/mysql/conf/master 并添加master.cnf文件

[mysqld]
log-bin=mysql-bin-master  //启用二进制日志
server_id=100   //xxx代表唯一ID,默认是1。特别注意,当前版本这里是server_id而不是server-id,有些版本可能会不一样

3.2 新建文件夹 /root/mysql/conf/slave并添加slave.cnf文件

[mysqld]
log-bin=mysql-bin-slave
server_id=200

PS: 如果是在Windows上面安装的docker-desktop安装的则在自己的盘下面建两个文件夹也是可以的,比如我的是:
D:/SoftTools/docker/masterD:/SoftTools/docker/slave

4. docker 运行两台MySQL

4.1 以10000端口运行第一台《主》,名字是:mysql-master并挂载刚才的配置文件

4.1.1 注意挂载位置一定是刚才你新建配置文件master.cnf的位置

4.1.2 注意MySQL版本是8.0.16并且两台MySQL的版本一定要一致

docker run --name mysql-master -v /root/mysql/conf/master:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -p 10000:3306 -d mysql:8.0.16     --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

4.2 以10001端口运行第2台《从》,名字是:mysql-slave并挂载刚才的配置文件

4.2.1 注意两台MySQL的用户名和密码都是root

 docker run --name mysql-slave -v /root/mysql/conf/slave:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -p 10001:3306 -d   mysql:8.0.16   --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

如果是windows安装的dockers,则可以

docker run --name mysql-master -v D:/SoftTools/docker/master:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -p 10000:3306 -d mysql:8.0.16 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


docker run --name mysql-slave -v D:/SoftTools/docker/slave:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -p 10001:3306 -d mysql:8.0.16 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

5. 配置主服务器,在主服务器新建从服务器的连接账号

建议直接往下看5.1 ,这个先别用

 // 1.进入主库容器
docker exec -it mysql-master bash
// 2.登录mysql
mysql -uroot -proot
// 3.rep表示复制账号;可修改为%,代表任意的主机;`IDENTIFIED BY`后面代表rep用户的认证密码
CREATE USER 'rep'@'<salve_ip>' IDENTIFIED WITH mysql_native_password BY 'reppassword';
GRANT REPLICATION SLAVE ON *.* TO 'rep'@'<salve_ip>';

5.1 推荐直接用下面的这个,因为两台MySQL在一台服务器上面

// 1.进入主库容器
docker exec -it mysql-master bash
// 2.登录mysql
mysql -uroot -proot
// 3.rep表示复制账号;可修改为%,代表任意的主机;`IDENTIFIED BY`后面代表rep用户的认证密码
CREATE USER 'rep'@'%' IDENTIFIED WITH mysql_native_password BY 'rep';
GRANT REPLICATION SLAVE ON *.* TO 'rep'@'%';

5.2 获取主服务器相关信息,记录File和Position值

show master status;

+-------------------------+----------+--------------+------------------+-------------------+
| File                    | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------------+----------+--------------+------------------+-------------------+
| mysql-bin-master.000003 |      656 |              |                  |                   |
+-------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

6. 配置从服务器

// 1.进入从库容器
docker exec -it mysql-slave bash
// 2.登录mysql
mysql -uroot -proot

不要直接复制,先看6.1

// 3.配置主库认证信息,同上
CHANGE MASTER TO MASTER_HOST='',MASTER_PORT=10000,MASTER_USER='rep',MASTER_PASSWORD='reppassword',MASTER_LOG_FILE='',MASTER_LOG_POS=<Position>;

6.1 注意你的xxxIP一定是你的真实IP,不要因为两个在一台服务器,而设置成127.0.0.1

6.2 MASTER_LOG_FILE 和MASTER_LOG_POS设置成刚才记录的值

CHANGE MASTER TO MASTER_HOST='xxxIP',MASTER_PORT=10000,MASTER_USER='rep',MASTER_PASSWORD='rep',MASTER_LOG_FILE='mysql-bin-master.000003',MASTER_LOG_POS=656;

7. 最后一步,开启同步

 在 slave 上启动线程:start slave;

查看状态

 在 slave 上执行命令:show slave status\G;

7.1 Slave_IO_Running: Yes Slave_SQL_Running: Yes同时YES才代表主从配置成功

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 101.200.55.12
                  Master_User: rep
                  Master_Port: 10000
                Connect_Retry: 60
              Master_Log_File: mysql-bin-master.000003
          Read_Master_Log_Pos: 656
               Relay_Log_File: feb2e3f40b29-relay-bin.000002
                Relay_Log_Pos: 329
        Relay_Master_Log_File: mysql-bin-master.000003
             Slave_IO_Running: Yes
            Slave_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_Master_Log_Pos: 656
              Relay_Log_Space: 544
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 100
                  Master_UUID: 31ef5ac8-8d02-11e9-a2f6-0242ac120005
             Master_Info_File: mysql.slave_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
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
       Master_public_key_path: 
        Get_master_public_key: 0
            Network_Namespace: 
1 row in set (0.00 sec)

ERROR: 
No query specified

如果没有成功,stop slave;重新设置

7.2 从库只读设置set global read_only=1

  1. 相关命令

设置从库只读:set global read_only=1;。1表示只读,0是读写,但对拥有super权限的账号是不生效的,所以在授权账号的时候应尽量避免添加super权限
查看读写情况:show global variables like "%read_only%";
查看server_id:show variables like '%server_id%';

  1. 踩坑记录
      执行show slave status\G;,发现从库并没有连接上主库,留意到错误信息大致为:“主从库server_id不能一致”,随即查看新增的master.cnf和slave.cnf,但并没有发现问题,随即用docker logs mysql-master查看启动日志,有一行警告大概是这样的:mysql: [Warning] World-writable config file ‘/etc/mysql/conf.d/master.cnf’ is ignored.,这说明配置文件并没有挂载成功,搜索后得知当文件权限全局可写时,mysql会担心这种文件被其他用户恶意修改,所以会忽略掉这个配置文件,修改文件权限chmod 644 *.cnf后,再将以上流程重新跑了一遍,问题没有复现。

8. 添加数据测试

8.1 测试主从同步

在主库 MySQL进入之后

//创建库
create database hcg;
use hcg ;
create table one(id int(10) primary key ,name varchar(11) );
show tables;
insert into one (id ,name )values (1,'hcg');
select * form one ;
# 如下:
mysql> select * from one ;
+----+------+
| id | name |
+----+------+
|  1 | hcg  |
+----+------+
1 row in set (0.00 sec)

在从库查看是否有数据,先进入MySQL,发现数据自动同步过来了

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| hcg                |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> use hcg
Database changed
mysql> show tables ;
+---------------+
| Tables_in_hcg |
+---------------+
| one           |
+---------------+
1 row in set (0.00 sec)

mysql> select * from one;
+----+------+
| id | name |
+----+------+
|  1 | hcg  |
+----+------+
1 row in set (0.00 sec)

8.2 测试从库只读

在从库操作:发现数据添加上了

mysql> insert into one (id ,name )values (2,'slave');
Query OK, 1 row affected (0.00 sec)

mysql> select * from one;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
+----+-------+
2 rows in set (0.00 sec)

在主库查看:发现并没有同步过来

mysql> select * from one ;
+----+------+
| id | name |
+----+------+
|  1 | hcg  |
+----+------+
1 row in set (0.00 sec)
## 同时主库插入id为2的记录
mysql> insert into one (id ,name )values (2,'slave');
Query OK, 1 row affected (0.00 sec)

mysql> select * from one;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
+----+-------+
2 rows in set (0.00 sec)

这个时候查看从库同步状态,发现报错了,怎么办,怎么办?请看下面

8.3 从库不小心插入数据怎么办?

在刚才的情况下我们已经设置了从库只读,但是还要向从库中添加数据,就会导致从库同步状态报错,如下:

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 101.200.55.12
                  Master_User: rep
                  Master_Port: 10000
                Connect_Retry: 60
              Master_Log_File: mysql-bin-master.000003
          Read_Master_Log_Pos: 1910
               Relay_Log_File: feb2e3f40b29-relay-bin.000002
                Relay_Log_Pos: 1015
        Relay_Master_Log_File: mysql-bin-master.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1062
                   Last_Error: Could not execute Write_rows event on table hcg.one; Duplicate entry '2' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin-master.000003, end_log_pos 1595
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1342
              Relay_Log_Space: 1798
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 1062
               Last_SQL_Error: Could not execute Write_rows event on table hcg.one; Duplicate entry '2' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin-master.000003, end_log_pos 1595
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 100
                  Master_UUID: 31ef5ac8-8d02-11e9-a2f6-0242ac120005
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 190613 02:01:08
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
       Master_public_key_path: 
        Get_master_public_key: 0
            Network_Namespace: 
1 row in set (0.00 sec)

ERROR: 
No query specified

8.3.1 解决方案:

手动的解决方法是告诉从库slave_sql线程让他忽略掉这个错误继续执行:

set global sql_slave_skip_counter=1;
start slave;

上面的语句是告诉slave跳过当前卡住的event,然后重新起来干活。

8.3.2 问题解决后再次用主库添加数据测试

mysql> insert into one (id ,name )values (4,'slave');
Query OK, 1 row affected (0.00 sec)

mysql> select * from one ;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
|  3 | slave |
|  4 | slave |
+----+-------+
4 rows in set (0.00 sec)

从库查看是否同步了过来:

mysql> select * from one ;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
|  3 | slave |
|  4 | slave |
+----+-------+
4 rows in set (0.00 sec)

发现问题已经得到了解决,但是试想一下,如果我们刚才的错误不是一条而是多条怎么办?
或者说:不小心在从库添加了数据,导致从库挂掉了,但是这个时候我们不知道它挂掉了,我们依然向主库写入数据N天,这里我们模拟多向主库添加了3条数据为例

8.3.3 制造从库挂掉,主库一直塞入数据的现象

  1. 我们在从库中执行下面的操作
mysql> insert into one (id ,name )values (5,'slave');
Query OK, 1 row affected (0.01 sec)

mysql> select * from one;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
|  3 | slave |
|  4 | slave |
|  5 | slave |
+----+-------+
5 rows in set (0.00 sec)

mysql> show slave status\G;

## 发现从库还是正常运行的

  1. 然后我们在主库也同时插入这条id等于5的sql
mysql> insert into one (id ,name )values (5,'slave');
Query OK, 1 row affected (0.01 sec)

mysql> select * from one;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
|  3 | slave |
|  4 | slave |
|  5 | slave |
+----+-------+
5 rows in set (0.00 sec)
  1. 再次返回从库查看同步状态发现,从库挂了,但是主库依旧添加6,7,8三条数据

从库再次查看状态

mysql> show slave status\G;

## 发现从库 已经挂了

主库不理会从库,继续添加6,7,8三条数据

mysql> insert into one (id ,name )values (6,'slave');
Query OK, 1 row affected (0.00 sec)

mysql> insert into one (id ,name )values (7,'slave');
Query OK, 1 row affected (0.01 sec)

mysql> insert into one (id ,name )values (8,'slave');
Query OK, 1 row affected (0.00 sec)

mysql> select * from one ;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
|  3 | slave |
|  4 | slave |
|  5 | slave |
|  6 | slave |
|  7 | slave |
|  8 | slave |
+----+-------+
8 rows in set (0.00 sec)

8.3.4 主从库数据不一样的数据太多了怎么解决,怎么解决?

先把主库锁定FLUSH TABLES WITH READ LOCK; 不再让主库添加记录,在从库进行下面的操作:

mysql> stop  slave;
Query OK, 0 rows affected (0.00 sec)
mysql> set global sql_slave_skip_counter=1;
Query OK, 0 rows affected (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
## 发现主从同步可以了

mysql> select * from one  ;
+----+-------+
| id | name  |
+----+-------+
|  1 | hcg   |
|  2 | slave |
|  3 | slave |
|  4 | slave |
|  5 | slave |
|  6 | slave |
|  7 | slave |
|  8 | slave |
+----+-------+
8 rows in set (0.00 sec)



从库数据同步完之后,再把主库解锁 unlock tables;。因为如果主从数据差距太大,从库恢复起来要很长时间,

9. 更改MySQL8.0默认的加密方式,不然客户端连接不上

通过本地去连接远程的mysql时报错,原因时mysql8.0的加密方法变了。

mysql8.0默认采用caching_sha2_password的加密方式

第三方客户端基本都不支持这种加密方式,只有自带的命令行支持

所以需要修改加密方式。

首先进入mysql命令行

[root@localhost ~]# mysql -u root -p
    Enter password:

第一步:修改加密方式

ALTER USER 'root'@'%' IDENTIFIED BY 'root' PASSWORD EXPIRE NEVER;

第二步:重新修改密码

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root'; 

第三步:刷新(不做可能无法生效)

FLUSH PRIVILEGES;

之后可以成功连接。


N 最后说下,读写分离、分库分表可以在代码层面解决

参考连接:mybatisPlus3.x几行代码实现读写分离

你可能感兴趣的:(MySql,Docker)