MySQL复制问题的三个参数分析


Posted in MySQL onApril 07, 2021

    今天星期二,早上居然起晚了,上班迟到了,简直是。。。废话不多说,在昨天的文章中,我们提到了三个参数,分别是:

  • slave_exec_mode参数;
  • sql_slave_skip_counter=N参数;
  • slave-skip-errors=N参数。

这三个参数都可以解决并行复制中的一些指定的错误,例如duplicate key 1062错误等,今天我们简单试验一下,这三个参数的区别:

01 sql_slave_skip_counter参数

这个参数的设置主要是为了跳过某些错误的"event",注意这里的用词是event而不是事务,是因为它的本质是跳过一个一个事件,需要注意的是,这个参数需要在偏移量复制模式中使用,如果使用的是gtid的复制模式,则不可以使用这个参数。我们来看例子,首先搭建一套复制关系:

master   10.30.124.68

slave     10.30.124.128

这俩实例互为主从。我们创建测试表test.yeyz,并插入一些数据,其中id为主键,具有唯一性,如下:

master上

mysql:(none) 22:25:56>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
+----+------+
4 rows in set (0.00 sec)

slave上

mysql:(none) 22:25:38>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
+----+------+
5 rows in set (0.00 sec)

我们可以发现,从节点的数据比主节点多一条,多了id=5的记录,然后我们在主节点上插入数据:

mysql:(none) 22:26:06>>insert into test.yeyz values (5,5),(6,6);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

此时观察从节点:

mysql:(none) 22:26:34>>show slave status\G
                  Master_Host: 10.30.124.68
                  Master_User: dba_repl
                  Master_Port: 4306
                Connect_Retry: 60
              Master_Log_File: mysqlbin.000002
          Read_Master_Log_Pos: 523
               Relay_Log_File: slave-relay-bin.000002
                Relay_Log_Pos: 319
        Relay_Master_Log_File: mysqlbin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
                   Last_Errno: 1062
                   Last_Error: Coordinator stopped because there were error(s) 
in the worker(s). The most recent failure being:
 Worker 0 failed executing transaction 'ANONYMOUS' at
 master log mysqlbin.000002, end_log_pos 492.
 See error log and/or performance_schema.replication_applier_status_by_worker
 table for more details about this failure or others, if any.
                 Skip_Counter: 0

可以发现,从节点已经SQL线程断开了, 这个时候,在主节点上查询这个错误position 492处的binlog,可以看到:

mysql:(none) 22:30:28>>show binlog events in 'mysqlbin.000002' from 194;  
+-----------------+-----+----------------+-----------+-------------+--------------------------------------------+
| Log_name        | Pos | Event_type     | Server_id | End_log_pos | Info                                       |
+-----------------+-----+----------------+-----------+-------------+--------------------------------------------+
| mysqlbin.000002 | 194 | Anonymous_Gtid |       192 |         259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'       |
| mysqlbin.000002 | 259 | Query          |       192 |         327 | BEGIN                                      |
| mysqlbin.000002 | 327 | Rows_query     |       192 |         391 | # insert into test.yeyz values (5,5),(6,6) |
| mysqlbin.000002 | 391 | Table_map      |       192 |         439 | table_id: 108 (test.yeyz)                  |
| mysqlbin.000002 | 439 | Write_rows     |       192 |         492 | table_id: 108 flags: STMT_END_F            |
| mysqlbin.000002 | 492 | Xid            |       192 |         523 | COMMIT /* xid=38 */                        |
+-----------------+-----+----------------+-----------+-------------+--------------------------------------------+
6 rows in set (0.00 sec)

从上面的binlog可以看出来,我们的一个insert操作实际上生成了5个enent,分别对应的pos是从259~492,关于event,待会儿再说。

因为主节点上插入了id=5的记录,跟从节点上的记录冲突了,查看错误日志,可以发现:

Duplicate entry '5' for key 'PRIMARY',
 Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; 
the event's master log FIRST, 
end_log_pos 492 | 2019-07-16 22:26:25

我们通过sql_slave_skip_counter参数的设置来解决这个问题,步骤如下:

mysql:(none) 22:29:32>>stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql:(none) 22:32:45>>set global sql_slave_skip_counter=1;
Query OK, 0 rows affected (0.00 sec)

mysql:(none) 22:33:06>>start slave;

   在昨天的文章中我们说过,sql_slave_skip_counter后面跟的值是event的个数,所以这里我们相当于跳过了一个event,mysql中规定,如果跳过一个event之后,还在某一个事务里面,那么会继续跳过这个事务。

   使用这个参数跳过一个event之后,我们再来看从库表中的数据和复制情况,可以看到:

slave表:

mysql:(none) 22:33:10>>show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.30.124.68
                  Master_User: dba_repl
                  Master_Port: 4306
                Connect_Retry: 60
              Master_Log_File: mysqlbin.000002
          Read_Master_Log_Pos: 523
               Relay_Log_File: slave-relay-bin.000003
                Relay_Log_Pos: 319
        Relay_Master_Log_File: mysqlbin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes


