最近踩到一个说大不大,说小不小的坑,在此分享出来给各位同学。事情是这样的,线上有2台服务器,1主1从。A -> B,B服务器从A服务器同步数据。每天使用xtrabackup在B服务器上面进行全备。某天A服务器挂了,后来由于某种原因无法进入系统了,只有重装了系统,那么此时要恢复A服务器的步骤就是在A服务器部署mysql实例,从B服务器上面拿备份恢复到A,再根据POS点change到B服务器,让A服务器从B服务器同步。此时是B -> A。相信熟悉MySQL的人都知道步骤是没有问题的。

但在这过程中还是出问题了,在A服务器从新从B服务器同步完成以后,确认没有延时以后,此时把A重新恢复成了原来的角色,也就是主库,架构又变回了A -> B。恢复完成以后询问开发说没有异常。到第二天的时候有玩家反馈数据不正确。此时进行数据差异的查找。最后发现A的数据比B的数据少。在经过几番查找以及回忆操作步骤以后,发现踩了大坑。那就是我们安装mysql实例的时候,server-id是根据服务器ip地址的后2位生成的,比如ip地址是:192.168.5.6,那么server-id就是56。

有同学会问了,和server-id有毛关系啊。大家仔细想想mysql的双主是怎样确定binlog是否需要应用的?没错,那就是server-id,如果server-id是自己的就不再应用binlog,那么我踩的坑就是当A再次重新向B同步的时候,A的server-id还是老的,没有修改,B服务器的binlog里面记录的server-id就是A服务器的server-id,最后导致有一部分binlog没有应用。原理已经说明了,那么接下来进行简单的实验就可以论证了。

环境:

自己搭建一个测试环境,简单的1主1从。

我主库的server-id是

  1. mysql> show variables like '%server_id%';
  2. +---------------+-------+
  3. | Variable_name | Value |
  4. +---------------+-------+
  5. | server_id | 25152 |
  6. +---------------+-------+
  7. 1 row in set (0.00 sec)

从库的server-id是

  1. mysql> show variables like '%server_id%';
  2. +---------------+-------+
  3. | Variable_name | Value |
  4. +---------------+-------+
  5. | server_id | 25250 |
  6. +---------------+-------+
  7. 1 row in set (0.00 sec)

主库建库,建表,插入数据:

  1. mysql> create database yayun;
  2. Query OK, 1 row affected (0.00 sec)
  3.  
  4. mysql> create table yayun.tb1 ( id int, age int, name char(20), primary key(id) );
  5. Query OK, 0 rows affected (0.07 sec)
  6.  
  7. mysql> use yayun
  8. Database changed
  9. mysql> insert into tb1 (id,age,name)values(1,18,'aa');
  10. Query OK, 1 row affected (0.00 sec)
  11.  
  12. mysql> insert into tb1 (id,age,name)values(2,18,'bb');
  13. Query OK, 1 row affected (0.00 sec)
  14.  
  15. mysql> select * from tb1;
  16. +----+------+------+
  17. | id | age | name |
  18. +----+------+------+
  19. | 1 | 18 | aa |
  20. | 2 | 18 | bb |
  21. +----+------+------+
  22. 2 rows in set (0.00 sec)
  23.  
  24. mysql>

从库查询:

  1. mysql> select * from tb1;
  2. +----+------+------+
  3. | id | age | name |
  4. +----+------+------+
  5. | 1 | 18 | aa |
  6. | 2 | 18 | bb |
  7. +----+------+------+
  8. 2 rows in set (0.00 sec)
  9.  
  10. mysql>

此时数据是一致的。

接下来在从库备份数据,并且记录pos点。(这里模拟的是从库每天进行的备份)

  1. mysqldump -uroot -p --master-data= yayun > /tmp/backup_yayun.sql

下面在主库继续进行insert,update操作。

  1. mysql> insert into tb1 (id,age,name)values(3,19,'cc');
  2. Query OK, 1 row affected (0.00 sec)
  3.  
  4. mysql> update tb1 set name='yayun' where id=1;
  5. Query OK, 1 row affected (0.00 sec)
  6. Rows matched: 1 Changed: 1 Warnings: 0
  7.  
  8. mysql> select * from tb1;
  9. +----+------+-------+
  10. | id | age | name |
  11. +----+------+-------+
  12. | 1 | 18 | yayun |
  13. | 2 | 18 | bb |
  14. | 3 | 19 | cc |
  15. +----+------+-------+
  16. 3 rows in set (0.00 sec)
  17.  
  18. mysql>

查询从库记录:

  1. mysql> select * from tb1;
  2. +----+------+-------+
  3. | id | age | name |
  4. +----+------+-------+
  5. | 1 | 18 | yayun |
  6. | 2 | 18 | bb |
  7. | 3 | 19 | cc |
  8. +----+------+-------+
  9. 3 rows in set (0.00 sec)
  10.  
  11. mysql>

可以看到此时主从数据是一致的。接下来我们就当主库挂了。重新需要拉取备份,然后向从库同步数据。
1. 把备份文件backup_yayun.sql拉到主库。

