田舎プログラマーの備忘録

田舎出身のWEBプログラマーが書く備忘録です。

sessionのガベージコレクションについて[PHP]

これは、sessionが2年間消さない設定にされていたのを、1週間にしたとき気になって調べたことのまとめです。

ざっくり起きた内容まとめ

  • RDSの容量が無料枠の20Gを食いつぶそうとしていた
  • 原因は過去にsessionデータをdatabaseに保存しているのを知りながら、有効期限を2年にしたから
  • 8Gほどに上るデータを削除しなければいけない

まずはCodeIgniterの設定を見てみる

$config['sess_expiration'] = 60*60*24*30*12*2;

( ^ω^ )どうしてこうなったし・・

およそ2年データを保持するという設定が書かれていました。

(なら、DBにわざわざ持たせるなという話ですが・・・)

CodeIgniterのコードを読んでみると、sess_expirationでは後述のmax_lifetimeしか設定できなさそうなので、これを1週間とかにするのはなんだか嫌な予感がすると思い、PHPの挙動を調べてみることにしました。

※実際、30日にしてみると一気にsessionが消えたので、一斉削除する処理が走っていると予想されます。

PHPのリファレンスを見てみる

1.必要な設定情報

注目するべきは以下の項目です。

config名 デフォルト値 ドキュメントから抜粋
session.gc_probability 1 session.gc_probabilityと session.gc_divisorの組み合わせでgcガーベッジコレクション)ルーチンの始動を制御します。
session.gc_divisor 100 session.gc_divisorと session.gc_probabilityの組み合わせで すべてのセッションの初期化過程でgc(ガーベッジコネクション)プロセス も始動する確率を制御します。
session.gc_maxlifetime 1440 (秒) session.gc_maxlifetime は、データが 'ごみ' とみなされ、消去されるまでの秒数を指定します。

2.挙動

gc_divisorとgc_probabilityの動作が気になったので、さらにPHP知っている人にも聞いてみることにしました。 どうやら、以下の式が成り立つときにgcが実行されるようです。

 \displaystyle { (0 < x < 1 ) < \frac{session.gc\_probability}{session.gc\_divisor}}

実際のPHPコードを読んでみましたが、下記の箇所が該当すると思います。

nrand = (zend_long) ((float) PS(gc_divisor) * php_combined_lcg());
if (PS(gc_probability) > 0 && nrand < PS(gc_probability)) {
    PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num);
}

また、gcが動作すると、max_lifetimeを超えているセッションデータは一斉に削除されます。

一斉に削除されます(←ここ重要)

そのため、使用しているDBの性能によっては、動作が重くなる可能性もあるので注意しましょう。

できることなら、ある程度の件数ずつ削除していくといいのではないかと思います。

そろそろPythonのこと書いていきたい・・ Chainerもっと頑張らなきゃ

参考

PHPの公式リファレンス:PHP: 実行時設定 - Manual

PHPのセッションに関するコード:php-src/session.c at master · php/php-src · GitHub