mysql:(none) 22:33:16>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
+----+------+
5 rows in set (0.00 sec)

看看master表:

mysql:(none) 22:33:36>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
|  6 |    6 |
+----+------+
6 rows in set (0.00 sec)

   可以发现,master中数据插入成功,而slave中数据插入失败,也就是说:

该参数跳过错误的时候,会导致主从的数据不一致。

02 slave_skip_errors参数

    这个参数是跳过制定的错误,也就是说,需要我们设置对应的error_code,从下面的日志中的内容可以看出,error_code的值为1062

Duplicate entry '5' for key 'PRIMARY',
 Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; 
the event's master log FIRST, 
end_log_pos 492 | 2019-07-16 22:26:25

   我们需要手动将这个参数的值也该为1062,需要注意的是,这个参数的改动需要重启mysql服务,因为这个参数是一个只读的参数。

   修改后的情况如下:

mysql--dba_admin@127.0.0.1:(none) 22:38:55>>show variables like '%errors%';
+--------------------+---------+
| Variable_name      | Value   |
+--------------------+---------+
| max_connect_errors | 1000000 |
| slave_skip_errors  | 1062    |
+--------------------+---------+
2 rows in set (0.01 sec)

   此时我们更新master表和slave表的数据,更新后的情况如下:

master:

mysql:(none) 22:39:15>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 ||  2 |    2 |
|  3 |    3 ||  4 |    4 |
|  5 |    5 ||  6 |    6 |
+----+------+
6 rows in set (0.00 sec)

slave上:

mysql:(none) 22:40:15>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
|  6 |    6 |
|  7 |    7 |
+----+------+
7 rows in set (0.00 sec)

我们发现,slave表比master表多一条数据,也就是id=7的记录,此时我们在master上执行:

mysql:(none) 22:34:15>>insert into test.yeyz values (7,7),(8,8);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

查看slave上面的复制情况和数据情况,如下:

mysql:(none) 22:39:05>>show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.30.124.68
                  Master_User: dba_repl
                  Master_Port: 4306
                Connect_Retry: 60
              Master_Log_File: mysqlbin.000002
          Read_Master_Log_Pos: 852
               Relay_Log_File: slave-relay-bin.000005
                Relay_Log_Pos: 648
        Relay_Master_Log_File: mysqlbin.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: 


mysql:(none) 22:40:15>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
|  6 |    6 |
|  7 |    7 |
+----+------+
7 rows in set (0.00 sec)

   可以看到,复制没有出现错误,即使从库上已经有id=7的记录。而且发现,从库的数据跟之前保持一致,也就是说,主库插入的id=8的记录没有被同步过来。

   总结一下:该参数在跳过复制错误的时候,需要重启mysql服务,然后可能导致主从数据不一致。

03 slave-skip-errors=N参数

  再看最后一个参数,这个参数表示的是并行复制过程中的从库复制模式,默认值是strict严格模式,和上面一样,我们先看主库和从库的数据情况:

master数据:

mysql:(none) 22:39:20>>select * from test.yeyz;                 
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
|  6 |    6 |
|  7 |    7 |
|  8 |    8 |
+----+------+
8 rows in set (0.00 sec)

slave数据:

mysql:(none) 22:42:46>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
|  6 |    6 |
|  7 |    7 |
|  8 |    8 |
|  9 |    9 |
+----+------+
9 rows in set (0.00 sec)

   此时我们在从库上修改参数如下:

mysql:(none) 22:42:59>>show variables like '%exec%';
+----------------------------------+--------+
| Variable_name                    | Value  |
+----------------------------------+--------+
| gtid_executed_compression_period | 1000   |
| max_execution_time               | 0      |
| rbr_exec_mode                    | STRICT |
| slave_exec_mode                  | STRICT |
+----------------------------------+--------+
4 rows in set (0.00 sec)

mysql:(none) 22:44:05>>set global slave_exec_mode='IDEMPOTENT';
Query OK, 0 rows affected (0.00 sec)

mysql:(none) 22:44:10>>show variables like '%exec%';           
+----------------------------------+------------+
| Variable_name                    | Value      |
+----------------------------------+------------+
| gtid_executed_compression_period | 1000       |
| max_execution_time               | 0          |
| rbr_exec_mode                    | STRICT     |
| slave_exec_mode                  | IDEMPOTENT |
+----------------------------------+------------+
4 rows in set (0.00 sec)

  修改完参数,我们在主库上进行insert操作:

insert into test.yeyz values (9,9),(10,10);

   查看从库的复制状态和数据情况,如下:

mysql:(none) 22:44:14>>show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.30.124.68
                  Master_User: dba_repl
                  Master_Port: 4306
                Connect_Retry: 60
              Master_Log_File: mysqlbin.000002
          Read_Master_Log_Pos: 1183
               Relay_Log_File: slave-relay-bin.000007
                Relay_Log_Pos: 650
        Relay_Master_Log_File: mysqlbin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

1 row in set (0.00 sec)

