MySQL内核月报 2015.01-MySQL · 新增特性· DDL fast fail

背景

项目的快速迭代开发和在线业务需要保持持续可用的要求,导致MySQL的ddl变成了DBA很头疼的事情,而且经常导致故障发生。本篇介绍RDS分支上做的一个功能改进,DDL fast fail。主要解决:DDL操作因为无法获取MDL排它锁,进入等待队列的时候,阻塞了应用所有的读写请求问题。

MDL锁机制介绍

首先介绍一下MDL(METADATA LOCK)锁机制,MySQL为了保证表结构的完整性和一致性,对表的所有访问都需要获得相应级别的MDL锁,比如以下场景:


session 1对t1表做查询,首先需要获取t1表的MDL_SHARED_READ级别MDL锁。锁一直持续到commit结束,然后释放。
session 2对t1表做DDL,需要获取t1表的MDL_EXCLUSIVE级别MDL锁,因为MDL_SHARED_READ与MDL_EXCLUSIVE不相容,所以session 2被session 1阻塞,然后进入等待队列。
session 3对t1表做查询,因为等待队列中有MDL_EXCLUSIVE级别MDL锁请求,所以session3也被阻塞,进入等待队列。

这种场景就是目前因为MDL锁导致的很经典的阻塞问题,如果session1长时间未提交,或者查询持续过长时间,那么后续对t1表的所有读写操作,都被阻塞。 对于在线的业务来说,很容易导致业务中断。

aliyun RDS分支改进

DDL fast fail并没有解决真正DDL过程中的阻塞问题,但避免了因为DDL操作没有获取锁,进而导致业务其他查询/更新语句阻塞的问题。

其实现方式如下:

alter table test.t1 no_wait/wait 1 add extra int;
在ddl语句中,增加了no_wait/wait 1语法支持。

其处理逻辑如下:

首先尝试获取t1表的MDL_EXCLUSIVE级别的MDL锁:

当语句指定的是no_wait,如果获取失败,客户端将得到报错信息:ERROR : Lock wait timeout exceeded; try restarting transaction。
当语句指定的是wait 1,如果获取失败,最多等待1s,然后得到报错信息:ERROR : Lock wait timeout exceeded; try restarting transaction。

另外,除了alter语句以外,还支持rename,truncate,drop,optimize,create index等ddl操作。

与Oracle的比较

在Oracle 10g的时候,DDL操作经常会遇到这样的错误信息:

ora-00054:resource busy and acquire with nowait specified
即DDL操作无法获取表上面的排它锁,而fast fail。

其实DDL获取排他锁的设计,需要考虑的就是两个问题:

1. 雪崩
如果你采用排队阻塞的机制,那么DDL如果长时间无法获取锁,就会导致应用的雪崩效应,对于高并发的业务,也是灾难。
2. 饿死
如果你采用强制式的机制,那么要防止DDL一直无法获取锁的情况,在业务高峰期,可能DDL永远无法成功。

在Oracle 11g的时候,引入了DDL_LOCK_TIMEOUT参数,如果你设置了这个参数,那么DDL操作将使用排队阻塞模式,可以在session和global级别设置, 给了用户更多选择。

时间: 2024-08-01 09:00:38

MySQL内核月报 2015.01-MySQL · 新增特性· DDL fast fail的相关文章

MySQL内核月报 2014.11-TokuDB· 引擎特性· FAST UPDATES

MySQL的update在执行时需要做read-modify-write: 操作路径还是比较长的,TokuDB提供了fast update语法,让"某些"场景下update更快,无需做read和modify直接write. 用法: NOAR语句: 语义是:插入一条记录,如果该记录存在(id为1),就对count的值做加法操作,不存在则做插入. 注意: fast updates的条件是比较苛刻的,必须满足: 看了这些苛刻的条件后,有种"臣妾做不到"的感觉了吧,可以看出TokuDB一直为细节而努力.

MySQL内核月报 2015.02-MariaDB · 特性分析· Per-query variables

自MariaDB 10.1.2起,MariaDB提供了一种"Per-query variables的方式来为Query设置语句级变量,通过 SET STATEMENT 语句可以为接下来要执行的语句设置一些系统变量值. 语法 SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement> varN是一个系统变量,valueN是一个常量值.但是有部分变量是不支持的,在这个章节的末尾列出了所有不支持的变量. 一条 "S

