不停机修改线上 MySQL 主键字段 以及其带来的问题和总结思考
起因:
线上 user 数据库没有自增字段,数据量已经达到百万级。无论是给离线仓库还是数据分析同步数据,没有主键自增 id 都是杀手级的困难。所以在使用 create_time 痛苦了几次之后准备彻底来解决这个问题。
解决问题的思路:
当时理了两个思路,一个是直接找个夜生人静的夜晚,drop 掉目前的 primary key 。然后再 add 一个 id 字段做 primary key auto increament 。我觉得这个方法对于 100w 以下的数据表是一个不错的方法,首先简单,其次找个夜生人静的晚上也不会有非常长时间的锁表。当然最好使用 online ddl 进行操作就更好了。我们碰到的稍微现实一点问题是,目前线上表还会跟离线表进行同步。然后也想挑战一下不停机不锁表的切换。所以规划了一个思路是
1. 首先建一个变更 ddl 后的表,在这里表现为已经设置好自增 id 的情况。
2. 将线上数据导入该表。并且保持两张表同步。
- 方案1: 如果数据比较多 例如已经是1000w 插入了,而且插表频率高,那么建议使用类似于 maxwell 数据同步工具,读取 binlog 时时同步让两张表时刻保持一致。最后找一个表没那么热的时候,rename 表即可。 rename 操作可以在一个命令里面执行几乎是秒切,如果跟上线上没有延迟那么基本上不会有数据丢失,如果切换的时候表比较热,可能会有几条不一致可以手动修复即可。
- 方案2: 如果数据没有那么多 比如只是百万级别,而且也有表明显不热的时候比如说晚上 3 4 点的时候。那么你可以通过导入数据,然后根据 update_time 字段时时跟上线上表。然后最后再切换之前再执行一次 根据 update_time 的更新脚本,然后立即完成 rename 操作。这样的操作 在数据量不大表不热的时候甚至不会有数据的不一致。大家可以根据需求来选择具体的方案。
3. 找个夜深人静的时候 rename 表完成两张表的切换。
其实从流程上来看还是比较简单的,但是实际处理的时候还是遇到不少问题。
1. 我在线上进行两张表同步的时候发现 slave 明显跟不上 master,而且延迟的时间越来越大。后来查阅了一些资料发现是当 master 发生大量写入的时候, slave 是很有可能发生慢慢跟不上 master 的情况。引起这个情况有可能是 socket 网络通信上的跟不上,可能是 slave 机器的配置不行,更有可能是没有开启并行复制导致吞吐量跟不上。因为主库上可能是开启多进程在写,从库却是单进程在跟复制,慢慢落后是理所当然的,但是只要这种情况不长时间持续,可以发现离线库在主库完成大并发写入之后会慢慢恢复正常。
2. 切换方案跟太多别的业务交杂在一起,例如还去考虑同时兼容我们的离线分析库,把问题搞得十分复杂。下次在思考类似需求的解决方案的时候,一定要遵循最小优化原则。理论上来说离线分析库完全可以等切换完成之后全量重刷,由于已经有主键自增 id 了。刷新会变得比以前简单方便非常多,速度也会快很多。所以没有必要纠结同时兼容的问题。导致复制方案变得复杂最后导致出错。
3. 新键的表 ddl 一定不要随意改动上面的字段,理论上无论之前表字段有多不合理多恶心,如果没有在切换计划里面有比较全面的考量都不应该擅自删除字段。保持只增不减跟之前完全兼容。
最后这次切换虽然出了一些小岔子,但是总的来说比较顺利。目前已经正常跑了一周,应该稳定了。
Reference:
http://mysql.taobao.org/monthly/2016/04/08/ 常见的 MySQL slave 延迟问题
https://www.cnblogs.com/kevingrace/p/6065088.html MySQL binlog 总结
https://dev.mysql.com/doc/refman/5.6/en/rename-table.html 参考 MySQL 5.6 rename 文档
不停机修改线上 MySQL 主键字段 以及其带来的问题和总结思考的更多相关文章
- 线上Mysql数据库崩溃事故的原因和处理
前文提要 承接前文<一次线上Mysql数据库崩溃事故的记录>,在文章中讲到了一次线上数据库崩溃的事件记录,建议两篇文章结合在一起看,不至于摸不着头脑. 由于时间原因,其中只讲了当时的一些经 ...
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(八)线上Mysql数据库崩溃事故的原因和处理
前文提要 承接前文<一次线上Mysql数据库崩溃事故的记录>,在文章中讲到了一次线上数据库崩溃的事件记录,建议两篇文章结合在一起看,不至于摸不着头脑. 由于时间原因,其中只讲了当时的一些经 ...
- 记一次排查线上MySQL死锁过程,不能只会curd,还要知道加锁原理
昨晚我正在床上睡得着着的,突然来了一条短信. 啥,线上MySQL死锁了,我赶紧登录线上系统,查看业务日志. 能清楚看到是这条insert语句发生了死锁. MySQL如果检测到两个事务发生了死锁,会回滚 ...
- MySQL主键设计
[TOC] 在项目过程中遇到一个看似极为基础的问题,但是在深入思考后还是引出了不少问题,觉得有必要把这一学习过程进行记录. MySQL主键设计原则 MySQL主键应当是对用户没有意义的. MySQL主 ...
- mysql主键问题
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_22314145/article/details/80824660 MySQL主键 一. MyS ...
- 不停机替换线上代码? 你没听错,Arthas它能做到
写在前边 有没有这样一种感受,自己写的代码在开发.测试环境跑的稳得一笔,可一到线上就抽风,不是缺这个就是少那个反正就是一顿报错,线上调试代码又很麻烦,让人头疼得很.阿里巴巴出了一款名叫Arthas的工 ...
- MySQL主键设计盘点
目录 主键定义 主键设计和应用原则 主键生成策略 自增ID UUID 自建的id生成器 Twitter的snowflake算法 @ 最近在项目中用了UUID的方式生成主键,一开始只是想把这种UUID的 ...
- 原创 记录一次线上Mysql慢查询问题排查过程
背景 前段时间收到运维反馈,线上Mysql数据库凌晨时候出现慢查询的报警,并把原始sql发了过来: --去除了业务含义的sql update test_user set a=1 where id=1; ...
- MYSQL主键自动增加的配置及auto_increment注意事项
文章一 原文地址: http://ej38.com/showinfo/mysql-202971.html 文章二: 点击转入第二篇文章 在数据库应用,我们经常要用到唯一编号.在MySQL中可通过字 ...
随机推荐
- java 图片转换成base64字符串
import java.io.ByteArrayOutputStream; import java.io.FileInputStream;import java.io.FileOutputStream ...
- docker 13 dockerfile的保留字指令
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本. 构建三步骤:1.编写dockerfile文件:2.docker build:3.docker run doc ...
- Feature Extractor[SENet]
0.背景 这个模型是<Deep Learning高质量>群里的牛津大神Weidi Xie在介绍他们的VGG face2时候,看到对应的论文<VGGFace2: A dataset f ...
- linux驱动之中断处理过程C程序部分
当发生中断之后,linux系统在汇编阶段经过一系列跳转,最终跳转到asm_do_IRQ()函数,开始C程序阶段的处理.在汇编阶段,程序已经计算出发生中断的中断号irq,这个关键参数最终传递给asm_d ...
- C#打印字符串内容,例如打印Textbox内容
/// <summary> /// 打印txt文档 /// </summary> class PrintTxt { System.Drawing.Printing.PrintD ...
- Item 14: 如果函数不会抛出异常就把它们声明为noexcept
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 在C++98中,异常规范(exception specificat ...
- 容器互联(linking)
容器互联(linking)是一种让多个容器中的应用进行快速交互的方式. 它会在源和接受容器中间创建连接关系,接受容器可以通过容器名快速访问到源容器而不用指出具体的IP地址.
- python之socket模块详解--小白博客
主要是创建一个服务端,在创建服务端的时候,主要步骤如下:创建socket对象socket——>绑定IP地址和端口bind——>监听listen——>得到请求accept——>接 ...
- Linq中比较字符串类型的日期
一.在使用Linq时,想要比较字符串类型的日期时,参考以下: SQL语句: )select * from TableName where StartTime > '2015-04-08' )se ...
- c++入门之命名空间存在的意义
看过鸡啄米的C++编程入门系列教程的朋友,应该能注意到,在其中的很多实例中,都有这么一条语句:using namespace std;,即使用命名空间std,其作用就是规定该文件中使用的标准库函数都是 ...