mysql主从,gtid和binlog以及只读模式高可用实战(I)

理论:mysql主从,高可用复制原理(I)_Michaelwubo的博客-CSDN博客

数据库主从同步配置是开发中比较常见的需求,在MySql里,主从同步主要有两种,bin-log和gtid。下面就主要总结一下使用GTID模式配置主从同步的过程。

  • 全局事务标识:global transaction identifiers;
  • GTID是一个事务一一对应,并且全局唯一ID;
  • 一个GTID在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致;
  • GTID用来代替传统复制方法,不再使用MASTER_LOG_FILE+MASTER_LOG_POS开启复制。而是使用MASTER_AUTO_POSTION=1的方式开始复制;
  • MySQL-5.6.5开始支持的,MySQL-5.6.10后开始完善;
  • 在传统的slave端,binlog是不用开启的,但是在GTID中slave端的binlog是必须开启的,目的是记录执行过的GTID(强制)。

  • GTID = source_id:transaction_id
  • source_id,用于鉴别原服务器,即mysql服务器唯一的的server_uuid,由于GTID会传递到slave,所以也可以理解为源ID。
  • transaction_id,为当前服务器上已提交事务的一个序列号,通常从1开始自增长的序列,一个数值对应一个事务。
  • 示例:3E11FA47-71CA-11E1-9E33-C80AA9429562:23  。前面的一串为服务器的server_uuid,即3E11FA47-71CA-11E1-9E33-C80AA9429562,后面的23为transaction_id
  • 更简单的实现failover,不用以前那样在需要找log_file和log_pos;
  • 更简单的搭建主从复制;
  • 比传统的复制更加安全;
  • GTID是连续的没有空洞的,保证数据的一致性,零丢失。

1 环境 

master:172.16.10.1

slave:192.168.1.36

mysql version:5.7.35

2 主从配置:

bin-log 方式:

2.1 主配置

2.1.1 master 172.16.10.1:

[root@localhost mysql]# cat /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

max_binlog_size = 100m //binlog每个日志文件大小
binlog_cache_size = 4m //binlog缓存大小
max_binlog_cache_size = 512m //最大binlog缓存大小

#关闭查询缓存提高效率
query_cache_type=OFF

#lower_case_table_names=1 #忽略大小写
server-id=1 #服务器id (主从必须不一样),爱写啥写啥,别太离谱就行
log-bin=master-bin  #打开日志(主机需要打开),这个mysql-bin也可以自定义,这里也可以加上路径
#作为主机的配置
lower_case_table_names=1
server-id=1
binlog-format=ROW 
binlog-do-db=test#要给从机同步的库,如果是多个库,可以写多个命令
binlog-do-db=test1
#指定某些库无需同步
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
expire_logs_days=7  #自动清理 7 天前的log文件,可根据需要修改

下面展示如何在mysql实例层设置该参数值:
设置为statement格式:
mysql> set global binlog_format=statement;
Query OK, 0 rows affected (0.00 sec)
设置为mixed格式:
mysql> set global binlog_format=mixed;
Query OK, 0 rows affected (0.00 sec)
设置为row格式:
mysql> set global binlog_format=row;
Query OK, 0 rows affected (0.00 sec)
注意:重启MYSQL实例后该设置将失效,永久设置则通过mysql参数文件进行修改。

MySQL的复制是利用二进制日志binlog实现主从之间的数据同步。binlog日志的格式分为三种,使用参数binlog_format控制binlog的格式,该参数的不同值代表不同的日志格式,三种日志格式对应三种主从复制模式:
1. 语句复制模式(Statement Based Replication,SBR):基于实际执行的SQL语句的复制模式,该复制模式简单实现了数据同步,但在执行跨库更新等SQL语句时容易出现主从库的数据不一致问题。
2. 记录复制模式(Row Based Replication,RBR):基于修改的行的复制模式。不再简单记录SQL语句的执行顺序,而是逐行记录存储引擎的数据是如何变更的,主从库的数据一致性保障得到大幅度提升,是当前各生产环境常用的一种复制模式,该方式更安全。
3. 混合复制模式(Mixed Based Replication):简称MBR,根据SQL语句的不同来判断是否需要使用row格式,当出现可能造成主从库数据不一致的SQL语句时(例如:用户自定义函数、跨库SQL语句等),binlog自动转为row格式记录。

4.对于执行的SQL语句中包含now()这样的时间函数,会在日志中产生对应的unix_timestamp()*1000的时间字符串,slave在完成同步时,取用的是sqlEvent发生的时间来保证数据的准确性。另外对于一些功能性函数slave能完成相应的数据同步,而对于上面指定的一些类似于UDF函数,导致Slave无法知晓的情况,则会采用ROW格式存储这些Binlog,以保证产生的Binlog可以供Slave完成数据同步。

