2016年12月10日土曜日

オートバキュームがされない原因は? (Postgres)

 Postgresは、MVCC(多版式同時実行制御)の追記型なので、新規行作成(INSERT)だけでなく、
更新(UPDATE)の場合も内部では行データ(タプルという)が新たに増えていきます。
そのため、UPDATEを繰り返すだけでも、データがどんどん増えていき、
パフォーマンスが極端に落ちてしまうことがあります。

これを解決するために、Postgresでは、不要な行データを削除すること(バキュームという)が
必要となってきます。

昔は、バキュームコマンドを定期的に実行する必要がありましたが、
最近のPostgresでは、オートバキューム機能があるため、特に気にすることもなく、
勝手にバキュームしてくれます。

と、思っていましたが・・・
どういうわけか、担当プロジェクトの大量データ処理で激しい処理落ちが・・・

そして、原因調査へ


■まずは、バキューム関係のパラメータを設定
バキュームログを出力して、状況の詳細を確認する。

Postgres.confで、バキュームログを出力するように設定
autovacuum = on
log_autovacuum_min_duration = 0

※postgresの再起動が必要
※postgres.confは、デフォルトなら「C:\Program Files\PostgreSQL\9.x\data」にあるはず。

■ログの確認
そして、再実行して、処理落ちがはじまったところでログを見てみると



やはり、タプルが残っていて、バキュームされていないように見える。
※このテーブル「ad_sequence」の実際の行は1479行であり、それに対してタプルが多すぎる。
※Postgresのログは、デフォルトなら「C:\Program Files\PostgreSQL\9.x\data\pg_log」に
日時付ファイル名で出力されている。


■さらに、PGAdminで、タプル状態の確認



これを見ても、やはり、タプルが残っているようだ。


■いろいろググッてみると、
Let's Postgresの以下のサイトを見つけた。
HOT(Heap Only Tuples) ~ Let's Postgres

HOT(Heap Only Tuple)といわれる機能があって、バキューム処理をしてくれるらしいのだが・・・

だけど、処理が激落ちしているので、それすら走っていない気がする。

そして、さらに上記サイトを読み進めていくと
ロングトランザクションに気をつけようということにひっかかる。


■ロングトランザクションとコネクションプールに注意!!!
  改めて、ソースを確認していくとなんとコミット漏れがあり
それをコミットすることで状況は無事解決した。
(めでたし、めでたし、苦労のわりには、原因はイージーミスという情けない幕切れ。)

実行中のトランザクションで、更新されたテーブルは
そのトランザクションが終了するまでバキュームされないようだ。

ここでもうひとつ注意が必要なのは、コネクションプールについてである。
コネクションプールを使っていると、トランザクションがコミットされていても
バキュームされないことがあるようだ。

詳細不明だが、コネクションプールの機能は、プログラムからコネクションをクローズしても
物理的なコネクションはクローズされず、ある程度の期間(KeepAlive)、
コネクションを保持したり、使いまわしをするもののため、
そのKeepAliveの間は解放されないのではないかと推測しています。

なので、大量データ処理では、コネクションプールを使わず、コネクションの時間的コストはかかるが、適度なタイミングで、コネクションを解放して、再接続をしたほうがいいという結論に至りました。


0 件のコメント:

コメントを投稿