MySQL 5.7 独占表锁和共享读锁导致死锁/冻结

问题描述 投票:0回答:1

我正在修改表格以添加评论,列的类型和其他参数没有改变:

ALTER TABLE `table1` CHANGE `id` `id` INT(11) NOT NULL AUTO_INCREMENT
COMMENT 'test1';

当我尝试在流量适中的生产服务器上运行此更改时,我看到了看起来像是死锁的情况。要求 SHARED_READ 锁的请求无法继续(它们是 PENDING)并且 EXCLUSIVE 锁也是 PENDING,因此系统冻结并且无法处理对表的查询。

查看文档,MySQL 应该能够访问 DDR,同时允许在 innodb 表上进行 DML 事务。有什么我想念的吗?

使用以下查询我可以看到锁:

SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID, PROCESSLIST_ID, PROCESSLIST_HOST, PROCESSLIST_STATE, PROCESSLIST_INFO, PROCESSLIST_TIME

FROM performance_schema.metadata_locks 
LEFT JOIN performance_schema.threads ON threads.THREAD_ID = metadata_locks.OWNER_THREAD_ID

order by owner_thread_id DESC;

这就是 MySQL 的工作方式,您不能在具有中等流量的系统上从功能上更改表吗?

OBJECT_TYP OBJECT_SCHEMA     OBJECT_NAME   LOCK_TYPE           LOCK_DURATION LOCK_STATUS OWNER_THREAD_ID  PROCESSLIST_ID PROCESSLIST_HOST PROCESSLIST_STATE          PROCESSLIST_INFO                PROCESSLIST_TIME
TABLE      main_db           table2        SHARED_READ         TRANSACTION   GRANTED     80801101         80801075       IP2              Waiting for table metadata SELECT FROM table1              16
TABLE      main_db           table1        SHARED_READ         TRANSACTION   PENDING     80801101         80801075       IP2              Waiting for table metadata SELECT FROM table1              16
TABLE      main_db           table1        SHARED_READ         TRANSACTION   PENDING     80799419         80799393       IP1              Waiting for table metadata SELECT FROM table1 and table2   11
GLOBAL     NULL              NULL          INTENTION_EXCLUSIVE STATEMENT     GRANTED     80777210         80777184       IP1              Waiting for table metadata ALTER TABLE table1 add comment  17
SCHEMA     main_db           NULL          INTENTION_EXCLUSIVE TRANSACTION   GRANTED     80777210         80777184       IP1              Waiting for table metadata ALTER TABLE table1 add comment  17
TABLE      main_db           table1        SHARED_UPGRADABLE   TRANSACTION   GRANTED     80777210         80777184       IP1              Waiting for table metadata ALTER TABLE table1 add comment  17
TABLE      main_db           table1        EXCLUSIVE           TRANSACTION   PENDING     80777210         80777184       IP1              Waiting for table metadata ALTER TABLE table1 add comment  17

如果我离开它 30 秒,它仍然不会获取锁来更改表,并且会阻止选择。

mysql transactions locking mysql-5.7
1个回答
0
投票

你所看到的并不恰当地称为死锁。死锁是指两个或多个事务处于相互依赖的锁等待循环中,因此无法打破等待。在这种情况下,除了终止其中一项交易之外别无他法。我认为我从未在 MySQL 中见过涉及元数据锁的死锁,只有行锁。

你所看到的是 MySQL 元数据锁是如何工作的。这些不同于 InnoDB 存储引擎中的行锁。

任何 DDL 语句,即使是仅更改注释的语句,因此它只是元数据更改,都需要独占元数据锁。

但是任何正在读取或写入该表的会话都持有共享元数据锁,直到其事务结束。共享元数据锁阻止独占元数据锁请求。独占意味着没有其他会话可以持有任何元数据锁,共享或其他方式,因此元数据锁请求等待所有会话完成其事务并释放其共享元数据锁。

一旦 DDL 语句开始等待其独占元数据锁,所有其他想要运行简单查询的会话都需要它们的共享元数据锁,并且未完成的 DDL 锁请求会阻止它们。所以他们也在等待。这样,单个 DDL 语句等待可以阻止在 DDL 语句开始等待后开始请求的每个人。

DDL语句为什么要等待?因为在 DDL 语句开始时持有共享元数据锁的一个或多个会话不会放弃它们的元数据锁。他们可能正在运行一个非常长寿命的查询,但也有可能他们的查询已经完成,他们只是不会通过 COMMIT 或 ROLLBACK 来释放他们的锁。这取决于应用程序代码设计。

您应该编写您的应用程序以使交易尽可能短:

  • 优化单个查询,使它们不会运行太久。

  • 不要将太多不相关的查询组合到一个事务中。事务应该表示需要在同一事务中的有限组查询。我见过一些开发人员无缘无故地将无限数量的查询组合成一个长期存在的事务。

  • 在事务中一起执行所有查询,它们之间没有不必要的非数据库代码,然后尽快提交或回滚。我已经看到事务在某些应用程序中意外地变得长期存在,因为在查询之间,应用程序对 Web 服务或其他花费很长时间的请求进行了 http 请求。同时,数据库事务在未提交状态下持续时间过长。

元数据锁请求是否像行锁请求一样超时?是的,有一个超时,但是元数据锁定请求的默认超时持续时间是1年(这是

lock_wait_timeout
配置变量的值)。

你能减少元数据锁请求超时吗?是的你可以。在我从事一项工作的模式更改管理应用程序中,我们将

lock_wait_timeout
设置为 2 秒,因此如果应用程序很忙,至少 DDL 语句不会导致严重的阻塞(嗯,不超过 2 秒)每个请求的秒数;如果其他会话需要运行以毫秒为单位完成的查询,这可能有点糟糕。

然后我们的服务会在超时时重试 DDL 语句。它会在短暂的睡眠间隔后重试多达 200 次。如果它仍然失败(它可能会失败,例如,如果它永远不会在其他会话运行的长时间运行的事务之间滑动),那么模式更改将失败并返回错误。这意味着必须在其他时间尝试更改,希望在交通较少时。

© www.soinside.com 2019 - 2024. All rights reserved.