现在来比较以下 SBR 和 RBR 2中模式各自的优缺点:

SBR 的优点:

历史悠久,技术成熟

binlog文件较小

binlog中包含了所有数据库更改信息,可以据此来审核数据库的安全等情况

binlog可以用于实时的还原,而不仅仅用于复制

主从版本可以不一样,从服务器版本可以比主服务器版本高

SBR 的缺点:

不是所有的UPDATE语句都能被复制,尤其是包含不确定操作的时候。

调用具有不确定因素的 UDF 时复制也可能出问题

使用以下函数的语句也无法被复制:

* LOAD_FILE()

* UUID()

* USER()

* FOUND_ROWS()

* SYSDATE() (除非启动时启用了 --sysdate-is-now 选项)

INSERT ... SELECT 会产生比 RBR 更多的行级锁

复制需要进行全表扫描(WHERE 语句中没有使用到索引)的 UPDATE 时,需要比 RBR 请求更多的行级锁

对于有 AUTO_INCREMENT 字段的 InnoDB表而言,INSERT 语句会阻塞其他 INSERT 语句

对于一些复杂的语句,在从服务器上的耗资源情况会更严重,而 RBR 模式下,只会对那个发生变化的记录产生影响

存储函数(不是存储过程)在被调用的同时也会执行一次 NOW() 函数,这个可以说是坏事也可能是好事

确定了的 UDF 也需要在从服务器上执行

数据表必须几乎和主服务器保持一致才行,否则可能会导致复制出错

执行复杂语句如果出错的话,会消耗更多资源

RBR 的优点:

任何情况都可以被复制,这对复制来说是最安全可靠的

和其他大多数数据库系统的复制技术一样

多数情况下,从服务器上的表如果有主键的话,复制就会快了很多

复制以下几种语句时的行锁更少:

* INSERT ... SELECT

* 包含 AUTO_INCREMENT 字段的 INSERT

* 没有附带条件或者并没有修改很多记录的 UPDATE 或 DELETE 语句

执行 INSERT,UPDATE,DELETE 语句时锁更少

从服务器上采用多线程来执行复制成为可能

RBR 的缺点:

binlog 大了很多

复杂的回滚时 binlog 中会包含大量的数据

主服务器上执行 UPDATE 语句时,所有发生变化的记录都会写到 binlog 中,而 SBR 只会写一次,这会导致频繁发生 binlog 的并发写问题

UDF 产生的大 BLOB 值会导致复制变慢

无法从 binlog 中看到都复制了写什么语句

当在非事务表上执行一段堆积的SQL语句时,最好采用 SBR 模式,否则很容易导致主从服务器的数据不一致情况发生

另外,针对系统库 mysql 里面的表发生变化时的处理规则如下:

如果是采用 INSERT,UPDATE,DELETE 直接操作表的情况,则日志格式根据 binlog_format 的设定而记录

如果是采用 GRANT,REVOKE,SET PASSWORD 等管理语句来做的话,那么无论如何都采用 SBR 模式记录

注:采用 RBR 模式后,能解决很多原先出现的主键重复问题。
 


mysql> show global variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.08 sec)


 

2.1.2 重启 master

[root@localhost mysql]# systemctl restart mysqld

2.1.3 通过登录命令进入主数据库

#测试是否开启成功

mysql> show variables like  "%log_bin%";
+---------------------------------+---------------------------------+
| Variable_name                   | Value                           |
+---------------------------------+---------------------------------+
| log_bin                         | ON                              |
| log_bin_basename                | /var/lib/mysql/master-bin       |
| log_bin_index                   | /var/lib/mysql/master-bin.index |
| log_bin_trust_function_creators | OFF                             |
| log_bin_use_v1_row_events       | OFF                             |
| sql_log_bin                     | ON                              |
+---------------------------------+---------------------------------+
6 rows in set (0.01 sec)

2.1.4 我忽略了,我用主库的root用户和密码(也可以专门创建一个账户用来同步的)。创建从数据库访问主数据库的帐号,用于获取数据内容 

-- % 可以修改成指定IP进行访问,如果是多个从库需要配置%
grant replication slave on *.* to '帐号'@'%' identified by '密码';
mysql> select user,host from mysql.user;
#查询当前Mysql用户信息
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+

mysql> GRANT REPLICATION SLAVE ON *.* TO 'sync'@'172.16.10.%' IDENTIFIED BY '123456';
#授权 REPLICATION SLAVE 为同步权限 *.* 指所有库中所有表 sync为用户名 172.16.10.% 可以登录的主机网段
Query OK, 0 rows affected, 1 warning (0.10 sec)

