4

我正在Rails 3.2.3使用 mysql 数据库服务器的虚拟主机上运行使用 apache2/passenger 部署的应用程序。在大量流量访问该网站后,我收到此错误:

ActiveRecord::StatementInvalid (Mysql::Error: Can't create more than 
max_prepared_stmt_count statements (current value: 16382)

我认为这与流量有关,但如果是这样,我必须找到解决方法。以前有人遇到过这个错误吗?我不知道如何阻止它。

这是我在mysql中看到的:

mysql> 显示全局状态,如“com_stmt%”;

| Com_stmt_close | 1720319 | com_stmt_execute | 2094137 |

| Com_stmt_fetch | 0 |

| Com_stmt_prepare | 1768924 |

| Com_stmt_reprepare | 0 |

| Com_stmt_reset | 0 |

| Com_stmt_send_long_data | 0 |

+--------------+----------+

我正在运行 resque gem。

4

2 回答 2

2

很可能是针对数据库打开准备好的语句而不是关闭它们。

要检查这一点,请尝试查询:

show global status like ‘com_stmt%’;

Com_stmt_prepare 和 Com_stmt_close 之间的非常大的差异将表明某些东西使准备好的语句保持打开状态。Com_stmt_close = 0 当然会特别有说服力。


有可能,由于两者之间的差异相对较小,您实际上确实需要一次打开许多语句,尽管我仍然认为您更有可能在某处泄漏它们(错误/边缘情况处理,是典型的例子人们经常忘记关闭资源的地方)。

您可以通过以下方式增加允许的语句数:

set global max_prepared_stmt_count=<some_larger number>;

这应该让事情再次发生。小心过高的限制,因为这会使您容易受到 DoS 攻击。

之后,我会对其进行监控,看看是否有更多准备好的语句随着时间的推移而积累。

如果你:

set global general_log = 'ON';

一般日志将记录Prepare语句。寻找任何没有匹配的关闭,以帮助找到任何此类问题。

于 2012-12-12T21:38:53.377 回答
2

好的,我在这里暂时权衡一个答案。我使用 femtoRgon 的提示检查状态。然后我将这两行添加到我的 database.yml 文件中

  pool: 30
  prepared_statements: false

我重新启动了mysql。现在让应用程序运行一段时间后,我看到了这个:

mysql> show global status like 'com_stmt%';

| Com_stmt_close          | 189017 |

| Com_stmt_execute        | 189017 |

| Com_stmt_fetch          | 0      |

| Com_stmt_prepare        | 189017 |

| Com_stmt_reprepare      | 0      |

| Com_stmt_reset          | 0      |

| Com_stmt_send_long_data | 0      |

任何地方都没有差异......加上我曾经看到这个:

Ecard Load (0.1ms)  SELECT `ecards`.* FROM `ecards` WHERE `ecards`.`id` = ? LIMIT 1  [["id", "34"]] 

我现在看到这个:

Ecard Load (0.4ms)  SELECT `ecards`.* FROM `ecards` WHERE `ecards`.`id` = 34 LIMIT 1

我认为这表明我不再使用准备语句?希望有任何想法-我想我将不得不继续监视以了解情况如何...

于 2012-12-13T06:48:31.273 回答