MySQL Flush导致的等待问题

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 前言在实际生产环境中有时会发现大量的sql语句处于waiting for table.. 状态中,有时候看起来会让人觉得困惑,本文将讲解此状态产生的原因及解决办法。

前言

在实际生产环境中有时会发现大量的sql语句处于waiting for table.. 状态中,有时候看起来会让人觉得困惑,本文将讲解此状态产生的原因及解决办法。

正文

本文中用到了lock table来模拟实际情况, 首先介绍一个lock tables需要注意的事项,如果在一个session中使用了lock tables,那么在此session中将只能访问获取到lock的表。官方解释:

If the LOCK TABLES statement must wait due to locks held by other sessions on any of the tables, it blocks until all locks can be acquired. A session that requires locks must acquire all the locks that it needs in a single LOCK TABLES statement. While the locks thus obtained are held, the session can access only the locked tables. For example, in the following sequence of statements, an error occurs for the attempt to access t2 because it was not locked in the LOCK TABLES statement: mysql> LOCK TABLES t1 READ; mysql> SELECT COUNT(*) FROM t1; +----------+ | COUNT(*) | +----------+ |        3 | +----------+ mysql> SELECT COUNT(*) FROM t2; ERROR 1100 (HY000): Table ‘t2‘ was not locked with LOCK TABLES Tables in the INFORMATION_SCHEMA database are an exception. They can be accessed without being locked explicitly even while a session holds table locks obtained with LOCK TABLES.

 基于这样的原因,往往在备份时选择flush table with read lock;是个不错的选择,如果成功,它会锁住所有表。

 回顾一下官方文档关于flush table的解释

Closes all open tables, forces all tables in use to be closed, and flushes the query cache. FLUSH TABLES also removes all query results from the query cache, like the RESET QUERY CACHE statement.

 模拟Flush操作导致的waiting tables等待问题。

 

a) 在终端1中执行lock table锁住jackjhu库中的一张表

mysql> lock table t1 read; Query OK, 0 rows affected (0.00 sec)

 b) 在终端2中执行flush tables

mysql> flush tables;

       --无返回,被阻塞..

c) 此时终端3欲连接到jackjhu库,如果mysql连接时没有使用-A,将出现阻塞。

mysql> use jackjhu

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A   --无返回,被阻塞,后面会解释原因…

重新使用-A选项连接终端3执行select jackjhu库中表t1,阻塞。

mysql> select * from t1;

 --无返回,被阻塞..

d) 新建终端4,使用-A选项连接mysql,到jackjhu库中查询其他表,正常。

mysql> select * from t2;

+----+---------+ | id | name    | +----+---------+ |  5 | mysql   | |  6 | test    | +----+---------+ 2 rows in set (0.01 sec)

 退出终端,重新使用不带-A选项连接mysql,选中jackjhu。

mysql> use jackjhu

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A   --无返回,被阻塞..

查看现在的线程情况,并分析阻塞的原因。

mysql> show full processlist;

+----+------+-----------+---------+------------+------+-------------------------+-----------------------+ | Id | User | Host      | db      | Command    | Time | State                   | Info                  | +----+------+-----------+---------+------------+------+-------------------------+-----------------------+ |  2 | root | localhost | jackjhu | Query      |    0 | init                    | show full processlist | |  3 | root | localhost | jackjhu | Query      |   33 | Waiting for table flush | flush tables          | |  7 | root | localhost | jackjhu | Query      |   20 | Waiting for table flush | select * from t1      | | 12 | root | localhost | jackjhu | Field List |   10 | Waiting for table flush |                       | +----+------+-----------+---------+------------+------+-------------------------+-----------------------+ 4 rows in set (0.00 sec) 

首先查看waiting for table ..的官方解释:

The thread got a notification that the underlying structure for a table has changed and it needs to reopen the table to get the new structure. However, to reopen the table, it must wait until all other threads have closed the table in question. This notification takes place if another thread has used FLUSH TABLES or one of the following statements on the table in question: FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE, orOPTIMIZE TABLE.

分析

ID 3:终端2,由于t1被终端1锁住(lock table t1 read),flush操作中需要刷新表t1缓冲并关闭表,被阻塞,表被锁无法关闭。

ID 7:终端3,查询t1表的内容,由于查询前有flush操作,flush操作会发出表需要被重新打开的信号。终端3的查询需要重新打开t1表,显然也被阻塞,由我们上面的实验知道,打开其他没有被锁定的表是可以的,他们已经完成flush并可以被打开。

ID 12:不使用-A连接mysql,被阻塞。线程状态:Field List。解释:

The thread is retrieving information for table columns. 

 由于表t1需要被reopen阻塞,所以这里也被阻塞。

从show full processlist这个表象上看,好像是flush tables引起的问题,其实问题的根源在于这个操作被阻塞,也就是表t1被锁住,或无法释放被关闭。

 同样ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE,  OPTIMIZE TABLE等操作也会出现这样的问题,这面是实验结果。

条件1:lock table t1 read      

repair table, alter table(create index…),rename table,optimize table

以上操作和之后的select出现 Waiting for table metadata lock

analyze table t1操作正常,但是后面的select出现 Waiting for table metadata lock

--无field List锁

条件2:lock table t1 write

仅仅说一下和条件1中情况不同的,其他一样。

analyze table

以上操作和之后的select出现 Waiting for table metadata lock

--无field List锁

注意这里使用了lock table .. read简单的进行了模拟,实际上生产环境中大多数是由于长查询,导致flush table一直等待无法关闭该表导致。

 

MySQL Flush操作的bug

 