mysql>  show grants for 'sync'@'172.16.10.%';
#查看权限
+----------------------------------------------------------+
| Grants for [email protected].%                            |
+----------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO 'sync'@'172.16.10.%' |
+----------------------------------------------------------+
1 row in set (0.00 sec)

#如果授权错误,删除用户即可
#mysql> delete from mysql.user where user='sync';
mysql> quit
Bye


FLUSH PRIVILEGES; -- 刷新

2.1.5 获取主数据库同步状态 

mysql> show master status\G
*************************** 1. row ***************************
             File: master-bin.000001
         Position: 154
     Binlog_Do_DB: test,test1
 Binlog_Ignore_DB: mysql,performance_schema,information_schema,sys
Executed_Gtid_Set: 
1 row in set (0.00 sec)

2.2 从库配置: 不需要开启binlog功能,除非这个从也有自己的slave 属于级联方式

2.2.1 slave  192.168.1.36:

[root@test-36 mysql]# cat /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

lower_case_table_names = 1
server-id=2
slave_skip_errors=1146,2003
#slave_skip_errors=2003

#read_only = 1
#super_read_only = 1

2.2.2 重启服务

[root@test-36 mysql]# systemctl restart mysqld

 2.2.3 通过登录命令进入从数据库,配置主数据库的登录信息,用于获取数据

change master to master_host='172.16.10.1',master_port=3306,master_user='root',master_password='123456aA',master_log_file='master-bin.000001',master_log_pos=154;


-- 根据主数据库状态中的日志File填写 #在主中的目录查看 ls -al /var/lib/mysql
-- 根据主数据库状态中的Position填写 在主中show master status\G 查看



2.2.4: 查看savle状态:

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 154
               Relay_Log_File: test-36-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: master-bin.000001
             Slave_IO_Running: No
            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: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 154
              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: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 0
                  Master_UUID: 
             Master_Info_File: /var/lib/mysql/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: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified

发现此时IO的两个线程还是NO状态(Slave_IO_RUNNING和Slave_SQL_RUNNING)

2.2.5 启动从数据库同步命令

mysql> start slave;
ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository

解决办法:在start slave之前,先启用reset slave

mysql> reset slave;

 2.2.6 再次查看:两个IO线程已经启动ok

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 154
               Relay_Log_File: test-36-relay-bin.000003
                Relay_Log_Pos: 369
        Relay_Master_Log_File: master-bin.000001
             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: 154
              Relay_Log_Space: 578
              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: 1
                  Master_UUID: 02376f51-1473-11ed-8e95-005056b93c30
             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
                  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: 
1 row in set (0.00 sec)

ERROR: 
No query specified

可能出现的错误,需要用到的命令(可能需要关闭同步)

-- server id冲突
set global server_id=8;

-- 解决日志冲突
change master to master_log_file='mysql-bin.000001',master_log_pos=154;

-- 拨针,跳过这一个错误
SET GLOBAL sql_slave_skip_counter =10;

3. 测试一下

第一次数据量很大:

1)可以锁表,不让数据写入

flush tables with read lock;

2)记录下二进制日志文件名和位置

mysql> show master status\G;
*************************** 1. row ***************************
             File: master-bin.000001
         Position: 1022
     Binlog_Do_DB: test,test1
 Binlog_Ignore_DB: mysql,performance_schema,information_schema,sys
Executed_Gtid_Set: 
1 row in set (0.00 sec)

ERROR: 
No query specified

3)备份数据库:

  在master上执行

mysqldump -uroot -p test > back.sql;

4)把备份好的数据拷贝到从服务器scp back.sql xxxx:~

 5)配置从(slave)

把主服务器备份的数据导入从服务器

在slave上执行

 mysqldump -uroot -p test< back.sql

vi /etc/my.cnf

修改或增加:

server-id=2 #这个数值不能和主一样

可选参数(2选1,这两个参数设置成和主一样):

接下来就是下面的操作了:

3.1 master 172.16.10.1 数据库情况:

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

3.2 slave  192.168.1.36 数据库情况:

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

此时是一样的

3.3 在master 创建数据库插入数据

mysql> create database test;
mysql> use test;
mysql> create table jettech01(id int,name char);
Query OK, 0 rows affected (0.00 sec)

mysql> insert into jettech01 value(1,'a');
Query OK, 1 row affected (0.00 sec)

