PHPセッションをPhpRedisに保存する


概要

PHPのRedis通信拡張(extension)であるPhpRedisでは、通常のRedisへの入出力に加えて、PHPセッションを保存する機能が提供されています。
PHPセッションは、デフォルトでは/tmpや/var/tmpなどといった一時ディレクトリにファイルとして保存されます。高負荷が予期されるサーバにおいて、ファイルI/Oが気になるような環境では、memcachedやRedisといったオンメモリKVSデータベースの利用を考えることになりますが、PhpRedisはその選択肢の1つになるのではないでしょうか。

インストール

PhpRedisのインストール自体はLinux系ならyumやapt-get、macOSならHomeBrewやMacPorts、*BSD系ならports collectionといった各パッケージシステムから利用できるかと思います。
また、私が書いたこちらも、参考になれば幸いです。

参考:macOS(Mac OS X)にPhpRedisをインストール

設定

PhpRedisのGitHubにあるREADME.markdownに書いてあるとおり、PhpRedisではphp.iniにハンドラ設定をすることでPHPセッションを保存に対応すると記されています

PHPセッションを保存するには、php.iniに次のような2行を設定します。

PHPセッションを保存するphp.iniの設定
# grep ^session /opt/local/etc/php56/php.ini
session.save_handler = redis
session.save_path = "tcp://localhost:6379"
(以下略)

1行目はハンドラとしてredisを使うことを宣言しています。デフォルトではここはfilesになっていますので、ここを書き換えます。
書き換えがためらわれる方は、ここを行コピーして、filesの行をコメントし、コピー行のfilesをredisに書き換えます。

2行目は保存パスです。filesの場合はここは/tmpなどのようにディレクトリパスが記載されていますが、redisではTCP経由で行いますので、tcp://localhost:6379を指定しています。
注意したいのはlocalhostの部分で、ここはredis-serverがコネクションを確立できる(TCP経由でデータを送受信できる)アドレスを指定します。ホスト名もしくはIPアドレスを指定することになります。
ホスト名(IPアドレス)の項目の右にある:の、さらに右にある数値がポート番号で、デフォルトではRedisは6379/TCPを使用します。別のポート番号を使っている人は、ここの値も同じものにしてください。

いくつかオプションが付けられますが、複数サーバでの運用とかタイムアウトとか、そうしたものを指定したい場合に加えることができます(少しだけ後述)。

動作確認

さて、これで本当にRedisに保存されるのでしょうか。
ということで、動作確認をしてみます。redis-serverはあらかじめ起動しておく必要があります。

redis-serverの起動の例
# redis-server &

次に、PHPセッションを使うテストコードsession.phpを用意します。

session.php
<?php
session_start();

echo "save_handler=" . ini_get("session.save_handler") . "\n";
echo "save_path=" . ini_get("session.save_path") . "\n";
echo "session_id=" . session_id() . "\n";

$_SESSION['libname'] = "PhpRedis";

テストコードを実行する前に、必要な確認作業があります。
当然ですが、現時点でRedisに何も(少なくともPHPセッションIDなどが)入っていないことを確認しなければなりません。

Redisの中にキーが何もないことを確認
> redis-cli
127.0.0.1:6379> keys *
(empty list or set)

この場合は、あらゆるキーが入っていないことを確認できましたので、心置きなく動作確認ができます。

では、さきほどのsession.phpを実行してみましょう。

テストコードの実行
> php56 session.php
save_handler=redis
save_path=tcp://localhost:6379
session_id=h59pqds8s5sdj9j0anmiqh63s0

save_handlerやsave_pathが、さきほどphp.iniに設定したものと同じになっていれば、設定とテストコードはうまく合致していそうです。

そして、ここが肝心な部分ですが、表示されているsession_idと同じものが、Redisに保存されて入れば、成功ということになります。redis-cliコマンドで確認してみましょう。

redis-cliでRedisにPHPセッションが保存されていることを確認
> redis-cli
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:h59pqds8s5sdj9j0anmiqh63s0"

キーは含まれています。どうやら通信も行われてRedisにキーが保存できているようです。

では、$_SESSION["libname"]に代入した値は保存されているでしょうか。
セッションIDをキーにしてredis-cliからgetしてみましょう。

セッション変数の保存状況の確認
127.0.0.1:6379> get PHPREDIS_SESSION:h59pqds8s5sdj9j0anmiqh63s0
"libname|s:8:\"PhpRedis\";"

こちらも保存されているようですね。ファイルにPHPセッションを保存しているのと同様に、PHPシリアライズで保存されてます。保存内容自体は、保存先(save_handler)が変わっても同じであることも確認できたと言えそうです(当然ちゃ当然ですけど)。

オプション

最後に、指定できるオプションを簡単にご紹介しておきます。説明自体はPhpRedisのGitHubリポジトリにあるREADME.markdownのPHP Session handlerの項目に書かれています。

オプション デフォルト 意味
weight 整数(integer) 1 ホスト(サーバ)の重み付けの値。PHPセッションを複数のRedisホストに分散して保存する場合の比重を設定することができる。あるRedisサーバAが別のRedisサーバBの2倍の重みを持っているとしたら、Aは2倍のセッションを保持することになる。
timeout 小数(float) 86400 Redisサーバへのコネクションタイムアウトまでの秒数。この時間以内にRedisサーバに接続できなかった場合、クライアントはセッションを利用できない。
persistent 0もしくは1 0 永続的コネクションで利用する場合は1を指定する(試験的オプション)。
prefix 文字列 PHPREDIS_SESSION: キーの接頭辞として使用する文字。さきほどの動作確認でのキーを見ると、デフォルトの接頭辞が付いているのがわかる。
auth 文字列 (空欄) コマンド早出前の認証キー。Redisでauthを使っている場合に使用する。
database 整数 -1 データベース番号を指定する。

オプションの指定の仕方は、さきほどのREADME.markdownのPHP Session handlerの項目に書かれています(以下抜粋)。

オプションの指定方法
session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=2&timeout=2.5, tcp://host3:6379?weight=2"