现象:如上文模拟的情况,如果在生产环境中发现waiting for table flush,阻塞了大量的sql。这时候为了解决问题,kill掉flush tables这个操作,这并不能解决问题, 需要reopen的标记依然会存在而没有被清除,后面的select依然没能被继续。

MySQL Bug:       http://bugs.mysql.com/bug.php?id=44884

 

出现waiting for table.. 的解决办法

 

找到阻塞FLUSH TABLES, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE, OPTIMIZE TABLE等操作的源头,或许是lock table操作和有表锁,或许是一个长长的查询(可以从proceelist的time列找到),总之,我们可以很容易定位到哪张表引起的问题,再去定位sql语句,从这个方向去思考,可以比较容易的解决这样的问题。

 

最后看看flush tables with read lock的行为,先看看官方解释:

Closes all open tables and locks all tables for all databases with a global read lock.

关闭打开的表。

mysql> flush table with read lock;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show global status like ‘%open%‘; +--------------------------+-------+ | Variable_name            | Value | +--------------------------+-------+ | Com_ha_open              | 0     | | Com_show_open_tables     | 0     | | Open_files               | 7     | | Open_streams             | 0     | | Open_table_definitions   | 0     | --表结构文件被关闭 | Open_tables              | 0     | --表被关闭 | Opened_files             | 561   | | Opened_table_definitions | 101   | | Opened_tables            | 101   | | Slave_open_temp_tables   | 0     | +--------------------------+-------+ 10 rows in set (0.00 sec)

mysql全局的读锁。

mysql> flush table with read lock;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show global status like ‘%open%‘; +--------------------------+-------+ | Variable_name            | Value | +--------------------------+-------+ | Com_ha_open              | 0     | | Com_show_open_tables     | 0     | | Open_files               | 7     | | Open_streams             | 0     | | Open_table_definitions   | 0     | | Open_tables              | 0     | | Opened_files             | 561   | | Opened_table_definitions | 101   | | Opened_tables            | 101   | | Slave_open_temp_tables   | 0     | +--------------------------+-------+ 10 rows in set (0.00 sec)

对于写入操作近些阻塞,写入操作被锁等待

mysql> insert into t3 values(3,‘uncommit‘); --无返回,等待,processlist中状态如下: |Query   |    37 | Waiting for global read lock                                                | insert into t3 values(3,‘uncommit‘) |

如果事务在flush with read lock前已经有数据写入,但是还没有提交,此时提交的话也会被阻塞。

Query   |     3 | Waiting for commit lock                                                       | commit

 

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
存储 缓存 关系型数据库
MySQL进阶突击系列(08)年少不知BufferPool核心原理 | 大哥送来三条大金链子LRU、Flush、Free
本文深入探讨了MySQL中InnoDB存储引擎的buffer pool机制,包括其内存管理、数据页加载与淘汰策略。Buffer pool作为高并发读写的缓存池,默认大小为128MB,通过free链表、flush链表和LRU链表管理数据页的存取与淘汰。其中,改进型LRU链表采用冷热分离设计,确保预读机制不会影响缓存公平性。文章还介绍了缓存数据页的刷盘机制及参数配置,帮助读者理解buffer pool的运行原理,优化MySQL性能。
|
SQL 关系型数据库 MySQL
MySQL - 锁等待及死锁初探
MySQL - 锁等待及死锁初探
574 0
|
SQL 关系型数据库 MySQL
MySQL中锁等待超时与information_schema的三个表
MySQL中锁等待超时与information_schema的三个表
627 0
|
监控 算法 关系型数据库
MySQL学习笔记- 刷脏页(flush)对性能的影响
MySQL学习笔记- 刷脏页(flush)对性能的影响
1125 0
|
SQL 弹性计算 监控
PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids, pg_safe_snapshot_blocking_pids
标签 PostgreSQL , 锁等待 , 队列 背景 当一个进程处于等待(被堵塞)状态时,是谁干的?可以使用如下函数,快速得到捣蛋(堵塞别人)的PID。 1、请求锁时被堵,是哪些PID堵的? pg_blocking_pids(int) int[] Process ID(s) that are blocking specified server process ID from acq
2134 0
PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids, pg_safe_snapshot_blocking_pids
|
运维 关系型数据库 MySQL
MySQL锁等待与死锁问题分析
在 MySQL 运维过程中,锁等待和死锁问题是令各位 DBA 及开发同学非常头痛的事。出现此类问题会造成业务回滚、卡顿等故障,特别是业务繁忙的系统,出现死锁问题后影响会更严重。本篇文章我们一起来学习下什么是锁等待及死锁,出现此类问题又应该如何分析处理呢?
831 0
|
SQL 弹性计算 监控
PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids
标签 PostgreSQL , 锁等待 , 队列 背景 1 "被害人" 1、找到"被害人",获取被锁堵塞的PID select distinct pid from pg_locks where not granted; 2、找到"嫌疑人",获取被锁堵塞的PID是被哪些PID堵塞的 postgres=# select * from pg_blocking_pids(5392
2046 0
|
关系型数据库 MySQL 调度
MySQL · RocksDB · Memtable flush分析
概述 首先我们知道在RocksDB中,最终数据的持久化都是保存在SST中,而SST则是由Memtable刷新到磁盘生成的,因此这次我们就主要来分析在RocksDB中何时以及如何来Flush内存数据(memtable)到SST.
4064 0
|
SQL 存储 关系型数据库
Mysql事物锁等待超时 Lock wait timeout exceeded; try restarting transaction
Mysql事物锁等待超时 Lock wait timeout exceeded; try restarting transaction
1178 0
|
SQL 监控 安全
PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids, pg_safe_snapshot_blocking_pids
PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids, pg_safe_snapshot_blocking_pids
2399 0

推荐镜像

更多