mysql> insert into jettech01 value(2,'b');
Query OK, 1 row affected (0.01 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
+------+------+
2 rows in set (0.00 sec)

3.4  在slave 节点观察同步情况:

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

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| jettech01      |
+----------------+
1 row in set (0.00 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
+------+------+
2 rows in set (0.00 sec)

说明同步成功.提示:单向主从仅支持主写,主从读,如在从写,则不会同步到主!!!双向的要搭建互为主从,以后写~

gtid 方式:

  • GTID使用master_auto_position=1来替代binlog 和position来搭建主从复制,更方便
  • GTID可以知道事务最开始是在那个实例上提交的
  • GTID方便实现主从间的failover

主从精简配置:

主库配置:
gtid_mode=on
enforce_gtid_consistency=on
log_bin=on
#STATEMENT,ROW,MIXED
binlog_format=row
server_id 不能和从库一样
从库配置:
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=1

虽然log_slave_updates在mysql5.7之后可以关闭,使用gtid_executed这张表,但是还是建议在从库中开启(万一需要从 从库继续向下一级从库同步数据)。如果需要将从库作为主库继续向下传递数据我们还需要继续在从库上添加下面两项配置log_bin=on 和binlog_format=row 另外server_id 和主库不一样 

1.master配置:在上面的配置多加如下:

# GTID模式
gtid_mode=on
enforce-gtid-consistency=true

# 半同步模式,无数据丢失AFTER_SYNC模式

#rpl_semi_sync_master_enabled=1

#rpl_semi_sync_master_timeout=1000

#rpl_semi_sync_master_wait_point=AFTER_SYNC
# binlog
# log_slave_updates允许下端接入slave

log_slave_updates=1

log_bin = master-bin

binlog_format = row

expire_logs_days = 7

登录mysql控制台mysql -uroot -p执行# 安装主库半同步复制插

install plugin rpl_semi_sync_master soname 'semisync_master.so';

# 检查安装
show global variables like 'rpl%';

flush privileges;

2. slave:在上面的配置多加如下:

# GTID模式
gtid_mode=on
enforce-gtid-consistency=true

# 半同步模式,无数据丢失AFTER_SYNC模式,从库

read_only=1

skip_slave_start=1

relay_log_recovery=1

rpl_semi_sync_slave_enabled=1

# binlog

# log_slave_updates允许下端接入slave

log_slave_updates=1

登录mysql控制台mysql -uroot -p执行# 安装从库半同步复制插件

INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

 3 从库设置要同步的主库信息

CHANGE MASTER TO MASTER_HOST='ip',MASTER_USER='用户名',MASTER_PASSWORD='密码',MASTER_AUTO_POSITION=1;


change master to master_host='172.16.10.1',master_port=3306,master_user='root',master_password='123456aA',master_auto_position=1;

4 开启同步

start slave;

5 查看状态。

show slave status\G;

配置完之后,通过查看slave的状态,可以看是否配置成功。同时可以在主库进行一些操作,提交一些事务(insert,update),之后数据就会自动同步到从库。

异常问题解决

由于某些原因导致了复制失败、异常、或者需要重置从库复制功能

登录从库的mysql控制台执行# 先关闭从库复制

stop slave;

# 重置主库

reset master;

# 重置从库

reset slave;

# 开启从库复制

start slave;

重置主库

登录主库的mysql控制台执行# 重置主库

reset master;
============================================

6 只读模式read_only,锁表 flush tables with read lock;

 6.1  在mysql数据库中,在进行数据迁移和从库只读状态设置时,都会涉及到只读状态和Master-slave的设置和关系。

 6.2 经过实际测试,对于MySQL单实例数据库和master库,如果需要设置为只读状态,需要进行如下操作和设置:

6.3 将MySQL设置为只读状态的命令:

# mysql -uroot -p

mysql> show global variables like "%read_only%";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_read_only      | OFF   |
| read_only             | OFF   |
| super_read_only       | OFF   |
| transaction_read_only | OFF   |
| tx_read_only          | OFF   |
+-----------------------+-------+
5 rows in set (0.01 sec)

mysql>flush tables with read lock;

mysql> set global read_only=1;

mysql> show global variables like "%read_only%";

6.4 将MySQL从只读设置为读写状态的命令:

mysql> unlock tables;

mysql> set global read_only=0;

6.5 对于需要保证master-slave主从同步的salve库,如果要设置为只读状态,需要执行的命令为:

mysql> set global read_only=1;

6.6 将salve库从只读状态变为读写状态,需要执行的命令是:

mysql>set global read_only=0;

6.7 注意:

     对于数据库读写状态,主要靠 “read_only”全局参数来设定;默认情况下,数据库是用于读写操作的,所以read_only参数也是0或faluse状态,这时候不论是本地用户还是远程访问数据库的用户,都可以进行读写操作;如需设置为只读状态,将该read_only参数设置为1或TRUE状态,但设置 read_only=1 状态有两个需要注意的地方:

1.read_only=1只读模式,不会影响slave同步复制的功能,所以在MySQL slave库中设定了read_only=1后,通过 show slave status\G 命令查看salve状态,可以看到salve仍然会读取master上的日志,并且在slave库中应用日志,保证主从数据库同步一致;

2.read_only=1只读模式,可以限定普通用户进行数据修改的操作,但不会限定具有super权限的用户的数据修改操作;在MySQL中设置read_only=1后,普通的应用用户进行insert、update、delete等会产生数据变化的DML操作时,都会报出数据库处于只读模式不能发生数据变化的错误,但具有super权限的用户,例如在本地或远程通过root用户登录到数据库,还是可以进行数据变化的DML操作;

为了确保所有用户,包括具有super权限的用户也不能进行读写操作,就需要执行给所有的表加读锁的命令 “flush tables with read lock;”,这样使用具有super权限的用户登录数据库,想要发生数据变化的操作时,也会提示表被锁定不能修改的报错。

这样通过 设置“read_only=1”和“flush tables with read lock;”两条命令,就可以确保数据库处于只读模式,不会发生任何数据改变,在MySQL进行数据库迁移时,限定master主库不能有任何数据变化,就可以通过这种方式来设定。

但同时由于加表锁的命令对数据库表限定非常严格,如果再slave从库上执行这个命令后,slave库可以从master读取binlog日志也就是同步过来了IO线程起作用了,但不能够应用日志也即是SQL线程不可以执行,slave库不能发生数据改变,当然也不能够实现主从同步了,这时如果使用 “unlock tables;”解除全局的表读锁,slave就会应用从master读取到的binlog日志,继续保证主从库数据库一致同步。

为了保证主从同步可以一直进行,在slave库上要保证具有super权限的root等用户只能在本地登录,不会发生数据变化,其他远程连接的应用用户只按需分配为select,insert,update,delete等权限,保证没有super权限,则只需要将salve设定“read_only=1”模式,即可保证主从同步,又可以实现从库只读。

6.8 相对的,设定“read_only=1”只读模式开启的解锁命令为设定“read_only=0”;设定全局锁“flush tables with read lock;”,对应的解锁模式命令为:“unlock tables;”.

当然设定了read_only=1后,所有的select查询操作都是可以正常进行的
 

6.9 测试一下:read_only 和flush tables with read lock;

6.9.1 从库slave只设置:read_only,目前状态

mysql> show global variables like "%read_only%";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_read_only      | OFF   |
| read_only             | OFF   |
| super_read_only       | OFF   |
| transaction_read_only | OFF   |
| tx_read_only          | OFF   |
+-----------------------+-------+
5 rows in set (0.00 sec)

6.9.2 修改slave只读模式

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

mysql> show global variables like "%read_only%";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_read_only      | OFF   |
| read_only             | ON    |
| super_read_only       | OFF   |
| transaction_read_only | OFF   |
| tx_read_only          | OFF   |
+-----------------------+-------+
5 rows in set (0.00 sec)

6.9.3 查看数据:

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+
3 rows in set (0.00 sec)

6.9.4 在master节点插入数据

mysql> insert into jettech01 value(5,'e');
Query OK, 1 row affected (0.00 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
|    5 | e    |
+------+------+
4 rows in set (0.00 sec)

6.9.5 在slave查看是否同步

mysql> 
mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
|    5 | e    |
+------+------+
4 rows in set (0.00 sec)

结论:从库slave只设置:read_only是可以继续同步数据的

6.9.6  从库slave只设置:read_only且flush tables with read lock; 

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

mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

数据情况:

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
|    5 | e    |
+------+------+
4 rows in set (0.00 se

6.9.7 主master 插入数据

mysql> insert into jettech01 value(6,'f');
Query OK, 1 row affected (0.00 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
|    5 | e    |
|    6 | f    |
+------+------+
5 rows in set (0.00 sec)

 6.9.8 查看从数据没哟变化

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
|    5 | e    |
+------+------+
4 rows in set (0.00 sec)

结论:不能同步数据。关闭之后就立刻同步

mysql> unlock tables ;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
|    5 | e    |
|    6 | f    |
+------+------+
5 rows in set (0.00 sec)

=========================

master->slave->slave案例

master(172.16.1.1):

1)配置

root@localhost mysql]# cat /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid


lower_case_table_names=1
server-id=1
log-bin=master-bin
binlog-format=ROW
binlog-do-db=test
binlog-do-db=test1
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
binlog-ignore-db=information_schema
binlog-ignore-db=sys
expire_logs_days=7

gtid_mode=on
enforce-gtid-consistency=true
log_slave_updates=1

2)造数据:

mysql> create database test;
mysql> create table jettech01(id int,name char);
mysql> insert into jettech01 value(1,'a');

3)slave01(192.168.1.36) 配置:

[root@localhost mysql]# cat /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

lower_case_table_names = 1


server-id=2
log-bin=slave36-bin
binlog-format=ROW
binlog-do-db=test
binlog-do-db=test1
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
binlog-ignore-db=information_schema
binlog-ignore-db=sys
expire_logs_days=7

slave_skip_errors=1146,2003
#slave_skip_errors=2003

gtid_mode=on
enforce-gtid-consistency=true
log_slave_updates=1

4)同步:

