[MySQL Bug]DDL操作导致备库复制中断

简介:

————————————————-

在MySQL5.1及之前的版本中,如果有未提交的事务trx,当执行DROP/RENAME/ALTER TABLE RENAME操作时,不会被其他事务阻塞住。这会导致如下问题(MySQL bug#989)

master:
未提交的事务,但SQL已经完成(binlog也准备好了),表schema发生更改,在commit的时候不会被察觉到。
slave:
在binlog里是以事务提交顺序记录的,DDL隐式提交,因此在备库先执行DDL,后执行事务trx,由于trx作用的表已经发生了改变,因此trx会执行失败。
在DDL时的主库DML压力越大,这个问题触发的可能性就越高
一个简单的例子:
session1,set autocommit=0,对表b执行一条DML
root@xxx 11:48:28>set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
root@xxx 11:48:35>insert into b values (NULL,4);
Query OK, 1 row affected (0.00 sec)
session2,执行rename table a to tmp_b
root@xxx 11:48:23>rename table b to tmp_b;
Query OK, 0 rows affected (0.01 sec)
session1:commit;
root@xxx 11:49:00>show binlog events;
+——————+—–+—-———+———–+——–—–+—————————————+
| Log_name         | Pos | Event_type  | Server_id | End_log_pos | Info                                  |
+——————+—–+—-———+———–+——–—–+—————————————+
| mysql-bin.000001 |   4 | Format_desc |        12 |         106 | Server ver: 5.1.48-log, Binlog ver: 4 |
| mysql-bin.000001 | 106 | Query       |        12 |         191 | use `xxx`; rename table b to tmp_b    |
| mysql-bin.000001 | 191 | Query       |        12 |         258 | BEGIN                                 |
| mysql-bin.000001 | 258 | Table_map   |        12 |         298 | table_id: 195 (xxx.b)                 |
| mysql-bin.000001 | 298 | Write_rows  |        12 |         336 | table_id: 195 flags: STMT_END_F       |
| mysql-bin.000001 | 336 | Xid         |        12 |         363 | COMMIT /* xid=737 */                  |
+——————+—–+—-———+———–+——–—–+—————————————+
显然当这样的Binlog同步到备库的话,必然会导致复制中断。
在5.1里可以通过如下步骤绕过bug:
>set autocommit = 0;
>lock tables t1 write;
> drop table t1 / alter table t1 rename to t2
rename table t1 to t2这样的DDL不适用于上述方法。
在5.5引入了MDL(meta data lock)锁来解决在这个问题,至于5.1,官方已经明确回复不会FIX,太伤感了。。。
我们来看看MDL是如何解决这个问题的,还是以rename为例吧
—————————————————————————————
我们知道,在5.5之前,当事务的一条语句执行完后,就会释放占有的数据字典锁,MDL的作用就是延迟这种锁的释放。
对于非事务表或者运行在autocommit=1时没有什么影响。
MDL的相关API和定义都在文件mdl.cc和mdl.h中
MDL锁的类型包括:
1. MDL_INTENTION_EXCLUSIVE
意向排他mdl锁,只用于范围锁(MDL_scoped_lock)。拥有该锁的可以获得单个对象升级的排他锁
该类型锁与其他IX锁相容,但和范围X和S锁不相容。
2.MDL_SHARED
共享mdl锁
当只对对象元数据感兴趣而无需访问对象的数据时使用
3.MDL_SHARED_HIGH_PRIO
更高优先级的共享mdl锁
更高优先级意味着和其他共享锁不一样,它可以忽略等待的排他锁请求。主要用于只需要访问metadata而非数据时。例如,填充一个i_s表时。
4.MDL_SHARED_READ
共享MDL读锁当试图从表中读取数据时加上该锁。持有该锁时,可以读取表的元数据和表的数据
5.MDL_SHARED_WRITE
共享MDL写锁,当试图修改表的数据时使用
持有该锁时可以读取表的元数据和表中的数据
主要适用于insert/delete/update,select…for update。不会作用于lock table write或者DDL。
6.MDL_SHARED_NO_WRITE
可升级的共享MDL锁,会阻塞所有的DML,但不阻塞读,可以升级为x MDL锁
和SNRW,SW不相容
在ALTER TABLE的第一阶段(表之间拷贝数据),允许并发的对表做select,但不允许更新
7.MDL_SHARED_NO_READ_WRITE
可升级的MDL锁,允许其他连接获取metadata信息,但不允许访问数据。
该锁会阻塞所有试图读/写表的数据,但允许information_schema及show操作
可以升级为x mdl锁
用于LOCK TABLES WRITE这样的语句。除了S和SH锁外,不与其他的锁相容。
8.MDL_EXCLUSIVE
持有该锁时,可以修改表的Metadata和数据,当持有该锁时,不能持有其他类型的任何mdl锁。用于CREATE/DROP/RENAME语句以及其他DDL语句的某些部分。
有三种类型的mdl锁持久化,在不同的时候释放:
enum enum_mdl_duration {
MDL_STATEMENT:在SQL完成或事务结束时释放
MDL_TRANSACTION:在事务完成时释放
MDL_EXPLICIT:显式的加锁,在事务或SQL完成后依旧持续,需要显式的调用  MDL_context::release_lock()来释放锁。
}
一个MDL锁的lock Key由以下几个部分组成:
<mdl_namespace>+<database name>+<table name>
mdl_namespace是枚举类型,用于区分对象的类型
206   enum enum_mdl_namespace { GLOBAL=0,
207                             SCHEMA,  
208                             TABLE,
209                             FUNCTION,
210                             PROCEDURE,
211                             TRIGGER,
212                             EVENT,
213                             COMMIT,
214                             /* This should be the last ! */
215                             NAMESPACE_END };
另外几个类:
############################################
MDL_wait_for_graph_visitor:An abstract class for inspection of a connected subgraph of the wait-for graph.
MDL_wait_for_subgraph:Abstract class representing an edge in the waiters graph to be traversed by deadlock detection algorithm.
class MDL_ticket : public MDL_wait_for_subgraph
MDL_ticket是MDL子系统的私有成员。
在同一个对象上的多个共享锁由一个ticket来表示,其他类型的锁不是这样。
有两组MDL_ticket成员
—可外部访问的(Externally accessible)
—线程私有(Context private)
MDL_savepoint:用于事务中存在savepoint时,作回滚用。
MDL_wait:定义了等待锁的方式
MDL_context:Context of the owner of metadata locks. I.e. each server connection has such a context.
主要函数都在文件mdl.cc中定义。
################################################
举一个简单的例子来阐述mdl锁吧,还是以rename为例
系统启动时,会在init_server_components里mdl_init
初始化mdl相关变量,例如m_locks hash结构体,用于存储所有的MDL锁。
创建一个简单的表t1
create table t1 (a int auto_increment primary key , b int );
session 1:
 > set autocommit = 0;
>  insert into t1 values (NULL,2);
在打开表的时候会申请mdl锁,调用栈
mysql_execute_command
             mysql_insert
                     open_and_lock_tables
                             open_tables
                                  open_and_process_table
                                        open_table
                                                MDL_context::acquire_lock(sql_base.cc:2920)
                                                open_table_get_mdl_lock(sql_base.cc:2929)
                                                        MDL_context::acquire_lock
在本例中table->mdl_request.type为MDL_SHARED_WRITE
session2: rename table t1 to t2;
mysql_rename_tables
      lock_table_names
session2需要请求表上的MDL_EXCLUSIVE锁,这是强度最大的锁,与其他所有的MDL锁类型都不兼容,由于之前的INSERT操作的session持有MDL_SHARED_WRITE锁,因此这里需要等待
lock_table_names          ——-搜集需要的锁
            ->MDL_context::acquire_locks
                     ->MDL_context::acquire_lock  —等待
session 1:
>commit;
mysql_execute_command
     ->MDL_context::release_transactional_locks  释放持有的MDL锁
MDL子系统的代码很复杂,以上也只是一个非常简单的例子,从如下的PDF中,你可以获得更详细的关于MDL如何设计的信息。
以下两个连接是MDL的worklog
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
SQL 存储 关系型数据库
菜鸟之路Day29一一MySQL之DDL
本文《菜鸟之路Day29——MySQL之DDL》由作者blue于2025年5月2日撰写,主要介绍了MySQL中的数据定义语言(DDL)。文章详细讲解了DDL在数据库和表操作中的应用,包括数据库的查询、创建、使用与删除,以及表的创建、修改与删除。同时,文章还深入探讨了字段约束(如主键、外键、非空等)、常见数据类型(数值、字符串、日期时间类型)及表结构的查询与调整方法。通过示例代码,读者可以更好地理解并实践MySQL中DDL的相关操作。
516 11
|
10月前
|
关系型数据库 MySQL Linux
MySQL包安装 -- SUSE系列(SUSE资源库安装MySQL)
本文介绍了在openSUSE系统上通过SUSE资源库安装MySQL 8.0和8.4版本的完整步骤,包括配置国内镜像源、安装MySQL服务、启动并验证运行状态,以及修改初始密码等操作,适用于希望在SUSE系列系统中快速部署MySQL的用户。
922 3
MySQL包安装 -- SUSE系列(SUSE资源库安装MySQL)
|
10月前
|
运维 Ubuntu 关系型数据库
MySQL包安装 -- Debian系列(Apt资源库安装MySQL)
本文介绍了在Debian系列系统(如Ubuntu、Debian 11/12)中通过APT仓库安装MySQL 8.0和8.4版本的完整步骤,涵盖添加官方源、配置国内镜像、安装服务及初始化设置,并验证运行状态,适用于各类Linux运维场景。
2810 0
MySQL包安装 -- Debian系列(Apt资源库安装MySQL)
|
10月前
|
存储 关系型数据库 MySQL
MySQL介绍和MySQL包安装 -- RHEL系列(Yum资源库安装MySQL)
MySQL是一款开源关系型数据库,高性能、易用、跨平台,支持多种存储引擎,广泛应用于Web开发、企业级应用等领域。本教程介绍其特点、架构及在主流Linux系统中的安装配置方法。
1503 0
MySQL介绍和MySQL包安装 -- RHEL系列(Yum资源库安装MySQL)
|
SQL 关系型数据库 MySQL
MySQL 5.6/5.7 DDL 失败残留文件清理指南
通过本文的指南,您可以更安全地处理 MySQL 5.6 和 5.7 版本中 DDL 失败后的残留文件,有效避免数据丢失和数据库不一致的问题。
|
关系型数据库 MySQL 数据库
RDS用多了,你还知道MySQL主从复制底层原理和实现方案吗?
随着数据量增长和业务扩展,单个数据库难以满足需求,需调整为集群模式以实现负载均衡和读写分离。MySQL主从复制是常见的高可用架构,通过binlog日志同步数据,确保主从数据一致性。本文详细介绍MySQL主从复制原理及配置步骤,包括一主二从集群的搭建过程,帮助读者实现稳定可靠的数据库高可用架构。
1017 9
RDS用多了,你还知道MySQL主从复制底层原理和实现方案吗?
|
SQL 存储 关系型数据库
MySQL主从复制 —— 作用、原理、数据一致性,异步复制、半同步复制、组复制
MySQL主从复制 作用、原理—主库线程、I/O线程、SQL线程;主从同步要求,主从延迟原因及解决方案;数据一致性,异步复制、半同步复制、组复制
2036 11
|
SQL 监控 关系型数据库
MySQL如何优雅的执行DDL
在MySQL中优雅地执行DDL操作需要综合考虑性能、锁定和数据一致性等因素。通过使用在线DDL工具、分批次执行、备份和监控等最佳实践,可以在保障系统稳定性的同时,顺利完成DDL操作。本文提供的实践和案例分析为安全高效地执行DDL操作提供了详细指导。
753 14
|
SQL DataWorks 关系型数据库
阿里云 DataWorks 正式支持 SelectDB & Apache Doris 数据源,实现 MySQL 整库实时同步
阿里云数据库 SelectDB 版是阿里云与飞轮科技联合基于 Apache Doris 内核打造的现代化数据仓库,支持大规模实时数据上的极速查询分析。通过实时、统一、弹性、开放的核心能力,能够为企业提供高性价比、简单易用、安全稳定、低成本的实时大数据分析支持。SelectDB 具备世界领先的实时分析能力,能够实现秒级的数据实时导入与同步,在宽表、复杂多表关联、高并发点查等不同场景下,提供超越一众国际知名的同类产品的优秀性能,多次登顶 ClickBench 全球数据库分析性能排行榜。
951 6
|
关系型数据库 MySQL
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
483 5

推荐镜像

更多