4

我想我有一些应用程序问题正在减慢我们整个应用程序的速度,并且可能会导致损坏和其他问题。
应用程序问题是由许多处于休眠状态的 mysql 连接引起的。

SHOW PROCESSLIST;输出 :

| 356058234 | Y  | X:39119 | D | Sleep   |  1442 |       | NULL             |
| 356058441 | Y  | X:39126 | D | Sleep   |  1442 |       | NULL             |
| 356059383 | Y  | X:46615 | D | Sleep   |  2049 |       | NULL             |
| 356059389 | Y  | X:46617 | D | Sleep   |  2052 |       | NULL             |
| 356065991 | Y  | X:39267 | D | Sleep   |  1442 |       | NULL             |
-------------  
452 rows in set (0.00 sec)

mysqlreport

__ Connections _________________________________________________________
Max used         8001 of 8000      %Max: 100.01
Total         356.07M    58.6/s

这表明我真的没有连接了。即使限制为 8000。这里必须有一些东西。但是调试这样的事情可能很麻烦。

无论如何,我用 netstat 查看了进程 ID,例如netstat -ntp | grep :39267输出如下:

tcp        0      0 IP_1:3306      IP_2:38727    VERBUNDEN   791/mysqld

因此,我更进一步,查找791打印出的长字符串(几百行),看起来像这里的那些:

tcp        0      0 IP_1:3306      IP_2:34109    VERBUNDEN   791/mysqld      
tcp        0      0 IP_1:3306      IP_3:32864    VERBUNDEN   791/mysqld      
tcp        0      0 IP_1:3306      IP_3:37231    VERBUNDEN   791/mysqld      
tcp        0      0 IP_1:3306      IP_2:38727    VERBUNDEN   791/mysqld      
tcp        0      0 IP_1:3306      IP_2:36645    VERBUNDEN   791/mysqld

但这告诉我什么?我应该收集哪些更多信息才能找到实际上导致太多连接问题的线索?

关于应用程序的更多信息:
我们在几台服务器上运行代码——在我们的数据库上更新、插入和删除相当大的内容,这些服务器通过分叉框架Gearman获取这些数据。我们正在运行一个MySQL INNODB 数据库,它被我们的PHP 5.4Zend Framework驱动的应用程序使用。操作系统是Linux(Debian)

4

2 回答 2

6

大多数(所有?)线程都处于睡眠状态的事实让我认为您的应用程序与数据库有一个开放的连接,但在数据库请求之间。

您可以通过使用带有Percona 监控插件的Cacti来监控Threads_runningThreads_connected的趋势来确认这一点。前者通常比后者低很多,但如果它平均水平较低,那么您基本上有空闲的数据库连接不必要地占用资源。

你可以做的几件事:

  • 连接数据库较晚。Zend Framework 的数据库适配器(我上次检查的)默认情况下直到第一个查询才真正连接。您可以覆盖它并强制它提前连接,但您应该尽量避免这种情况。

  • 尽早断开与数据库的连接。 在 PHP 中习惯于让资源闲置,因为它们会在请求结束时自动清理。但这意味着您的应用程序在不需要它时会保留与数据库服务器的连接一段时间,而其他应用程序请求可能正在等待它。您应该对您的应用程序进行编码,以便在它们获取所需的最后数据后立即断开与数据库的连接。

  • 尽量减少连接时间。 如果可以连接到数据库,快速获取给定页面请求所需的所有数据,然后及时断开连接,就可以释放服务器上的连接资源。这可能意味着重构您的 PHP 代码。无论您需要做什么来分析数据或将其格式化以供输出,都可以在关闭数据库连接后完成。

  • 不要不必要地连接。如果您的应用程序可以从memcachedAPC或类似缓存中获取所需的数据,那么您的某些页面请求可能根本不需要访问数据库。

  • 优化查询。另一种可能性是某些查询是长时间运行的,并且将打开的线程保持在睡眠以外的状态。换句话说,实际执行一个查询。但是,如果查询的速度始终快于它们可以完成的平均速度,那么您往往会获得长长的连接队列。使您的查询运行得更快。

    这样做的方法太多了,这里就不一一列举了,但你可以从这里开始学习:

于 2013-10-04T22:04:24.037 回答
3

经过长时间的调试和测试,我终于找到了导致那些昏昏欲睡的连接的错误,最终会导致too many connections错误。

我发现,我做了一个Zend_Db_Table_Select像这样的操作:

// $this->tablename is instance of Zend_Db_Table_Abstract
$select = $this->tablename->select();
$select->where('id = ?', $id);

return $this->tablename->fetchAll($select)->toArray();

Zend 让连接打开直到脚本结束。
但是因为我使用的是 Gearman,这意味着我的 PHP 工作脚本被用来永远运行,脚本永远不会终止,因此这些连接将保持打开状态,就像休眠连接一样。
所以最后你有一千个打开但昏昏欲睡的连接。

那么我们如何关闭这样的东西呢?我给自己做了一个__destruct()方法,它只包含:

// both $this->useraddons and $this->db get set up in my __construct()
$this->useraddons->getDefaultAdapter()->closeConnection();
$this->db->closeConnection();

每次我想关闭连接时,我只需要做一个unset($myTableClass).

于 2013-10-06T10:17:11.750 回答