reset slave

change master to master_host='172.16.10.1',master_port=3306,master_user='root',master_password='123456aA',master_auto_position=1;

5)查看同步数据:

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

6)slave02(172.16.10.5) 配置:

[root@localhost mysql]# cat /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=3
log-bin=slave5-bin
binlog-format=ROW
binlog-do-db=test
binlog-do-db=test1
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
binlog-ignore-db=information_schema
binlog-ignore-db=sys
expire_logs_days=7

slave_skip_errors=1146,2003

gtid_mode=on
enforce-gtid-consistency=true
log_slave_updates=1

7) 同步

reset slave

change master to master_host='192.168.1.36',master_port=3306,master_user='root',master_password='123456aA',master_auto_position=1;

8) 查看数据:

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

可能出现的问题:mysql gtid 不一致

   主从切换之后,新从库同步复制新主库产生报错1236,从库请求的gtid不在主库现有的binlog日志里。
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 192.168.1.36
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: 
          Read_Master_Log_Pos: 4
               Relay_Log_File: localhost-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: 
             Slave_IO_Running: No
            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: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 0
              Relay_Log_Space: 154
              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: 1236
                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires. Replicate the missing transactions from elsewhere, or provision a new slave from backup. Consider increasing the master's binary log expiration period. The GTID set sent by the slave is '', and the missing transactions are '02376f51-1473-11ed-8e95-005056b93c30:1-3,
