首先记录一个教训吧,任何数据库的操作,请三思而行,要做到就算领导同事把你催得欲生欲死,你也要想清楚再操作,否则你一个简单的操作,就有可能让你通宵。
这次就是一个教训: 我们本身的数据库集群是 双主互相切换的,今早突然有开发反馈: 数据库无法写入了,生产上已经无法进行出单操作。 哎呀妈呀,我本人之前就是个开发,搭建数据库、数据库运维全靠这三个月业务时间自修的,当时慌得一批,第一个想法就是:是不是我搭的集群啥子配置有问题啊?当时我记得我设置的默认主库是 A, 我通过 Mycat 入口进行insert 操作,然后到 A 库验证,果然没有写入。应用上注册用户,提示成功,但是库里就是没有数据,一脸蒙蔽。查看数据库 slave status, 发现有同步阻塞。这个时候领导来了,同事也貌似有点慌,一个项目组的人就望着你一个,感觉高考我都没这么紧张过。当时的确没找到出问题的原因,而且也是为了尽快回复应用,我就想,暂时将一台数据库shut down 掉,回复单点访问,同步的问题,之后查到原因后再解决。效果立竿见影,应用马上可以使用了,大家都暂时松了一口气。但是,万万没想到,这个shut down 操作却让我通宵到了3点过。。。
其实这个问题原因很简单,因为 quartz 表数据不一致,导致同步失败,但是我当时忘记了,之前上线前做容灾测试时,把 A、B库轮流关闭,中间件已经把数据库的主库从 A 调整到 B。此时,插入数据都是 在 B 完成的,查询数据在 A 完成,这就发生了:由于同步阻塞,插入在 A 成功,但是 查询 B 却没有数据,在开发人员来看,数据库就是写入不了。 这也让我吸取了一个教训:别人反馈给你的,永远是表象,你需要结合你自身的知识及资料做出判断,当然,部分也是因为我是第一次进行 DBA 运维的原因吧。
本身这个问题很简单:
1、 查看复制状态:show slave status \G;
2、 找到出错的 position
3、 通过 --start-datetime 是指定时间,或者 --start-position="720414968" 起始位置
/app/mysql/bin/mysqlbinlog --no-defaults --start-datetime='2018-11-12 9:50:00' /app/mysql/data/mybinlog3306001.000019 > /app/new2.sql
将二进制binlog导出成 sql 文件, 如果你my.cnf中 binlog_format = row 那么你查看就需要使用这个语句:
/app/mysql/bin/mysqlbinlog --no-defaults --base64-output=DECODE-ROWS -v --start-datetime='2018-11-13 2:00:00' /app/mysql/data/mybinlog3306002.000017 > /app/13.sql
因为 row 方式的日志,sql 语句是 base64加密的。
4、 修正从库数据;
5、 set global sql_slave_skip_counter=1; 自动跳过一个事务进行下一个同步
6、 start slave; 重新开始同步
但是由于我 误操作,将主库停了, B库(停止数据库前的主库)拥有停库前的所有数据, A 库拥有停主库后的当天数据,没法子,最后我只能做一下操作,来将当天 A 库的数据导入到 B 库,之后再以 B 库为主库运行。
操作步骤如下:
1、 整体备份 A 库;
2、 导出 A 库从10点开始的数据, 并做 A库 的备份;
3、 将 10 点之后数据导入B库;
4、 重新调整主从复制
5、 mycat 策略变更,指定 B 为主库
整体备份库的 SQL为:
./mysql/bin/mysqldump -uroot -p密码 --all-databases > /app/backup.sql
另外导出 A 库指定时间点后的数据:
./mysql/bin/mysqlbinlog --no-defaults --start-datetime='2018-11-12 10:00:00' /app/mysql/data/mybinlog3306001.000019 > /app/new2.sql