2. 把从库的同步断掉,清掉同步信息。

从库操作:

  1. mysql> stop slave;reset slave all;
  2. Query OK, 0 rows affected (0.03 sec)
  3.  
  4. Query OK, 0 rows affected (0.05 sec)
  5.  
  6. mysql>

主库操作:

  1. mysql -uroot -p yayun < backup_yayun.sql

查看pos点:

  1. [root@mdw ~]# grep -i change backup_yayun.sql
  2. -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=;
  3. [root@mdw ~]#

主库change到原来的从库

  1. mysql> CHANGE MASTER TO MASTER_HOST='10.36.25.250',MASTER_USER='repl',MASTER_PASSWORD='',MASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=4070;
  2. Query OK, 0 rows affected (0.10 sec)
  3.  
  4. mysql> start slave;
  5. Query OK, 0 rows affected (0.00 sec)

查询数据:

如果查询出来的数据是下面的数据,那么就是正确的:

  1. +----+------+-------+
  2. | id | age | name |
  3. +----+------+-------+
  4. | 1 | 18 | yayun |
  5. | 2 | 18 | bb |
  6. | 3 | 19 | cc |
  7. +----+------+-------+

我们实际查询一下:

  1. mysql> select * from tb1;
  2. +----+------+------+
  3. | id | age | name |
  4. +----+------+------+
  5. | 1 | 18 | aa |
  6. | 2 | 18 | bb |
  7. +----+------+------+
  8. 2 rows in set (0.00 sec)
  9.  
  10. mysql>

卧槽,发生了什么,怎么数据少了,而且id等于1的name字段结果也不一样?

下面我们看看原来老的从库的binlog

  1. # :: server id end_log_pos Query thread_id= exec_time= error_code=
  2. SET TIMESTAMP=/*!*/;
  3. insert into tb1 (id,age,name)values(,,'cc')
  4. /*!*/;
  5. # at
  6. # :: server id end_log_pos Xid =
  7. COMMIT/*!*/;
  8. # at
  9. # :: server id end_log_pos Query thread_id= exec_time= error_code=
  10. SET TIMESTAMP=/*!*/;
  11. BEGIN
  12. /*!*/;
  13. # at
  14. # :: server id end_log_pos Query thread_id= exec_time= error_code=
  15. SET TIMESTAMP=/*!*/;
  16. update tb1 set name='yayun' where id=
  17. /*!*/;
  18. # at
  19. # :: server id end_log_pos Xid =
  20. COMMIT/*!*/;
  21. DELIMITER ;

可以看见有insert,update,但是server id都是25152,也就是主库的。这也就是为什么少了数据的原因。开头也提到过了。

如果我们在新的主库上面进行update,如果这条记录在从库没有存在,而且主从的binlog是row模式,那么就会触发1032错误,复制将中断,由于我的是mixed模式,同步一直没有报错,没有早发现问题。我update语句加limit就会触发row模式,下面我们试试。

主库:

  1. mysql> update tb1 set name='abcd' where id=3 limit 1;
  2. Query OK, 1 row affected (0.00 sec)
  3. Rows matched: 1 Changed: 1 Warnings: 0
  4.  
  5. mysql>

从库:

  1. mysql> show slave status\G
  2. *************************** 1. row ***************************
  3. Slave_IO_State: Waiting for master to send event
  4. Master_Host: 10.36.25.250
  5. Master_User: repl
  6. Master_Port: 3306
  7. Connect_Retry: 60
  8. Master_Log_File: mysql-bin.000004
  9. Read_Master_Log_Pos: 4653
  10. Relay_Log_File: relaylog.000002
  11. Relay_Log_Pos: 253
  12. Relay_Master_Log_File: mysql-bin.000004
  13. Slave_IO_Running: Yes
  14. Slave_SQL_Running: No
  15. Replicate_Do_DB:
  16. Replicate_Ignore_DB:
  17. Replicate_Do_Table:
  18. Replicate_Ignore_Table:
  19. Replicate_Wild_Do_Table:
  20. Replicate_Wild_Ignore_Table:
  21. Last_Errno: 1032
  22. Last_Error: Could not execute Update_rows event on table yayun.tb1; Can't find record in 'tb1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000004, end_log_pos 4626
  23. Skip_Counter: 0
  24. Exec_Master_Log_Pos: 4454
  25. Relay_Log_Space: 601
  26. Until_Condition: None
  27. Until_Log_File:
  28. Until_Log_Pos: 0
  29. Master_SSL_Allowed: No
  30. Master_SSL_CA_File:
  31. Master_SSL_CA_Path:
  32. Master_SSL_Cert:
  33. Master_SSL_Cipher:
  34. Master_SSL_Key:
  35. Seconds_Behind_Master: NULL
  36. Master_SSL_Verify_Server_Cert: No
  37. Last_IO_Errno: 0
  38. Last_IO_Error:
  39. Last_SQL_Errno: 1032
  40. Last_SQL_Error: Could not execute Update_rows event on table yayun.tb1; Can't find record in 'tb1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000004, end_log_pos 4626
  41. Replicate_Ignore_Server_Ids:
  42. Master_Server_Id: 25250
  43. 1 row in set (0.00 sec)