244c310f-14ab-11ed-8230-005056b9e62b:1'.'
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
                  Master_UUID: 244c310f-14ab-11ed-8230-005056b9e62b
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 220808 08:33:24
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 

问题分析:

        造成该问题的原因为,从库之前执行过命令导致产生了新的gtid,并且该gtid所在的binlog已经被清理,导致发生主从切换之后,新从库同步复制新主库时,由于master_auto_position=1模式下,从库会将当前已经执行过的gtid集合发送给主库,主库接收到从库发送的gtid集合后,会与当前已经执行的gtid求差值,并将没有执行过的gtid发送给备库,由于binlog被清理导致无法将gtid发送给从库(gtid_purged没有包含)

问题解决:

        1 在新从库手动跳过缺失的gtid(注:跳过缺失的gtid,意味着不在从库执行缺失的事务,可能导致数据的丢失)
 获取新主库的gtid_purged: 21395c77-16b5-11ed-b628-005056b93c30:1-9

master(172.16.10.1)执行:

1)

stop slave;
show global variables like '%gtid_purged%' ;
show global variables like 'server_uuid';
 或

mysql> show master status \G;
*************************** 1. row ***************************
             File: master-bin.000003
         Position: 2359
     Binlog_Do_DB: test,test1
 Binlog_Ignore_DB: mysql,performance_schema,information_schema,sys
Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-9
1 row in set (0.00 sec)

ERROR: 
No query specified

在slave(192.168.1.36 节点)

1)获取新从库的execute_gtud: 21395c77-16b5-11ed-b628-005056b93c30:1-7

mysql> stop slave;
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000003
          Read_Master_Log_Pos: 1829
               Relay_Log_File: localhost-relay-bin.000004
                Relay_Log_Pos: 722
        Relay_Master_Log_File: master-bin.000003
             Slave_IO_Running: No
            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: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1829
              Relay_Log_Space: 2558
              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: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 21395c77-16b5-11ed-b628-005056b93c30
             Master_Info_File: /var/lib/mysql/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: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-7
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-7,
a597f4d4-d0c5-11ec-8444-005056b9e62b:1-3
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

mysql> show global variables like '%gtid_executed%';
+----------------------------------+------------------------------------------------------------------------------------+
| Variable_name                    | Value                                                                              |
+----------------------------------+------------------------------------------------------------------------------------+
| gtid_executed                    | 21395c77-16b5-11ed-b628-005056b93c30:1-7,
a597f4d4-d0c5-11ec-8444-005056b9e62b:1-3 |
| gtid_executed_compression_period | 1000                                                                               |
+----------------------------------+------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

 2)计算出缺失的gtid: 21395c77-16b5-11ed-b628-005056b93c30:7-8,

mysql> select GTID_SUBTRACT('21395c77-16b5-11ed-b628-005056b93c30:1-9','21395c77-16b5-11ed-b628-005056b93c30:1-7');
+------------------------------------------------------------------------------------------------------+
| GTID_SUBTRACT('21395c77-16b5-11ed-b628-005056b93c30:1-9','21395c77-16b5-11ed-b628-005056b93c30:1-7') |
+------------------------------------------------------------------------------------------------------+
| 21395c77-16b5-11ed-b628-005056b93c30:8-9                                                             |
+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

