线上服务宕机,码农试用期被毕业,原因竟是给MySQL加个字段
1. 问题:怎么给线上表加字段?
工作中最常遇到的问题,怎么给线上频繁使用的大表添加字段?
比如:给下面的用户表(user)添加年龄(age)字段。
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(100) DEFAULT NULL COMMENT '姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
有同学会说,这还不简单,直接加不加完了,用下面的命令:
ALTER TABLE `user` ADD `age` int NOT NULL DEFAULT '0' COMMENT '年龄';
添加完,再查看一下表结构:
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(100) DEFAULT NULL COMMENT '姓名',
`age` int NOT NULL DEFAULT '0' COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
这不是添加成功了吗?有什么呀!
是的,线下数据库怎么整都行,但是如果在线上数据库这样操作,整个服务都有宕机的风险!自己也离毕业不远了。
不是危言耸听,我们找个case测试一下:

- Session1启动了一个事务,没有提交。
- Session2执行添加列的操作,被阻塞。
- 更严重的是,Session3执行简单查询的语句也被阻塞了。
2. 线上服务宕机的原因
为什么会出现这种情况呢?
原因是在执行查询语句的时候,MySQL自动加了MDL锁(metadata lock,即元数据锁)。
不行的话,我们可以再执行一下show processlist命令,查看有哪些正在执行的进程:

可以清楚的看到Session2和Session3的语句正在等待MDL锁,Waiting for table metadata lock。
MDL锁的作用是什么?
为了保证并发操作下数据的一致性。
如果一个事务正在执行中,另一个在这时修改了表结构,不但可能导致当前事务出现不可重复读的问题,还有可能连事务都无法提交。
什么时候会加MDL锁?
MDL锁是MySQL自动隐式加锁,无需我们手动操作。
在我们执行DDL语句的时候,MySQL自动添加MDL读锁。
在我们执行DML语句的时候,MySQL自动添加MDL写锁。
读锁与读锁之间不互斥,读锁与写锁、写锁与写锁之间互斥。
注意:MDL锁是表锁,会对整张表加锁。
普及额外的小知识点,什么是DML和DDL:
DML(Data Manipulation Language)数据操纵语言:
适用范围:对表数据进行操作,比如 insert、delete、select、update等。
DDL(Data Definition Language)数据定义语言:
适用范围:对表结构进行操作,比如create、drop、alter、rename、truncate等。
3. 如何优雅的给线上表加字段
既然修改表结构的时候,MySQL会自动添加表锁,并且是写锁,会阻塞后续的所有读写请求,造成非常严重的后果。
还有没有办法能优雅的给线上表添加字段呢?
当然有,从MySQL5.6版本开始增加了Online DDL,作用就是在执行DDL的时候,允许并发执行DML。简单翻译就是修改表结构的时候,也能同时支持并发执行增删查改操作。
从MySQL8.0版本开始又优化了Online DDL,支持快速添加列,可以实现给大表秒级加字段。
具体用法就是在DDL语句后面增加两个参数ALGORITHM和LOCK。
比如下面这样:
ALTER TABLE `user` ADD `age` int NOT NULL DEFAULT '0' COMMENT '年龄',
ALGORITHM=Inplace,
LOCK=NONE;
这两个参数分别是干嘛用的?有哪些选项呢?
ALGORITHM可以指定使用哪种算法执行DDL,可选项有:
Copy:
拷贝方式,MySQL5.6 之前 DDL 的执行方式,过程就是先创建新表,修改新表结构,把旧表数据复制到新表,删除旧表,重命名新表。执行过程非常耗时,产生大量的磁盘IO和占用CPU,还有使Buffer poll失效,而且需要锁住旧表,性能较差,现在基本很少使用。
Inplace:
原地修改,MySQL5.6开始引入的,优点是不会在Server层发生表数据拷贝,过程中允许并发执行DML操作。过程就是先添加MDL写锁,执行初始化操作,然后降级为MDL读锁,执行DDL操作(比较耗时,允许并发执行DML操作),升级为MDL写锁,完成DDL操作。
Instant:
快速修改,MySQL8.0开始引入的,可以实现快速给大表添加字段。
性能依次是,Instant > Inplace > Copy。
LOCK可以指定执行过程中,是否加锁,可选项有:
NONE
不加锁,允许DML操作。
SHARED
加读锁,允许读操作,禁止DML操作。
DEFAULT
默认锁模式,在满足DDL操作前提下,默认锁模式会允许尽可能多的读操作和DML操作。
EXCLUSIVE
加写锁,禁止读操作和DML操作。
Online DDL并不是支持所有DDL操作,看一下到底支持哪些操作?
| 操作 | Instant | Inplace | Rebuilds Table | 允许并发DML | 仅修改元数据 |
|---|---|---|---|---|---|
| 添加列 | Yes | Yes | No | Yes | No |
| 删除列 | No | Yes | Yes | Yes | No |
| 重命名列 | No | Yes | No | Yes | Yes |
| 更改列顺序 | No | Yes | Yes | Yes | No |
| 设置列默认值 | Yes | Yes | No | Yes | Yes |
| 更改列数据类型 | No | No | Yes | No | No |
| 设置VARCHAR列大小 | No | Yes | No | Yes | Yes |
| 删除列默认值 | Yes | Yes | No | Yes | Yes |
| 更改自动增量值 | No | Yes | No | Yes | No |
| 设置列为null | No | Yes | Yes | Yes | No |
| 设置列not null | No | Yes | Yes | Yes | No |
像最常见的添加列就可以使用Instant,而像删除列、重命名列、更改列数据类型就只能使用Inplace了。

