如何检测 MySQL 中的死锁?什么可能导致我的应用程序在建立连接时挂起?

JSB*_*ach 5 mysql locking

我有一个应用程序存在一些数据库问题:当它尝试打开与数据库的连接(或执行查询,这不清楚)时,它突然冻结。没有错误信息。我怀疑有一些查询阻止了其他查询,我想弄清楚那是什么。我用了

SET profiling=1;
Run Code Online (Sandbox Code Playgroud)

但是当我执行时:

show profiles;
Run Code Online (Sandbox Code Playgroud)

我只得到我自己执行的查询,而不是应用程序查询(应用程序和我使用的是同一个用户)。

打电话

 SHOW FULL PROCESSLIST;
Run Code Online (Sandbox Code Playgroud)

返回包含所有进程的表。

+-----+----------+---------------------+--------+---------+------+-------+-----------------------+
| Id  | User     | Host                | db     | Command | Time | State | Info                  |
+-----+----------+---------------------+--------+---------+------+-------+-----------------------+
|   8 | user     | <HOST>              | DBs    | Sleep   |    3 |       | NULL                  |
| 722 | user     | <HOST>              | DBs    | Sleep   | 8205 |       | NULL                  |
| 726 | user     | <HOST>              | DBs    | Sleep   | 8212 |       | NULL                  |
| 727 | user     | <HOST>              | DBs    | Sleep   | 8205 |       | NULL                  |
| 728 | user     | <HOST>              | DBs    | Sleep   | 8205 |       | NULL                  |
| 730 | user     | <HOST>              | DBs    | Sleep   | 7172 |       | NULL                  |
| 732 | user     | <HOST>              | DBs    | Sleep   | 8095 |       | NULL                  |
| 733 | user     | <HOST>              | DBs    | Sleep   | 8055 |       | NULL                  |
| 735 | user     | <HOST>              | DBs    | Sleep   | 8075 |       | NULL                  |
| 736 | user     | <HOST>              | DBs    | Sleep   | 8075 |       | NULL                  |
| 737 | user     | <HOST>              | DBs    | Sleep   | 8035 |       | NULL                  |
| 738 | user     | <HOST>              | DBs    | Sleep   | 8015 |       | NULL                  |
| 740 | user     | <HOST>              | DBs    | Sleep   | 7995 |       | NULL                  |
| 741 | user     | <HOST>              | DBs    | Sleep   | 7975 |       | NULL                  |
| 742 | user     | <HOST>              | DBs    | Sleep   | 7955 |       | NULL                  |
| 774 | user     | <HOST>              | DBs    | Sleep   | 5772 |       | NULL                  |
| 779 | user     | <HOST>              | DBs    | Sleep   | 6068 |       | NULL                  |
| 806 | user     | <HOST>              | DBs    | Query   |    0 | init  | SHOW FULL PROCESSLIST |
+-----+----------+---------------------+--------+---------+------+-------+-----------------------+
Run Code Online (Sandbox Code Playgroud)

打电话

show engine innodb status
Run Code Online (Sandbox Code Playgroud)

返回大量交易,有些是活跃的,有些是未开始的。但没有关于锁定查询的信息。

这个查询,据说会给我关于被阻止查询的信息返回一个空集:

SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id,  b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM       information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b  ON   b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r  ON   r.trx_id = w.requesting_trx_id;
Run Code Online (Sandbox Code Playgroud)

有了所有这些信息,我可以保证没有死锁吗?

你能猜出会发生什么,以便我可以研究一下吗?

有什么方法可以获得有关流程的更多信息?

我是 DB 管理和 MySQL 的新手。

谢谢

Bil*_*win 4

锁等待延迟

锁定等待可能就是您的意思。您可以通过启用慢查询日志、收集一堆日志然后查看它来监视锁等待。这是一个例子:

# Time: 140605 15:00:06
# User@Host: appuser[appuser] @  [127.0.0.1]  Id:    29
# Schema:   Last_errno: 0  Killed: 0
# Query_time: 0.011732  Lock_time: 0.000161  Rows_sent: 214  Rows_examined: 214  Rows_affected: 0
SET timestamp=1402005606;
SELECT ...blah blah blah...
Run Code Online (Sandbox Code Playgroud)

您可以看到上面的字段Lock_time,它显示查询在开始执行之前等待锁定 161 微秒。然后执行时间不到 12 毫秒(如图所示Query_time)。

非常小是很正常的Lock_time,通常甚至超出范围,所以它只显示为 0.000000。如果它达到数百毫秒或更长,那就不寻常了。如果是整秒,那你就有麻烦了。

Query_time请注意,除非超出您的配置变量,否则慢查询日志条目不会写入日志long_query_time- 即使该变量Lock_time很大。有关此问题的更多讨论,请参阅http://www.mysqlperformanceblog.com/2012/11/22/get-me-some-query-logs/

转机延误

您还提到,这可能是在运行任何查询之前获取连接导致的延迟。您需要查明是否属于这种情况。在任何应用程序语言中都应该很容易读取连接数据库之前和之后的时间,并比较它们以了解需要多长时间。有些框架甚至为每个查询提供这种类型的应用程序级分析(或者您可以自己执行)。

例如,连接延迟的一个常见原因是 MySQL 服务器正在执行反向 DNS 查找,以将传入套接字的 IP 地址转换为主机名。它这样做是为了可以在授权表中查找主机名,以确定 user@host 拥有哪些权限。但如果您的 DNS 服务器速度缓慢或过载,则速度可能会很慢。令人惊讶的是,它会超过几分之一秒,但这是可能的。

您可以通过设置配置变量来加快速度skip_name_resolve。这意味着您无法根据主机名向用户授予权限,您必须仅通过 IP 地址来识别用户。现实世界中的大多数生产 MySQL 实例都是这样设置的skip_name_resolve

连接缓慢也可能有其他原因,但首先进行一些应用程序分析,以最终确定是连接缓慢还是查询缓慢。


PS:很多人说“死锁”时,他们的意思是“锁等待”。死锁是指两个事务因等待对方的锁而无法继续进行。死锁不会导致延迟,因为 InnoDB 会立即注意到循环依赖并终止其中一个事务。您可以在标题为“最新死锁”的部分中的“SHOW ENGINE INNODB STATUS”中查看是否出现死锁。