3) 手动跳过gtid:21395c77-16b5-11ed-b628-005056b93c30:7


mysql> set gtid_next='21395c77-16b5-11ed-b628-005056b93c30:7';
Query OK, 0 rows affected (0.00 sec)

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

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

4)手动跳过gtid:21395c77-16b5-11ed-b628-005056b93c30:8

mysql> set gtid_next='21395c77-16b5-11ed-b628-005056b93c30:8';
Query OK, 0 rows affected (0.00 sec)

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

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

5) 设置gtid_next为automatic,启动复制进程恢复同步

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

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000003
          Read_Master_Log_Pos: 2359
               Relay_Log_File: localhost-relay-bin.000005
                Relay_Log_Pos: 722
        Relay_Master_Log_File: master-bin.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: 2359
              Relay_Log_Space: 1501
              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: 1
                  Master_UUID: 21395c77-16b5-11ed-b628-005056b93c30
             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
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-7:9
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-9,
a597f4d4-d0c5-11ec-8444-005056b9e62b:1-3
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

6) 从备份binlog里面恢复slave 192.168.1.36

      将binlog从备份里面恢复到原来的日志目录(需要的binlog要从第一个包含缺失的gtid日志到当前的全部日志) 比如之前的bin-log 备份到哪里了 就从哪里copy 到 /var/lib/mysql 下面 cp -a /tmp/mysql/bin-log/xxxx  /var/lib/mysql

[root@localhost mysql]# ls -al  localhost-relay-bin.*
-rw-r-----. 1 mysql mysql  779 5月  11 09:55 localhost-relay-bin.000004
-rw-r-----. 1 mysql mysql 1252 5月  11 09:58 localhost-relay-bin.000005
-rw-r-----. 1 mysql mysql   58 5月  11 09:55 localhost-relay-bin.index
[root@localhost mysql]# cat localhost-relay-bin.index 
./localhost-relay-bin.000004
./localhost-relay-bin.000005

7)手动修改日志文件index,添加恢复的binlog,从头追加写入 

[root@localhost mysql]# cat localhost-relay-bin.index 
./localhost-relay-bin.000004
./localhost-relay-bin.000005
./localhost-relay-bin.000006

8)刷新新主库binlog日志

mysql> flush binary logs;
Query OK, 0 rows affected (0.00 sec)

mysql> show binary logs;
+--------------------+-----------+
| Log_name           | File_size |
+--------------------+-----------+
| slave36-bin.000001 |       177 |
| slave36-bin.000002 |       177 |
| slave36-bin.000003 |      3593 |
| slave36-bin.000004 |       283 |
| slave36-bin.000005 |       283 |
| slave36-bin.000006 |       234 |
+--------------------+-----------+
6 rows in set (0.00 sec)

9)重启新主库,让gtid_purged重新读取到最旧的binlog文件

mysql> show global variables like "%gtid%";
+----------------------------------+-------------------------------------------------------------------------------------+
| Variable_name                    | Value                                                                               |
+----------------------------------+-------------------------------------------------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                                                                  |
| enforce_gtid_consistency         | ON                                                                                  |
| gtid_executed                    | 21395c77-16b5-11ed-b628-005056b93c30:1-11,
a597f4d4-d0c5-11ec-8444-005056b9e62b:1-4 |
| gtid_executed_compression_period | 1000                                                                                |
| gtid_mode                        | ON                                                                                  |
| gtid_owned                       |                                                                                     |
| gtid_purged                      |                                                                                     |
| session_track_gtids              | OFF                                                                                 |
+----------------------------------+-------------------------------------------------------------------------------------+
8 rows in set (0.00 sec)

10)新从库重新恢复复制 


start slave
show slave status\G

3 重置gtid进行恢复

通过重置新从库的execute_gtid,跳过缺失的gtid进行恢复(注:跳过缺失的gtid,意味着不在从库执行缺失的事务,可能导致数据的丢失)

        备份记录当前的gtid值

mysql> show global variables like '%gtid%';
+----------------------------------+-------------------------------------------------------------------------------------+
| Variable_name                    | Value                                                                               |
+----------------------------------+-------------------------------------------------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                                                                  |
| enforce_gtid_consistency         | ON                                                                                  |
| gtid_executed                    | 21395c77-16b5-11ed-b628-005056b93c30:1-11,
a597f4d4-d0c5-11ec-8444-005056b9e62b:1-4 |
| gtid_executed_compression_period | 1000                                                                                |
| gtid_mode                        | ON                                                                                  |
| gtid_owned                       |                                                                                     |
| gtid_purged                      |                                                                                     |
| session_track_gtids              | OFF                                                                                 |
+----------------------------------+-------------------------------------------------------------------------------------+
8 rows in set (0.00 sec)

