4

Rails 3.2.3mysql データベース サーバーを使用する仮想ホストで、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 は、特に意味があります。


2 つの間の差異が比較的小さいため、実際には一度に多くのオープン ステートメントが必要になる可能性がありますが、どこかにリークしている可能性が高いと考えています (エラー/エッジ ケースの処理が典型的な例です)。人々がしばしばリソースをクローズするのを忘れる場所)。

以下を使用して、許可されるステートメントの数を増やすことができます。

set global max_prepared_stmt_count=<some_larger number>;

これで、物事が再び動き出すはずです。制限が高すぎると、DoS に対して脆弱になる可能性があるため、注意してください。

その後、私はそれを監視し、より多くの準備済みステートメントが時間の経過とともに蓄積されるかどうかを確認します。

もし、あんたが:

set global general_log = 'ON';

一般ログにはPrepareステートメントが記録されます。このような問題を見つけるのに役立つように、一致する Close のないものを探します。

于 2012-12-12T21:38:53.377 に答える
2

わかりました、私は暫定的にここで答えを検討しています。femtoRgonさんのtipsを使ってステータスを確認してみました。次に、これらの2行を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 に答える