KyotoTycoonのmemcachedプラグインにPHP(PECL)からアクセスする
メモ書きにつき。
PECLのMemcacheクラスを使ってKyotoTycoonにアクセスしていたが、あるデータサイズを超えた時、突然データが「壊れる」という現象に遭遇。原因を究明するため、以下のようなコードで試してみた。
<?php $str_1k = ''; foreach(range(1, 1024) as $i) { $str_1k .= 'a'; } $str_5k = ''; foreach(range(1, 5) as $i) { $str_5k .= $str_1k; } $str_10k = ''; foreach(range(1, 2) as $i) { $str_10k .= $str_5k; } $str_15k = ''; foreach(range(1, 3) as $i) { $str_15k .= $str_5k; } $str_20k = ''; foreach(range(1, 2) as $i) { $str_20k .= $str_10k; } $str_30k = ''; foreach(range(1, 3) as $i) { $str_30k .= $str_10k; } $m = new Memcache; $m->addServer('kt-domain', 1975); $m->set('test-1k', $str_1k); $m->set('test-5k', $str_5k); $m->set('test-10k', $str_10k); $m->set('test-15k', $str_15k); $m->set('test-20k', $str_20k); $m->set('test-30k', $str_30k); echo "test-1k: " . mb_strlen($m->get('test-1k')) ."\n"; echo "test-5k: " . mb_strlen($m->get('test-5k')) ."\n"; echo "test-10k: " . mb_strlen($m->get('test-10k')) ."\n"; echo "test-15k: " . mb_strlen($m->get('test-15k')) ."\n"; echo "test-20k: " . mb_strlen($m->get('test-20k')) ."\n"; echo "test-30k: " . mb_strlen($m->get('test-30k')) ."\n"; $m->delete('test-1k'); $m->delete('test-5k'); $m->delete('test-10k'); $m->delete('test-15k'); $m->delete('test-20k'); $m->delete('test-30k');
念のためmb_strlen関数を使ってるが、これで格納されてるデータのサイズを取得できるはず。そう思って実行したら、こんな結果が出てきた。
test-1k: 1024 test-5k: 5120 test-10k: 10240 test-15k: 15360 test-20k: 44 test-30k: 53
上記を起点にもう少し詰めてみると、どうも20kbを超えたところから極端にデータサイズが落ちてる。実際に中身を見てみると、アルファベットしか入ってないはずなのに化ける。
最初はKyotoTycoonのデータサイズの上限かと勘ぐってしまったが、どうもそんな記述はない。となると、Memcacheクラスのどこかに何かがある。
そう思ってMemcacheのドキュメントを漁ってみると、これが出てきた。
→PHP: Memcache::setCompressThreshold - Manual
キャッシュするデータ量を抑えるために、ある一定以上のデータサイズについては圧縮をする設定のことだ。特にディフォルト値の記述はないが、サンプルコードにある「20000」という指定が怪しい。試しに、上記スクリプトのaddServerの直後に、以下のコードを入れてみた。
$m->setCompressThreshold(0, 0);
多分これならどんなデータサイズでも無圧縮で入れてくれるはず、と思って、再度スクリプトを実行。その結果は
test-1k: 1024 test-5k: 5120 test-10k: 10240 test-15k: 15360 test-20k: 20480 test-30k: 30720
20kb以上のデータもちゃんと取れるようになった。と、ここで、そもそも何故このご時世にMemcachedクラスの方ではなくMemcacheクラスを採用していたかを思い出した。Memcachedクラスを使用したとき、何を入れてもデータが「壊れて」しまっていたので、てっきりKyotoTycoon(のmemcachedプラグイン)とは相性が悪いんだと思ってたけど、実際には圧縮して格納していたため、参照時に解凍できてないだけなのかも。
と思ったので、Memcacheの定義部分を以下に変更。
$m = new Memcached; $m->addServer('kt-domain', 1975); $m->setOption(Memcached::OPT_COMPRESSION, false);
これを実行してみたら、全く問題がなくなった。ということで、問題の本質は圧縮の設定だったということですね。となると、KyotoTycoonにデータを圧縮して入れるには、どうしたらいいんだ。。。?