执行reset master 置空gtid (注:操作还会清空重置binlog日志)

MySQL 主从GTID不一致导致主从切换报错_牛牛的笔记的博客-CSDN博客_mysql主从gtid不一致

============================

模拟GTID不一致 然后解决案例:

master(172.16.10.1)

slave(192.168.1.36)

1.master:

mysql> reset master;
Query OK, 0 rows affected (0.01 sec)

2)slave:

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

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

3. master 做数据

mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> 
mysql> create table jettech01(id int,name char);
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> insert into jettech01 value(1,'a');
Query OK, 1 row affected (0.00 sec)

mysql> insert into jettech01 value(2,'b');
Query OK, 1 row affected (0.00 sec)

mysql> insert into jettech01 value(3,'c');
Query OK, 1 row affected (0.01 sec)

mysql> 
mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
+------+------+
3 rows in set (0.00 sec)

4:slave 同步查看数据

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

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

mysql> 
mysql> use test;
Database changed
mysql> 
mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
+------+------+
3 rows in set (0.00 sec)

 5.我们来模拟故障现象:

在master上,通过设置sql_log_bin来控制命令是否写入二进制日志中,运行命令:

mysql> set sql_log_bin=OFF;insert into jettech01 value(4,'e');set sql_log_bin=ON;insert into jettech01 value(5,'f');

6. 这样数据在master上是这样的:

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    4 | e    |
|    5 | f    |
+------+------+
5 rows in set (0.00 sec)

7. 而在slave上的数据是这样的:

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    5 | f    |
+------+------+
4 rows in set (0.00 sec)

此时发现4这条数据没有同步过来

8. 此时我们在master上执行操作:

mysql> update jettech01 set id=6 where id=4;insert into jettech01 value(7,'k');
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Query OK, 1 row affected (0.00 sec)

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    6 | e    |
|    5 | f    |
|    7 | k    |
+------+------+
6 rows in set (0.00 sec)

9. 我们查询一下slave上的数据:

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    5 | f    |
+------+------+
4 rows in set (0.00 sec)

10. 发现数据并没有被同步过来,我们来show一下slave

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 2090
               Relay_Log_File: localhost-relay-bin.000003
                Relay_Log_Pos: 1767
        Relay_Master_Log_File: master-bin.000001
             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: 1032
                   Last_Error: Could not execute Update_rows event on table test.jettech01; Can't find record in 'jettech01', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log master-bin.000001, end_log_pos 1794
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1552
              Relay_Log_Space: 2516
              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: 1032
               Last_SQL_Error: Could not execute Update_rows event on table test.jettech01; Can't find record in 'jettech01', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log master-bin.000001, end_log_pos 1794
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 21395c77-16b5-11ed-b628-005056b93c30
             Master_Info_File: /var/lib/mysql/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: 220511 10:24:22
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-6
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified

提示我们在修改错误并重新启动slave,但关键在于如何修正错误,一般我们采用如下方法:

在从机slave上执行:

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

我们发现上面的两条数据

           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-6

Retrieved_Gtid_Set:意思就是master已经到了1-8了也就是IO线程已经同步过来把数据。

Executed_Gtid_Set:意思就是目前执行sql的线程只执行到1-6 那么还缺少7-8的数据呢。怎么办?

方法:手动跳过gtid

10.1)

mysql>  set gtid_next='21395c77-16b5-11ed-b628-005056b93c30:7';
Query OK, 0 rows affected (0.00 sec)

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

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

10.2)

mysql> set gtid_next='AUTOMATIC';
mysql> start slave;

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.10.1
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000002
          Read_Master_Log_Pos: 997
               Relay_Log_File: localhost-relay-bin.000005
                Relay_Log_Pos: 457
        Relay_Master_Log_File: master-bin.000002
             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: 997
              Relay_Log_Space: 1726
              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: 1
                  Master_UUID: 21395c77-16b5-11ed-b628-005056b93c30
             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
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8
            Executed_Gtid_Set: 21395c77-16b5-11ed-b628-005056b93c30:1-8,
56fc5c7d-d0d7-11ec-bbf9-005056b9e62b:1-3
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified

mysql> select * from jettech01;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
|    5 | f    |
|    7 | k    |
+------+------+
5 rows in set (0.00 sec)

可以发现事务已经全部同步了,但现在数据却是不一致的。

这种适合在数据要求不高的情况下使用,如果后续还有其它数据操作,造成主从数据差异过大,就得用从主库的一个完整备份过来,再从某点开始做replication。

你可能感兴趣的:(服务器)