可以看见抛1032错误,主库有这条记录,从库没有,同时触发了row模式,就会导致复制中断。

结论:

1. 在重新搭建复制关系的时候一定注意server-id。

2. 线上对数据一致性要求比较高的一定要使用row模式。

MySQL Server-id踩到的坑的更多相关文章

  1. mysql server id一样导致报错

    (root@localhost) 16:03:38 [(none)]> show slave status \G; Last_IO_Errno: 1593 Last_IO_Error: Fata ...

  2. Linux下安装mysql你又踩过多少坑【宇宙最全教程】

    一.检查以前是否安装过MySql 因为cnetos7一般默认安装mariadb,所以要检查mysql或者mariadb是否安装 rpm -pa | grep -i mysql rpm -pa | gr ...

  3. 踩坑录-mysql不允许远程连接(错误码:1130) Host'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL server“

    每次搭建mysql环境都会遇见同样的问题,在此分享一下踩坑笔录. 一.问题描述 安装成功后,本地直接链接远程mysql,默认为不允许远程访问,则客户端提示1130 - Host'xxx.xxx.xxx ...

  4. Ubuntu 16.04 安装Mysql 5.7 踩坑小记

    title:Ubuntu 16.04 安装Mysql 5.7 踩坑小记 date: 2018.02.03 安装mysql sudo apt-get install mysql-server mysql ...

  5. 【详记MySql问题大全集】四、设置MySql大小写敏感(踩坑血泪史)

    系列目录 一.安装MySql 二.安装并破解Navicat 三.没有my.in配置文件怎么办 四.设置MySql的大小写敏感 五.重置MySql登陆密码 这一篇可以说是我的踩坑的血泪史了... MyS ...

  6. windows下mysql免安装版配置(踩过的坑)简记

    下载 从官网(https://dev.mysql.com/downloads/mysql/)下载 这里的免安装版本的,相对来说干净,但是需要自己来配置很多东西. 配置 首先是注册windows的服务. ...

  7. Linux安装mysql以及安装时踩下的坑

    安装: 检测是否已经安装了mysql rpm -qa | grep mysql 如果已经安装了,将其卸载,如: rpm -e --nodeps  mysql-libs-5.1.71-1.el6.x86 ...

  8. windows 上的MySQL默认字符集设置踩过的坑

    前言: 前几天刚买了新电脑,装上MySQL有几天了,今天没事试了一下,发现默认字符集没有修改,还是默认的latin1,折腾了大半天,终于搞好了. 这是我成功设置后的结果图: 命令式直接在MySQL界面 ...

  9. 解决ROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'creat table study_record( id int(11) not null

    之前一直用的好好的,突然就出现了这个错误: ERROR 1064 (42000): You have an error in your SQL syntax; check the manual tha ...

随机推荐

  1. 【maven 报错】maven项目执行maven install时报错Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)

    在使用maven新建的web项目中,执行 执行如上的这两个操作,报错: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-co ...

  2. 【转】使用Apache Kylin搭建企业级开源大数据分析平台

    http://www.thebigdata.cn/JieJueFangAn/30143.html 本篇文章整理自史少锋4月23日在『1024大数据技术峰会』上的分享实录:使用Apache Kylin搭 ...

  3. poj3616 LIS变形

    题目链接:http://poj.org/problem?id=3616 题意:给出m组数据a,b,c代表在第a分钟到第b分钟产生c个效益,问最大产生多少效益(区间不能重叠,每次工作完必须歇息R分钟) ...

  4. PHP 采集

    <?php header("content-type:text/html;charset=gbk"); // 要采集的页面的地址 $url = "http://ww ...

  5. jquery mousewheel

    <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js&quo ...

  6. BeanShell用法汇总(部分摘抄至网络)【转】

    说明:本文部分资料摘抄至 来源: http://www.cnblogs.com/puresoul/p/4915350.html 来源: http://www.cnblogs.com/puresoul/ ...

  7. jquery笔记(操作HTML)

    获取: $("selector").text(): 获取元素里面的文本 $("selector").html(): 获取元素里面的代码标签 $("se ...

  8. 原生 js 写分页

    欢迎留言或者加本人QQ172360937咨询 这段代码是用原生 js 写的一个分页的效果 <!doctype html> <html lang="en"> ...

  9. POJ1769 Minimizing maximizer(DP + 线段树)

    题目大概就是要,给一个由若干区间[Si,Ti]组成的序列,求最小长度的子序列,使这个子序列覆盖1到n这n个点. dp[i]表示从第0个到第i个区间且使用第i个区间,覆盖1到Ti所需的最少长度 对于Si ...

  10. c# 基本值类型及其默认值

    //值类型 C# 类型      .NET Framework 类型 bool            System.Boolean 4Byte 32bit布尔型变量 逻辑值,true或者false,默 ...