MySQL内核月报 2015.02-MariaDB · 特性分析· 表/表空间加密

Google向MariaDB 10.1.13(暂未Release)贡献了这个补丁,可以对表/表空间进行加密. 加密过的表可以防止某些非授权用户访问或偷取磁盘然后通过访问原始数据文件来偷取数据.当然,假设你已经把密钥文件存储在另一个系统上.但是,使用加密可能会降低差不多10%的性能.目前,只有XtraDB/InnoDB引擎能完全支持加密. MariaDB在InnoDB/XtraDB中支持两种方式的加密: Table encryption(表级加密): 只有在创建时指定 PAGE_ENCRYPTIO

MySQL内核月报 2015.02-PgSQL · 特性分析· pg_prewarm

PostgreSQL内核中引入了一个很有意思的插件,pg_prewarm.它可以用于在系统重启时,手动加载经常访问的表到操作系统的cache或PG的shared buffer,从而减少检查系统重启对应用的影响.这个插件是这个通过这个patch加入PG内核的. pg_prewarm的开发者在设计pg_prewarm时,把它设计成一个执行单一任务的工具,尽求简单,所以我们看到的pg_prearm功能和实现都非常简单.下面我们对它进行性能实测并分析一下它的实现. 基本信息 利用下面的语句可以创建此插件

MySQL内核月报 2015.02-PgSQL · 特性分析· Replication Slot

PostgreSQL 9.4 已于2014年底正式发布了(阿里云的RDS将支持PG 9.4).在这个版本,我们看到了像Jsonb, Logical Decoding, Replication Slot等新功能.对于Replication Slot,文档上介绍的不多,乍一看让人比较难理解是做什么的.其实,Replication Slot的出现,主要是为最终在PG内核实现逻辑复制和双向复制铺路的(目前,逻辑和双向复制在内核中还缺少很多核心功能点,需要借助BDR插件,见PG官方wiki ,引入Repl

MySQL内核月报 2015.02-TokuDB · 特性分析· 日志详解

TokuDB的日志跟InnoDB不一样,它有两类文件: redo-log文件(以.tokulog[序号]为扩展名) rollback日志文件(tokudb.rollback) 接下来就简单唠唠这两类文件的内部细节. 1) redo-log 记录的不是页而是对Fractal-Tree索引的操作日志. log格式: content里记录的是具体的日志内容,比如insert操作,content就是: TokuDB在做恢复的时候,会找到上次checkpoint时的LSN位置,然后读取log逐条恢复. 为

MySQL内核月报 2015.01-TokuDB·特性分析· Optimize Table

来自一个TokuDB用户的"投诉": https://mariadb.atlassian.net/browse/MDEV-6207 现象大概是: 用户有一个MyISAM的表test_table: 转成TokuDB引擎后表大小为92M左右: 执行"OPTIMIZE TABLE test_table": 再次执行"OPTIMIZE TABLE test_table": 继续执行: 基本稳定在这个大小. 主索引从47M-->63M-->79

MySQL内核月报 2015.02-MySQL · 答疑释惑· 5.5 和 5.6 时间类型兼容问题

问题描述 5.6.4及以上版本,datetime,time,timestamp的Binlog在5.6.4以下的备库无法执行,如: 5.6.16(主库): create table t1(t datetime default now()); insert into t1 values(now()); 5.5.18(备库): show slave stauts\G ; 此时备库中断,报错:Last_Errno: 1677, 描述信息:Last_Error: Column 1 of table t1.

MySQL内核月报 2015.03-MySQL · 性能优化· 5.7.6 InnoDB page flush 优化

在上期的月报中,我们已经详细介绍了Oracle MySQL以及社区分支最新的对InnoDB page flush的优化.在最近release的5.7.6版本中又有了进一步的改进.主要包括以下几点修改 修改一.更精确的loop时间 Page cleaner每做srv_flushing_avg_loops次flush后,会去计算刷脏和Redo LSN增长的速度.由于每次Page cleaner的工作量是自适应的,一次flush操作的时间可能超过1秒. 在新版本中,统一采用当前时间和上次更新速率的时间