最近在进行purge binary logs的时候遇到一个错误如下,
- ERROR 4085 (HY000): Could not purge binary logs since another session is executing LOCK INSTANCE FOR BACKUP. Wait for that session to release the lock.
当然这个错误提示非常明显,就是在某个session执行了LOCK INSTANCE FOR BACKUP的情况下,不允许进行purge binary logs 命令,但是这个错误视乎没有遇到过,是不是8028新加入的报错呢?
一、什么是LOCK INSTANCE FOR BACKUP
在文章<<MySQL:8.0新的备份锁的浅析及其在xtrbackup的应用>>一文中我们详细描述过他的作用,以及其实现方式,如下。 这个操作主要堵塞的是DDL操作,包含不限于如下一些常见的操作:
CREATE_TABLE、CREATE_INDEX、ALTER_TABLE、TRUNCATE、DROP_TABLE、LOAD、CREATE_DB
、DROP_DB、ALTER_DB、RENAME_TABLE、DROP_INDEX、CREATE_VIEW、DROP_VIEW、CREATE_TRIGGER、DROP_TRIGGER、CREATE_EVENT、ALTER_EVENT、DROP_EVENT、IMPORT、RENAME_USER、DROP_USER、ALTER_USER、GRANT、REVOKE、GRANT_ROLE、REVOKE_ROLE、DROP_ROLE、CREATE_ROLE、OPTIMIZE、CREATE_FUNCTION、CREATE_PROCEDURE、DROP_PROCEDUR、DROP_FUNCTION、ALTER_PROCEDURE、ALTER_FUNCTION、REPAIR、ANALYZE、ALTER_TABLESPACE
我也随意测试了一些操作,确实都会被堵塞。从内部来看,实际上这个操作的功效依然是通过MDL LOCK的实现的,其策略为m_scoped_lock_strategy,那么从scoped策略的兼容性来看,如下:
对于lock instance for backup本生而言实际上是做了的如下操作:
Sql_cmd_lock_instance::execute
->acquire_exclusive_backup_lock
->acquire_mdl_for_backup
获取的MDL LOCK为 MDL_key::BACKUP_LOCK+MDL_SHARED(S)
并且看起来 MDL_key::BACKUP_LOCK的锁类型只会是MDL_SHARED(S)或者MDL_INTENTION_EXCLUSIVE(IX),因为acquire_mdl_for_backup里有断言:
DBUG_ASSERT(mdl_type == MDL_SHARED || mdl_type == MDL_INTENTION_EXCLUSIVE);
对于上面提到的会被堵塞的这些操作,则是在响应的地方加入了获取 MDL_key::BACKUP_LOCK+MDL_INTENTION_EXCLUSIVE(IX) 根据兼容矩阵,S和IX并不兼容,但是IX和IX之间是兼容的,因此只要不执行lock instance for backup操作,则不会有任何影响。而对于用户而言会发现processlist出现Waiting for backup lock字样则为这样的堵塞。测试如下:
mysql> show processlist;
+----+------+-----------+---------+---------+------+-------------------------+-------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+---------+---------+------+-------------------------+-------------------+
| 11 | root | localhost | testpri | Query | 4 | Waiting for backup lock | OPTIMIZE table t1 |
| 12 | root | localhost | t10 | Sleep | 175 | | NULL |
| 13 | root | localhost | testpri | Query | 0 | init | show processlist |
当然既然是MDL LOCK,它同样受到参数lock_wait_timeout参数的影响。比如我这里的操作为OPTIMIZE如下:
mysql> OPTIMIZE table t1;
+------------+----------+----------+--------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+------------+----------+----------+--------------------------------------------------------+
| testpri.t1 | optimize | Error | Lock wait timeout exceeded; try restarting transaction |
| testpri.t1 | optimize | status | Operation failed |
+------------+----------+----------+--------------------------------------------------------+
2 rows in set (2 min 0.01 sec)
需要的注意的这个锁并不会堵塞任何DML和SELECT操作(即便是mysiam表也不会堵塞DML操作),但是保护了元数据的正确性。如果要获取的一致的数据我们就需要额外的机制也就是下面谈到的ps.log_status。
二、LOCK INSTANCE常用场景
关于LOCK INSTANCE FOR BACKUP的常用场景大概有2个地方,如下,
- xtrabackup:xtrabackup在一开始就上了lock instance,而在备份即将结束的时候才解锁,因此整个xtrabackup期间不允许进行DDL操作。大概流程如下
- clone:在8.0.27之前clone期间不允许DDL操作,在8.0.27和其之后加入了参数clone_block_ddl进行控制,默认为flase,也就是允许DDL操作,但是需要注意的是如果修改参数,修改捐献节点是没有用的,需要修改加入节点。官方文档描述如下
- 实现大概在myclone::Server::init_storage中有如下
/* Acquire backup lock */
if (block_ddl()) {
auto failed = mysql_service_mysql_backup_lock->acquire(
thd, BACKUP_LOCK_SERVICE_DEFAULT, m_client_ddl_timeout);
这里可以看到就是lock instance的调用
mysql_acquire_backup_lock
->acquire_exclusive_backup_lock
->acquire_mdl_for_backup
->MDL_context::acquire_lock
三、8028加入新报错的原因
而如前文所言,在8.0.28中为了防止在lock instance for backup下能够修改文件,因此把清理binlog也加入其中,所以有了新的报错,引入这个错误的BUG修复如下,
也就是修复这个BUG引入的新的报错,主要增加的判定函数就是,
以上。。。