memcached で PHP セッションを共有してみる

単一サーバで提供している社外向けの PHP サイトアクセスが増大してきた(厳密に言うと、アプリケーション数が増大してきた)ので、そろそろ負荷分散を考えなければならなくなってきた。

PHP セッションを複数サーバで共有するというと、セッション情報をどこに入れるか、という事を考えることになる。で、これには、
o NFS マウントしたディスク
o DB / チュートリアル
といった選択肢があるが、今回は mixi や slashdot でも導入されてるとか言う memcached を使ってみることにした。

使ってみた限りではキャッシュ読み書きはさすがに高速。どっちかっていうと PHP 応答が遅い(アプリ側の)方が問題になりそうだ。

--
セッションハンドラには、weirdsessionを使った。
session_set_save_handler() でセッションハンドラをオーバライドしているので、既存のコードの頭に
require_once('weirdsession.inc.php');

とするだけで、既存アプリの session_start() がそのまま使えて楽ちん。memcached を動かすサーバを設定した上で、↑に転がっている example.php を

<?php
require_once('weirdsession.inc.php');
session_start();
if(isset($_GET['sid']))
{ session_id($_GET['sid']);
}if (!isset($_SESSION['TEST']))
{ $_SESSION['TEST'] = time();
}$_SESSION['TEST3'] = time();

print "saved session variable (saved time()) ... " . $_SESSION['TEST'];
print "<br><br>";
print "output of time() now ... " . $_SESSION['TEST3'];
print "<br><br>";
print session_name() . ": " . session_id();
print "<br><br>";
print $_SERVER['SERVER_ADDR'];
?>
<form action="" method="get">
session id: <input type="text" name="sid">
<input type="submit" value="submit">
</form>

こんな感じにして、sid を適当に指定できるようした上で、複数サーバに設置。うん、ちゃんと共有できてるみたい。

続いて、memcached は起動時にキャッシュサイズを指定するのだが、デフォルトは 64MB となっている。これが適当なのかを検証。

実際に社外に提供しているアプリを使って、セッションハンドラに↑の weirdsession を使ってみる。で、JMeter 使って適当に http アクセス負荷をかけながら、こんなスクリプトを使用し、
$ while :; do clear; ./memcached-tool 127.0.0.1; sleep 1; done

といった感じで、キャッシュ状況を監視。
キャッシュ状況は 1MB/page 内に収まっているみたい。64 MB で十分事足りそうだ。
# Item_Size Max_age 1MB_pages Full?
6 B 0 s 0 yes
7 4 kB 139 s 1 no
8 B 0 s 0 yes
9 B 0 s 0 yes
10 B 0 s 0 yes
11 B 0 s 0 yes
12 B 0 s 0 yes
13 B 0 s 0 yes
14 B 0 s 0 yes
15 B 0 s 0 yes
16 B 0 s 0 yes
17 B 0 s 0 yes

アイテムサイズもこの程度であれば、よほど積み上がってしない限り問題はなさそう。
ただ、
Bulknews::Subtechによると、
memcached はストアするオブジェクトのサイズごとに異なるLRUキャッシュ(クラス)を保持する。また、あるクラスのデータをいれようとしたときにすでにメモリが埋まっていると、Out of Memory エラーとなる。

らしいので、実アクセスでどうなるかはもうちょっと検証が必要かな。