今天发生了与之前某篇博客相似的问题,有同学在不同步的 binlog 库中使用语句 database.table 命令对表进行 drop 导致 master 丢弃该表但是从库并未能同步到该操作。并且后续又实用 use xxxx 对该表进行增删字段,由于salve 并未建立此表于是 slave 崩溃的情况。

slave 崩溃信息通过查看 MySQL 错误日志差不多是这样

  1. -- :: [ERROR] Slave SQL: Error 'Table 'api.ring_king_record' doesn't exist' on query. Default database: 'api'. Query: 'ALTER TABLE `api`.`ring_king_record`
  2. CHANGE COLUMN `course_id` `course_id` VARCHAR() NULL DEFAULT '' AFTER `id`,
  3. CHANGE COLUMN `title` `title` VARCHAR() NULL DEFAULT '' AFTER `course_id`,
  4. CHANGE COLUMN `serialNumber` `serial_number` VARCHAR() CHARACTER SET 'latin1' NULL DEFAULT '' COMMENT '唯一标示码' ,
  5. CHANGE COLUMN `tsaCount` `tsa_count` VARCHAR() CHARACTER SET 'latin1' NULL DEFAULT '' COMMENT '剩余确权次数'', Error_code: 1146
  6. -- :: [Warning] Slave: Table 'api.ring_king_record' doesn't exist Error_code: 1146
  7. -- :: [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin.000762' position .
  8. -- :: [Note] Slave I/O thread: connected to master 'xxxx',replication started in log 'mysql-bin.000763' at position

可以很清晰的看到错误的原因是 api.ring_king_record 这个表根本不存在,但是却尝试去操作 change column 的操作。所以 slave 直接崩溃了, MySQL 提示我们数据库已经停止同步希望我们修复了这个问题之后再使用 SLAVE START 来启动 slave 的同步跟上 master.

这里只需要关注两个地方

1. mysql-bin.000762 可以让我们定位到发生问题是哪个 binlog。

2. position 可以让我们定位到发生的位置是在哪儿。

通过 position 16412435 如果你可以访问 master 物理机,那么可以通过访问 binlog 所在目录使用命令

  1. mysqlbinlog mysql-bin. | grep -C

去查看相关的信息,包括前后是什么语句,之类的。

如果类似于使用了 rds 这样的 MySQL 服务,可以去 master 所在的 rds 并使用 MySQL Client 上执行语句

  1. show binlog events in 'mysql-bin.000762' from limit \G;

我们可以得到从崩溃该语句开始的一些信息

  1. mysql> show binlog events in 'mysql-bin.000762' from limit \G;
  2. *************************** . row ***************************
  3. Log_name: mysql-bin.
  4. Pos:
  5. Event_type: Gtid
  6. Server_id:
  7. End_log_pos:
  8. Info: SET @@SESSION.GTID_NEXT= '8dcfd361-10cb-11e9-9060-506b4b2ac23e:30038123'
  9. *************************** . row ***************************
  10. Log_name: mysql-bin.
  11. Pos:
  12. Event_type: Query
  13. Server_id:
  14. End_log_pos:
  15. Info: use `api`; ALTER TABLE `api`.`ring_king_record`
  16. CHANGE COLUMN `course_id` `course_id` VARCHAR() NULL DEFAULT '' AFTER `id`,
  17. CHANGE COLUMN `title` `title` VARCHAR() NULL DEFAULT '' AFTER `course_id`,
  18. CHANGE COLUMN `serialNumber` `serial_number` VARCHAR() CHARACTER SET 'latin1' NULL DEFAULT '' COMMENT '唯一标示码' ,
  19. CHANGE COLUMN `tsaCount` `tsa_count` VARCHAR() CHARACTER SET 'latin1' NULL DEFAULT '' COMMENT '剩余确权次数'
  20. *************************** . row ***************************
  21. Log_name: mysql-bin.
  22. Pos:
  23. Event_type: Gtid
  24. Server_id:
  25. End_log_pos:
  26. Info: SET @@SESSION.GTID_NEXT= '8dcfd361-10cb-11e9-9060-506b4b2ac23e:30038124'
  27. *************************** . row ***************************
  28. Log_name: mysql-bin.
  29. Pos:
  30. Event_type: Query
  31. Server_id:
  32. End_log_pos:
  33. Info: /* rds internal mark */ CREATE TABLE IF NOT EXISTS mysql.ha_health_check (
  34. id BIGINT DEFAULT ,
  35. type CHAR() DEFAULT '',
  36. PRIMARY KEY (type)

这里可以很清楚的看到崩溃位置 16412436 GTID: 8dcfd361-10cb-11e9-9060-506b4b2ac23e:30038123 执行了 change column 的操作导致了崩溃。

现在我们要恢复 slave 就需要跳过这个报错的语句。因为全局开启了 GTID 的关系我们无法使用传统的

  1. root@(none) >stop slave;
  2. Query OK, rows affected (0.00 sec)
  3.  
  4. root@(none) >SET GLOBAL SQL_SLAVE_SKIP_COUNTER = N; #跳过N个事务
  5. Query OK, rows affected (0.00 sec)
  6.  
  7. root@(none) >start slave;
  8. Query OK, rows affected, warning (0.03 sec)
  9.  
  10. 来恢复 会报错
  11. ERROR (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction

我在网上查了不少资料,但是感觉大部分都是互相 copy xjb 扯淡,也根本使用不了。

下面是我结合几个靠谱博客和官方文档写的一个配置

  1. stop slave;
  2. reset master;
  3. reset slave;
  4. CHANGE MASTER TO MASTER_HOST='master_address',MASTER_USER='xxx', MASTER_PASSWORD='xxx';
  5. set global gtid_purged = '8dcfd361-10cb-11e9-9060-506b4b2ac23e:30038123';
    SET @@SESSION.GTID_NEXT= '8dcfd361-10cb-11e9-9060-506b4b2ac23e:30038124';
    begin;
    commit;
    SET GTID_NEXT="AUTOMATIC";
    start slave;

下面我会依次介绍这些命令是用来干嘛的。

首先我们所有现在针对去恢复的 slave 操作都需要先停止 slave.

reset master 这一步我不是很确定是否真的可以不做,reset master 会将 slave 机器的所有 binlog 都清空。比如之前我们可能是 mysql-bin.000023 这样子,如果使用了 reset master 会重新从 mysql-bin.000001 开始记录 binlog。我因为清理了也没关系,因为我会要显示的指定我从 master 机器的什么位置开始消费并且追上 master 所以就设置了。

reset slave 将让 slave 忘记主从复制的关系的位置信息,它会删除 master.info 和 relay-log.iinfo 文件重置 relaylog 信息。我们知道 relay-log 其实就是用于记录 slave 复制 master 信息复制到哪里来了这里会重置这些信息。

然后我哦们指定 change master 重新指定我们要跟随的 master 地址。

设置全局的 gtid_purged 这里注意 这个 gtid_purged 用于告诉你的 slave 无视哪些 gtid 的记录段,就是我们会无视掉所有之前我们消费过的记录段直到到达我们报错的位置。这个可以跟下面的参数联动。从上面的图我们看到我们只需要跳过 change column 那条语句所在的 GTID 重新从

  1. 8dcfd361-10cb-11e9--506b4b2ac23e:

开始消费即可跳过,所以上面我们使用 30038124-1 来表示我们需要 purged 的部分。

最后我们通过提交一个空事务并指定自动位移 GTID 来恢复我们的 slave。

一切完成之后我们启动 slave 使用 start slave

这个时候我们的 slave 从库会从我们指定的位置开始追上 master 只需要等待一段时间即可,那么如何判断已经追上了 master 呢?

  1. 我们在从库上执行
  2. show slave status
  3.  
  4. mysql> show slave status\G;
  5. *************************** . row ***************************
  6. Slave_IO_State: Waiting for master to send event
  7. Master_Host: xxxxxxxxxxxx
  8. Master_User: xxxx
  9. Master_Port:
  10. Connect_Retry:
  11. Master_Log_File: mysql-bin.
  12. Read_Master_Log_Pos:
  13. Relay_Log_File: mysqld-relay-bin.
  14. Relay_Log_Pos:
  15. Relay_Master_Log_File: mysql-bin.
  16. Slave_IO_Running: Yes
  17. Slave_SQL_Running: Yes
  18. Replicate_Do_DB: xxxxxxxxxxxx
  19. Replicate_Ignore_DB: mysql
  20. Replicate_Do_Table:
  21. Replicate_Ignore_Table:
  22. Replicate_Wild_Do_Table:
  23. Replicate_Wild_Ignore_Table:
  24. Last_Errno:
  25. Last_Error:
  26. Skip_Counter:
  27. Exec_Master_Log_Pos:
  28. Relay_Log_Space:
  29. Until_Condition: None
  30. Until_Log_File:
  31. Until_Log_Pos:
  32. Master_SSL_Allowed: No
  33. Master_SSL_CA_File:
  34. Master_SSL_CA_Path:
  35. Master_SSL_Cert:
  36. Master_SSL_Cipher:
  37. Master_SSL_Key:
  38. Seconds_Behind_Master:
  39. Master_SSL_Verify_Server_Cert: No
  40. Last_IO_Errno:
  41. Last_IO_Error:
  42. Last_SQL_Errno:
  43. Last_SQL_Error:
  44. Replicate_Ignore_Server_Ids:
  45. Master_Server_Id:
  46. Master_UUID: 8dcfd361-10cb-11e9--506b4b2ac23e
  47. Master_Info_File: /var/lib/mysql/master.info
  48. SQL_Delay:
  49. SQL_Remaining_Delay: NULL
  50. Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
  51. Master_Retry_Count:
  52. Master_Bind:
  53. Last_IO_Error_Timestamp:
  54. Last_SQL_Error_Timestamp:
  55. Master_SSL_Crl:
  56. Master_SSL_Crlpath:
  57. Retrieved_Gtid_Set: 8dcfd361-10cb-11e9--506b4b2ac23e:-
  58. Executed_Gtid_Set: 0cf0e744-f9f6-11e8-bb7a-00163e302177:-,
  59. 8dcfd361-10cb-11e9--506b4b2ac23e:-
  60. Auto_Position:

比较 Read_Master_Log_Pos 和 Exec_Master_Log_Pos 差不多就说明已经追上了 master。

Relay_Log_Pos 和他们差不多能说明 io 线程也能拉到最新的数据。

当我们有错误的时候 show slave status 也可以给我们提供非常多的信息,例如最后出错的信息是啥。为什么报错都有显示,如果没有第一时间去看错误日志,使用命令在这里看错误信息也不错。

另外使用 show variables like '%gtid%'; 也可以给我们提供一些基于 gtid 的信息。

唔。。。又是修数据跑监控的一天=。=

---------------------------------分割线---------------------------------

关于 GTID 昨晚回去 我重新翻看了一些资料觉得还是有必要多说两句。

可以说 GTID 的出现解决了之前完全依赖 master 文件和 pos 的来切换主从的问题得到了解决。

MySQL 版本5.6 引入了 GTID 解决主从同步位点问题。GTID 的全称是 Global Transaction Identifier 也就是全局事务 ID,是一个事务在提交的时候生成的,是这个事务的唯一标识。它由两部分组成:

  1. GTID=server_uuid:gno

其中 server_uuid 是一个实例第一次启动时自动生成的,可以通过我们上面介绍的命令 show master/slave status 看到该机器的 UUID

gno 是一个整数,初始化是1,每次提交事务的时候分配给这个事务,并加 1。

GTIO 模式的启动配置:

  1. #GTID
  2. gtid_mode=on
  3. enforce_gtid_consistency=on
  4. log-slave-updates=

GTID_mode 开启的参数相关的是前两个参数, log-slave-updates = 1 是开启连贯复制 log

本身 slave 同步 master 的日志是不会再放入自己的 binlog 中的,如果我们还有机器在监听 slave 的 binlog 日志就需要开启 log-slave-updates 参数。

在 GTID 模式下,每个事务都会跟一个 GTID 一一对应。这个 GTID 有两种生成方式,而使用哪种取决于 session 变量 gtid_next 的值。

可以看到上面我们在跳过事务的时候是直接指定了一个 GTID_NEXT 的位置从这个位置开始。

然后指定下面的偏移规则是 gtid_next=automatic 使用默认值每执行一个事务就 +1

这样每个 MySQL 实例都维护了一个 GTID 集合,用来对应“这个实例执行过的所有事务”。

因为这个集合的存在,所以我们在重制  slave 和 master 的进度的时候,如果 slave 并没有通过 gtid_purged 或者通过指定 GTID_NEXT 跳过已经执行的事务 slave 会尝试去执行这些事务,并且因为主键冲突等原因报错崩溃。

所以现在回头过来看这几条命令

  1. set gtid_next='aaaaaaaa-cccc-dddd-eeee-ffffffffffff:10';
  2. begin;
  3. commit;
  4. set gtid_next=automatic;
  5. start slave;

其实它的意义是 首先 :10 这个gtid 是有问题那个 GTID 就是执行了会崩溃的那个 GTID 。

然后这个时候我们对其替换成一个空事务。

再设置之后都正常加一偏移数据。

最后启动 slave 。这样的话当我们的 slave 运行到这里的时候会因为已经因为这个 GTID 执行了空事务,而无视跳过 master 传递过来的有问题的 binlog 从而达到跳过有问题事务的目的。

由于没有实操过主备切换,这里注意到资料大部分都提到 GTID 模式下只需要指定 change master to 新的机器即可。新的 master 会自动计算相关的位点。

  1. CHANGE MASTER TO MASTER_HOST='xxxx',MASTER_USER='xxx', MASTER_PASSWORD='xxx';
  2. master_auto_position=

Reference:

https://yq.aliyun.com/articles/155827  MySQL GTID 主从复制错误修复方法

https://www.douban.com/note/446551760/  RESET MASTER 和RESET SLAVE 命令的使用方法 注意事项

https://www.cnblogs.com/zhoujinyi/p/4717951.html  MySQL5.6 新特性之GTID

处理 MySQL 因为 SLAVE 崩溃导致需要手动跳过 GTID 的问题 | 关于 GTID的更多相关文章

  1. (转)mysql自增列导致主键重复问题分析

    mysql自增列导致主键重复问题分析...  原文:http://www.cnblogs.com/cchust/p/3914935.html 前几天开发童鞋反馈一个利用load data infile ...

  2. MySQL主库异常,从库手动切换为主库方案

    主库异常,从库手动切换为主库方案 1.登录从服务器,确认从服务器已经完成所有同步操作: mysql> stop slave io_thread mysql> show processlis ...

  3. Windows下搭建MySQL Master Slave

    一.背景 服务器上放了很多MySQL数据库,为了安全,现在需要做Master/Slave方案,因为操作系统是Window的,所以没有办法使用keepalived这个HA工具,但是我们可以接受人工进行切 ...

  4. Mysql复制-Slave库设置复制延迟

    mysql> stop slave; mysql> change master to master_delay=10;#单位是秒 mysql> start slave; mysql& ...

  5. MYSQL 配置slave故障

    之前为主从配置,后来分割成2个单实例.现在环境需要,重新配置为主从,之前参数都已配置好,直接启动,如下: mysql> change master to master_host='192.168 ...

  6. Windows下搭建MySQL Master Slave[转]

    Windows下搭建MySQL Master Slave 一.背景 服务器上放了很多MySQL数据库,为了安全,现在需要做Master/Slave方案,因为操作系统是Window的,所以没有办法使用k ...

  7. MySQL show slave status命令参数

    ? Slave_IO_State SHOW PROCESSLIST输出的State字段的拷贝.SHOW PROCESSLIST用于从属I/O线程.如果线程正在试图连接到主服务器,正在等待来自主服务器的 ...

  8. MySQL master/slave 模式

    1 .复制 Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的 数据复制到其它主机(slaves)上,并重 ...

  9. MySQL更改relay-bin名称导致同步停止的解决办法

    今天在优化io的时候,移动了从库relay-bin的位置,并将hostname部分去掉了,启动后,从库slave状态如下: mysql> show slave status\G; ******* ...

随机推荐

  1. C#实现AES加密解密

    AES   AES 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法 Rijndael(读作rain-dahl)是由美 ...

  2. P2801 教主的魔法 (线段树)

    题目 P2801 教主的魔法 解析 成天做水题 线段树,第一问区间加很简单 第二问可以维护一个区间最大值和一个区间最小值,若C小于等于区间最小值,就加上区间长度,若C大于区间最大值,就加0 ps:求教 ...

  3. pychrom注册码

    http://angame.top/wx/web/zhucema/ YZVR7WDLV8-eyJsaWNlbnNlSWQiOiJZWlZSN1dETFY4IiwibGljZW5zZWVOYW1lIjo ...

  4. 想知道使用OPC服务器时如何设置DCOM?看完本文就懂了(下)

    接上文...... “安全”选项卡“安全”选项卡上,有3个选项需要设置. 启动权限 选择“使用默认值”选项 访问权限 选择“使用默认值”选项 配置权限 选择“自定义”选项,然后单击“编辑” 将打开一个 ...

  5. 下载Spring

    下载Spring Spring官网并不直接提供Spring的下载,Spring现在托管在GitHub上. 1.进入Spring官网 -> PROJECTS -> SPRING FRAMEW ...

  6. 使用ABAP操作Excel的几种方法

    这篇文章本来不在我计划之内,因为最近一个朋友微信上问到我这个问题,但我平时在SAP研究院工作中从没遇到过需要用ABAP操作Excel的需求,因此也没有太多技术实现细节可以分享给大家,只能泛泛写一些. ...

  7. Nginx 常用命令并实现最基本的反向代理

    nginx 命令 测试配置文件格式是否正确:$ nginx -t 启动:nginx 重启:nginx -s reload 获取nginx进程号: ps -ef|grep nginx 停止进程(mast ...

  8. linux档案和目录管理(后续)

    资料来自鸟哥的linux私房菜 四:档案和目录的预设权限和隐藏权限 umask:预设权限,相比与chomd的4,2,1权限,档案满分为666,目录满分为777,umask可以预设消除部分权限,比如一个 ...

  9. 洛谷 P2921 在农场万圣节Trick or Treat on the Farm题解

    题意翻译 题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节. 由于牛棚不太大,FJ通过指定 ...

  10. 如果在使用谷歌的gson的时候,在返回时间类型的数据的时候,

    可能会出现在long类型的时间后面多3个0 如下图所示 可以自己创建一个json序列化的类 public class Date2LongSerializer extends JsonSerialize ...