我想我有一些应用程序问题,这会减慢我们的整个应用程序,并会造成可能的损害和其他问题。
许多正在hibernate的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的限制。这里有一些东西。 但是debugging这些东西可能会很麻烦。
无论如何,我看这个进程ID与netstat,例如像这样netstat -ntp | grep :39267
netstat -ntp | grep :39267
输出:
tcp 0 0 IP_1:3306 IP_2:38727 VERBUNDEN 791/mysqld
所以我再往前走一步,看看这里有一条长长的一串(几百行),看起来就像这些:
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
但是,这告诉我什么? 我应该收集哪些更多的信息来获得实际上导致连接太多问题的线索?
有关应用程序的更多信息:
我们在几台服务器上运行代码(在我们的数据库中进行更新,插入和删除),这些服务器通过派生Framework Gearman来获取这些数据。 我们正在运行一个MySQL INNODB数据库 ,它被我们的PHP 5.4和Zend Framework驱动的应用程序所使用。 操作系统是Linux(Debian) 。
大多数(所有?)线程处于睡眠状态的事实使我认为你的应用程序有一个到数据库的开放连接,但是在数据库请求之间。
您可以通过使用带有Percona监控插件的 Cacti来确认这一点,以监控Threads_running与Threads_connected的趋势。 前者通常比后者低很多,但是如果平均值降低的话,那么基本上就会有空闲的数据库连接不必要地占用资源。
你可以做几件事情:
晚点连接数据库。 Zend框架的数据库适配器(最后我检查)实际上并没有连接,直到第一个查询,默认情况下。 你可以覆盖这个,并强制它连接早,但你应该尽量避免这一点。
尽早断开数据库。 在PHP中习惯使用资源闲置,因为当请求结束时会自动清除资源。 但是这意味着你的应用程序在数据库服务器不需要的时候保留了一段时间的连接,当其他应用程序请求可能正在等待的时候。 一旦获取了所需的最后一个数据,就应该编写应用程序以及时从数据库断开连接。
尽量减少连接时间。 如果可以连接到数据库,快速获取给定页面请求所需的所有数据,然后立即断开连接,释放服务器上的连接资源。 这可能意味着重构你的PHP代码。 无论您需要如何分析数据或格式化输出,都可以在关闭数据库连接后完成。
不要不必要地连接。 如果您的应用程序可以从memcached或APC或类似的缓存中获取所需的数据,那么您的一些页面请求可能根本不需要触摸数据库。
优化查询。 另一种可能性是有些查询是长时间运行的,并且在Sleep以外的状态下保持打开的线程。 换句话说,实际执行一个查询。 但是,如果查询速度一直比他们能够完成的平均速度快,那么你往往会遇到长长的连接堆积。 让您的查询运行得更快。
这样做的方法太多,不能在这里重述,但是你可以在这里开始学习:
经过一段时间的调试和测试,我终于找到了造成这些困倦连接的错误,最终导致too many connections
错误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 worker脚本被永久运行,所以脚本永远不会终止,所以这些连接将保持打开状态。
所以最后你有一千个开放但困倦的连接。
那么我们如何关闭这样的东西呢? 我自己做了一个__destruct()
方法,它只是包含:
// both $this->useraddons and $this->db get set up in my __construct() $this->useraddons->getDefaultAdapter()->closeConnection(); $this->db->closeConnection();
每次我想关闭连接,我只需要做一个unset($myTableClass)
。