mysql:(none) 22:44:38>>select * from test.yeyz;
+----+------+
| id | age  |
+----+------+
|  1 |    1 |
|  2 |    2 |
|  3 |    3 |
|  4 |    4 |
|  5 |    5 |
|  6 |    6 |
|  7 |    7 |
|  8 |    8 |
|  9 |    9 |
| 10 |   10 |
+----+------+
10 rows in set (0.00 sec)

   可以发现,既没有出现复制错误,主库上插入的数据也同步过来了。   

总结一下:

  • slave_exec_mode参数;
  • sql_slave_skip_counter=N参数;
  • slave-skip-errors=N参数。

   这三个参数都能解决复制过程中的不一致情况,区别如下:

slave_exec_mode参数可以保证主从数据一致,其他两个不可以。

slave-skip-errors参数可以跳过制定的错误,但是需要重启实例,不能保证数据一致。

sql_slave_skip_counter参数需要在偏移量的复制模式下使用,不能保证数据一致。

以上就是MySQL复制问题的三个参数分析的详细内容,更多关于MySQL复制问题的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
详解MySQL 用户权限管理
Apr 20 MySQL
MySQL 全文索引使用指南
May 25 MySQL
MySQL 不等于的三种使用及区别
Jun 03 MySQL
浅谈mysql增加索引不生效的几种情况
Jun 23 MySQL
SQL之各种join小结详细讲解
Aug 04 MySQL
MySQL配置主从服务器(一主多从)
Aug 07 MySQL
MySQL如何解决幻读问题
Aug 07 MySQL
mysql事务隔离级别详情
Oct 24 MySQL
MySQL分区表实现按月份归类
Nov 01 MySQL
MySQL视图概念以及相关应用
Apr 19 MySQL
sql注入报错之注入原理实例解析
Jun 10 MySQL
MySQL控制流函数(-if ,elseif,else,case...when)
Jul 07 MySQL
MySQL pt-slave-restart工具的使用简介
Apr 07 #MySQL
MySQL主从复制断开的常用修复方法
Apr 07 #MySQL
MySQL infobright的安装步骤
Apr 07 #MySQL
MySQL表的增删改查基础教程
mysql批量新增和存储的方法实例
Apr 07 #MySQL
Mysql 性能监控及调优
数据库连接池
You might like
用PHP函数解决SQL injection
2006/12/09 PHP
php并发对MYSQL造成压力的解决方法
2013/02/21 PHP
PHP5各个版本的新功能和新特性总结
2014/03/16 PHP
PHP面向对象之工作单元(实例讲解)
2017/06/26 PHP
LaravelS通过Swoole加速Laravel/Lumen详解
2018/03/02 PHP
充分发挥Node.js程序性能的一些方法介绍
2015/06/23 Javascript
javascript实现动态导入js与css等静态资源文件的方法
2015/07/25 Javascript
JavaScript仿flash遮罩动画效果
2016/06/15 Javascript
微信小程序 后台登录(非微信账号)实例详解
2017/03/31 Javascript
老生常谈js数据类型
2017/08/03 Javascript
十分钟带你快速了解React16新特性
2017/11/10 Javascript
video.js 一个页面同时播放多个视频的实例代码
2018/11/27 Javascript
jquery-ui 进度条功能示例【测试可用】
2019/07/25 jQuery
Electron实现应用打包、自动升级过程解析
2020/07/07 Javascript
[01:32]DOTA2 2015国际邀请赛中国区预选赛第四日战报
2015/05/29 DOTA
python中的全局变量用法分析
2015/06/09 Python
详解JavaScript编程中的window与window.screen对象
2015/10/26 Python
Python装饰器实现几类验证功能做法实例
2017/05/18 Python
利用selenium 3.7和python3添加cookie模拟登陆的实现
2017/11/20 Python
Python迭代器与生成器用法实例分析
2018/07/09 Python
python复制列表时[:]和[::]之间有什么区别
2018/10/16 Python
一文了解Python并发编程的工程实现方法
2019/05/31 Python
python3下载抖音视频的完整代码
2019/06/05 Python
运行tensorflow python程序,限制对GPU和CPU的占用操作
2020/02/06 Python
python 对任意数据和曲线进行拟合并求出函数表达式的三种解决方案
2020/02/18 Python
Selenium执行完毕未关闭chromedriver/geckodriver进程的解决办法(java版+python版)
2020/12/07 Python
CSS3的颜色渐变效果的示例代码
2017/09/29 HTML / CSS
TripAdvisor土耳其网站:全球知名旅行社区,真实旅客评论
2017/04/17 全球购物
荷兰照明、灯具和配件网上商店:dmlights
2019/08/25 全球购物
Super-Pharm波兰:药房和香水在一个地方
2020/08/18 全球购物
《雾凇》教学反思
2014/02/17 职场文书
股东合作协议书范本
2014/04/14 职场文书
大专生找工作自荐书
2014/06/10 职场文书
公司外出活动方案
2014/08/14 职场文书
学校2014重阳节活动策划方案
2014/09/16 职场文书
2014学生会工作总结报告
2014/12/02 职场文书