记一次 MySQL 数据库单表恢复事故处理

公司web服务架设在阿里云全家桶上,数据库用的也是RDS

记一次MySQL数据库单表恢复事故处理

昨晚10点,运营同事在社区发文章,提示创建失败,查看接口项目的日志,是detail字段的类型为text,可能是不够,需要加长,我选择了mediumtext类型。

数据类型 长度
TINYTEXT 256 bytes 
TEXT 65,535 bytes~64kb
MEDIUMTEXT  16,777,215 bytes~16M
BLONGTEXT 4,294,967,295 bytes~4GB

然后执行一个DDL语句,如下:

ALTER TABLE `databasename`.`tablename` CHANGE COLUMN `question_detail` `question_detail` mediumint  DEFAULT NULL COMMENT '内容';

执行完了,好的,告诉运营同事,看下可以发文章了么?

记一次MySQL数据库单表恢复事故处理

还是不行,哦,DDL写错了,应该是【mediumtext】,这里错了,把正确的DDL语句执行一遍,再问下运营同事

ALTER TABLE `databasename`.`tablename` CHANGE COLUMN `question_detail` `question_detail` mediumtext  DEFAULT NULL COMMENT '内容';

记一次 MySQL 数据库单表恢复事故处理

基于一个好的习惯,我再去社区确认下,运营同事的新帖子内容挺不错,在随便点点别的帖子。

嗯?我凑???社区全部帖子的内容变成0了,如下

记一次MySQL数据库单表恢复事故处理
懵逼了,生产事故吖,看看咋回事,一个想法闪过,sql有问题,我用navicat生成的sql语句,更新后的数据类型应该是【mediumtext】,结果我敲到med的时候,他就主动补全了【mediumint】,没有看清,就放到生产执行了,一下子把所有detail的内容,强制转换成了数字??

黑人问号脸.jpg

ok,开始想办法恢复数据,中间各种想办法,最后依靠阿里云提供的数据备份管理功能,和本人一瞬间暴涨的工作效率和好运气,在今天凌晨1点搞定了。

记一次MySQL数据库单表恢复事故处理

记一次MySQL数据库单表恢复事故处理

记一次MySQL数据库单表恢复事故处理

记一次 MySQL 数据库单表恢复事故处理

至此,我得到了这个表本来的数据了,好在备份时间和发成事故的时间很相近,又是过年期间发帖频率很低,查一下表内行数,好的,备份库的贴子表只差一个生产库一行,应该就是运营那一篇了,哈哈哈。

执行一个兜底命令,重命名帖子表,先不要删掉这个表,避免一错再错

RENAME TABLE  aws_question to aws_question_bak;

然后把导出来的.sql文件上传到可以连接生产库的服务器,然后把这个.sql执行下,导入到生产库里

$ mysql -h hostname -u username -p < restore.sql 
Enter password:   #输入root用户的密码。

再回来看看贴子,好的,数据恢复了。

记一次 MySQL 数据库单表恢复事故处理

回过头来,我们在执行一遍更新字段数据类型的sql

ALTER TABLE `databasename`.`tablename` CHANGE COLUMN `question_detail` `question_detail` mediumtext  DEFAULT NULL COMMENT '内容';

把运营同事新写的文章,从bak表拿出来,导入到本表中,至此,数据完全存进去了。

😁Happyending😁

记一次 MySQL 数据库单表恢复事故处理

本作品采用《CC 协议》,转载必须注明作者和本文链接
是非之外有一座花园,我们会在那里相遇
Martist
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 4

所以,这次的总结就是,有些字段一定要大大大,一开始就很大,就不会出现这种事故的意思吗 :joy:

4年前 评论

我认为这类事故的主要教训是:

生产环境上的操作一定尽可能避免「人工操作」。将 SQL 语句写成 Migration 进到 Git,经过多人审查核对之后 Merge,再由 CI/CD 执行比较好。我司目前对于 Migration 的 CI/CD 的流程主要如下:

  1. php artisan down,确保后续的流程中不会有数据变更。
  2. 主动向云服务商提交 Create Snapshot 的请求。
  3. 等待 Snapshot 创建完成,开始执行 Migrations。
  4. 出现错误,等待人工回滚;未出现错误,则 php artisan up

同时整个流程有 Slack 消息通知,确保可回滚、回滚不会丢数据、责任到人、可追溯。

file

说了这么多,欢迎加入我司:https://join.rightcapital.com

逃,2333(

4年前 评论
L学习不停 4年前
幽弥狂 4年前
TimJuly 4年前
Wi1dcard (作者) 4年前
Wi1dcard (作者) 4年前
幽弥狂 4年前
Wi1dcard (作者) 4年前
Martist

@L学习不停 对生产心怀敬畏

4年前 评论

竟然还有停服更新数据库的,SLA够用么

@TimJuly 我们的产品是面向企业的,另外用户都在美国,并且每周 Cut release 很规律。因此我们每周有固定的 Maintenance window,大约在美东时间半夜,刚好是国内下午,几乎不会影响用户使用。

另外我认为,即使不中断服务,在执行 DDL 操作的时候也会造成表锁,具体表现就是卡住、或是 503 Service Unavailable;倒不如提前向用户公开 Maintenance window,并给予提示 此时我们正在维护,我们的维护时间窗口为 XX,请您 XX 时间后再试 更加友好。

此外,以个人角度说一点「傲气」的话。以我的经验来看,中小规模数据库,大多 Migration 时间都比较短,往往一次小事故造成的 Downtime 都比它长。花大量精力保持不停机执行数据库 Migration,还不如把时间用在优化日常 DevOps 流程中,尽可能避免人工失误带来的、不可预期的服务不可用。

4年前 评论
L学习不停 4年前
TimJuly 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!