线上服务宕机,码农试用期被毕业,原因竟是给MySQL加个字段的更多相关文章
- 最近两周我们接触到的两种线上抓娃娃机的技术实现方案(一种RTSP/一种RTMP)
线上抓娃娃机需求 最近线上抓娃娃机的项目火爆了,陆陆续续几十款线上抓娃娃机上架,还有一大波正在开发上线中,各大视频云提供商都在蹭热度发布自己的线上抓娃娃机方案,综合了一下,目前线上抓娃娃机的视频需求无 ...
- 记-ItextPDF+freemaker 生成PDF文件---导致服务宕机
摘要:已经上线的项目,出现服务挂掉的情况. 介绍:该服务是专门做打印的,业务需求是生成PDF文件进行页面预览,主要是使用ItextPDF+freemaker技术生成一系列PDF文件,其中生成流程有:解 ...
- 线上服务的FGC问题排查,看这篇就够了!
线上服务的GC问题,是Java程序非常典型的一类问题,非常考验工程师排查问题的能力.同时,几乎是面试必考题,但是能真正答好此题的人并不多,要么原理没吃透,要么缺乏实战经验. 过去半年时间里,我们的广告 ...
- 记一次线上服务CPU 100%的处理过程
告警 正在开会,突然钉钉告警声响个不停,同时市场人员反馈客户在投诉系统登不进了,报504错误.查看钉钉上的告警信息,几台业务服务器节点全部报CPU超过告警阈值,达100%. 赶紧从会上下来,SSH登录 ...
- 糟了,线上服务出现OOM了
前言 前一段时间,公司同事的一个线上服务OOM的问题,我觉得挺有意思的,在这里跟大家一起分享一下. 我当时其实也参与了一部分问题的定位. 1 案发现场 他们有个mq消费者服务,在某一天下午,出现OOM ...
- Linux(2)---记录一次线上服务 CPU 100%的排查过程
Linux(2)---记录一次线上服务 CPU 100%的排查过程 当时产生CPU飙升接近100%的原因是因为项目中的websocket时时断开又重连导致CPU飙升接近100% .如何排查的呢 是通过 ...
- 由Redis的hGetAll函数所引发的一次服务宕机事件
昨晚通宵生产压测,终于算是将生产服务宕机的原因定位到了,心累.这篇博客,算作一个复盘和记录吧... 先来看看Redis的缓存淘汰算法思维导图: 说明:当实际占用的内存超过Redis配置的maxmemo ...
- 线上服务CPU100%问题快速定位实战
功能问题,通过日志,单步调试相对比较好定位. 性能问题,例如线上服务器CPU100%,如何找到相关服务,如何定位问题代码,更考验技术人的功底. 58到家架构部,运维部,58速运技术部联合进行了一次线上 ...
- 线上服务内存OOM问题定位[转自58沈剑]
相信大家都有感触,线上服务内存OOM的问题,是最难定位的问题,不过归根结底,最常见的原因: 本身资源不够 申请的太多 资源耗尽 58到家架构部,运维部,58速运技术部联合进行了一次线上服务内存OOM问 ...
随机推荐
- centos安装torch==1.4.0与相关细节
对于某些直接安装torch==1.4.0报错的情况(没错,就是我遇到了) 在网上查找了,大概的解决方法是先安装一个低版本的torch和torchvision, torchvision是pytorch中 ...
- C#枚举器/迭代器
一.枚举器 1.为什么foreach可以顺序遍历数组? 因为foreach可以识别可枚举类型,通过访问数组提供的枚举器对象来识别数组中元素的位置从而获取元素的值并打印出来. 2.什么是枚举器?可枚举类 ...
- 有趣的特性:CHECK约束
有趣的特性:CHECK约束 功能说明 在MySQL 8.0.16以前, CREATE TABLE允许从语法层面输入下列CHECK约束,但实际没有效果: CHECK (expr) 在 MySQL 8.0 ...
- OpenCV4之C++入门详解
OpenCV之C++入门 1.Visual Studio安装及环境配置与搭建 下载地址:https://my.visualstudio.com/Downloads?q=Visual,下载后按照说明安装 ...
- 金灿灿的季节 - Apache DolphinScheduler收获5位新Committer
在这个金灿灿的收获季节,经过 Apache DolphinScheduler PPMC 们的推荐和投票,Apache DolphinScheduler 收获了 5 位新Committer .他们是:n ...
- Windows 查看端口占用并关闭
在启动服务的时候,可能会遇到端口被占用的情况. 这时候就需要知道哪个服务占用了这个端口,并将其关闭. 然后再启动服务就不会存在端口占用了. 这里以 Tomcat 的默认端口 8080 为例. 打开命令 ...
- python金牌班第五周周末总结
python金牌班第五周周末总结 常见内置函数 1.abs # 求绝对值,将负数变为整数,并且得出的值只有正数print(abs(-999)) # 999 2.all # 当在经历条件判断时所有的返回 ...
- Usmjeri(COCI2017.2)题解
题意 给一棵N个节点的树,编号从1到N,再给定m对点(u,v),你要将树上的每条无向边变为有向边,使得给定的点对都满足u能到达v或v能到达u.问有多少种不同的方案,答案对(1e9+7)求余. 1 ≤ ...
- C#基础_C#判断文件是否被打开
1.用文件流判断 using System; using System.Collections.Generic; using System.IO; using System.Linq; using S ...
- 基于Vue3实现一个前端埋点上报插件并打包发布到npm
前端埋点对于那些营销活动的项目是必须的,它可以反应出用户的喜好与习惯,从而让项目的运营者们能够调整策略优化流程提高用户体验从而获取更多的$.这篇文章将实现一个Vue3版本的埋点上报插件,主要功能有 通 ...