PHPのSESSIONファイルを階層化されたディレクトリに保存する

By shin - 08/10/17 - このエントリをはてなブックマークに追加このエントリをYahoo!ブックマークに追加このエントリをdel.icio.usに追加このエントリをFC2ブックマークに追加

作成した携帯サイトのアクセス数が増えてくると様々な問題が発生します。

Linuxの場合、一つのディレクトリの配下に10000個から15000個程度のファイルを作成することが出来ますが、実際には5000個もファイルを作成するとディスクI/Oの性能が落ち、ファイル読み書きのパフォーマンスが落ちてしまいます。

PHPで作成した携帯サイトで、デフォルトの設定どおり一つのディレクトリにSESSIONファイルを保存する設定にしている場合、大量のアクセスがあると、一つのディレクトリに大量のSESSIONファイルを作成する事になり、上記の理由から結果的にレスポンスが落ちる事に繋がってしまいます。

今回はPHPのSESSIONファイルを複数の階層化されたディレクトリに保存する事により、一つのディレクトリ配下のSESSIOINファイル数を減らし、パフォーマンスが落ちる事を防ぐ様に設定してみます。

 

PHPのSESSIONの設定を変更する

session.save_path は、保存ハンドラに渡される 引数を定義します。デフォルトのファイルハンドラを選択した場合、 ファイルが作成される場所のパスになります。 session_save_path() も参照ください。

オプションの引数としてN(数値)を指定できます。 これはセッションファイルを分散して保存する際にディレクトリ階層レベルを決定します。 例えば、’5;/tmp’とすると /tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If という位置にセッションファイルを生成します。

PHPマニュアルに今回の設定の詳しい内容が記載されています。session.save_path ディレクティブの値のディレクトリ名の前に階層の深さを指定すると良い様です。その際、デフォルトの「/tmp」は他のユーザーにも権限があるので利用しない方が無難でしょう。(他のユーザがこのディレクトリのファイルのリストを取得できるので、セッションハイジャックされる危険があります。 )

/path/to/php.ini

 
session.save_path '5;/path/to/session'

 

SESSIONファイルを保存するディレクトリを作成する

残念ながらPHPの設定を変更するだけでは利用できないので、自分で階層化されたディレクトリを作成しておく必要があります。といっても、手作業でこの様な大量のディレクトリを作成していくのはさすがにキツいです。PHPは自動では作成してくれませんが、代わりにディレクトリ作成用のスクリプトを用意してくれているので、それを利用します。

Nを使用するには、これらすべてのディレクトリが 事前に作成されている必要があります。 そのためのシェルスクリプトがext/sessionに mod_files.shというファイル名であります。

PHPソースのあるディレクトリにあるmod_files.shに「SESSIOINを保存するディレクトリのパス」「階層の深さ」を引数として渡して実行すると、ディレクトリを作成してくれます。

sh mod_files.sh /path/to/sessioin 5

 

SESSIONファイルを削除する仕組みを実装する

今回の設定を行うと、PHPのSESSIONでガベージコレクション(不要SESSIONファイルを自動で削除してくれる機能)が効かなくなり、session.gc_maxlifetimeなどの関数や設定でSESSIONの有効期限を指定する事が出来なくなってしまいます。

代わりに下記の様な、設定したディレクトリの中のSESSIONファイルが作成されてからの時間が一定以上のファイルを検索して削除するシェルスクリプトを作成して、cronで任意の間隔で実行する事にします。

php_session_gc.sh

find /path/to/session -type f -mtime +1 -name 'sess_*' | xargs -r rm

 

これで、下記の様にSESSIONファイルを複数の階層化されたディレクトリに保存する事が出来るようになりました。

/path/to/session/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If