PHPセッションのGCを非同期にする

PHP

概要

  • PHPのセッションハンドラをデフォルトで使っている場合のガーベージコレクタ(GC)の話。
  • PHPはサーバ上で保存してあるセッション情報を保存してあるファイルをを定期的に削除している。
  • 削除するタイミングはPHPが起動する時、HTTPリクエストまたはコマンドラインからPHPが起動した際に一定の確率でGCが起動するようになっている。Javaのアプリケーションサーバならメモリ上にJVMが常駐しているからプログラムの起動とは非同期にできるが、PHPは同期で処理している。そのため、PHPではGCが起動したときにプログラムの実行時間が長ってしまう。
  • よって、大規模サイトになったときには必然的にセッションファイルが扱うセッションが多くなるため、GCにかかる時間が長くってしまうから、同期によるPHPのGCに任せないで自前で非同期にGCを行うべき。

設定項目

PHPのGCを制御する設定はphp.iniに記載されている以下の3つ。

session.gc_probability = 1
session.gc_divisor     = 1024
session.gc_maxlifetime = 1440

GCの起動確立は、gc_divisor 分のgc_probability。上記の例では1/1024の確立でGCが起動する。
セッションファイルの最終変更時間がgc_maxlifetime秒以前だったらセッションを削除する。
(PHP4.2.3以降はファイルの最終更新日、それより前は最終アクセス時間)

gc_probabilityを0にすればPHPのGCは無効になる。
以下のようにすれば、PHPからGCが起動されることは無くなる。

session.gc_probability = 0
session.gc_divisor     = 1024
session.gc_maxlifetime = 1440

非同期でGCする設定

以下は、GCをcronで一定時間に削除する例。

*/10 * * * * daemon ionice -c3 nice -n19 -n 18 find /tmp -type f -name "sess_*" -mmin +120 -exec rm {} ;

上記の例では、10分に1回GCを起動し、最終変更時間から2時間経ったら削除する例。
プロセスの優先度は低め、IOの優先度も最低にしてある。

コメント

  1. より:

    session.gc_divisorの値を大きくするだけでよいのでは?

  2. matsu より:

    コメントありがとうございます!また、URL参考になりました。

    session.gc_divisor(分母)を大きくすると、GCが起動する確率が下がります。そのため、1回のGCで処理する対象のファイルが多くなり、IOの負荷が高くなり、GC完了まで時間がかかります。

    GCはユーザのHTTPアクセスによって発動するので、そのGCが発動した時のHTTPレスポンスが遅くなってしまいます。

    このレスポンス低下を防ぐためにはGCを同期ではなくて、ユーザアクセスとは非同期でに行います。