前の記事 ≪:HTML5ビデオの内容に併せて他コンテンツを連動させて切り替えられるフ...
次の記事 ≫:WordPressデフォルトテーマのTwentyTenから派生した12のテーマ

過負荷に耐えるWEBサービス作成のための使えるPHPキャッシュテクニックまとめ

2011年03月10日-はてなブックマーク

スポンサード リンク
[PR] 英単語を忘却曲線アプリを使って超効率よく記憶する方法
過負荷に耐えるWEBサービス作成のための使えるPHPキャッシュテクニックまとめ。
サービス展開というとOSのチューニングや各種インフラソフトウェアのチューニング、更にはWEBアプリプログラム自体の効率化と、幅広い知識が必要になってきますが、PHPでWEBアプリを作る際によく効くキャッシュテクニックを用途・使いどころ別に説明します。

キャッシュをうまく効かせることで大幅に計算量を減らしてより多くのリクエストを少ないマシンで捌くことが出来、コストを下げたり、過負荷の悩みを減らせます。
個人レベルでのWEBサービス開発の場合、サーバ代がお財布を大きく圧迫しますが、最低のコストでサービスを賄うことに繋げられます、ということでPHPでサービス作ってやろうと思っている人は参考にしてみて下さい。



static変数でキャッシュ
特に何も入れなくてもそのまま使えるstatic変数。例えば、関数等で一定の計算をした後、値を返すような関数の場合、キャッシュしておくことで、何度も呼び出す場合は効率が上がります。
<?php 
 
echo hoge(1); 
echo "<br>"; 
echo hoge(2); 
echo "<br>"; 
echo hoge(1); 
echo "<br>"; 
echo hoge(1); 
echo "<br>"; 
echo hoge(1); 
echo "<br>"; 
 
function hoge($id) { 
    static $cache; 
    if (isset($cache[$id])) { 
        echo "cached!!n"; 
        return $cache[$id]; 
    } 
    $ret = $id; 
    for ($i=0;$i<1000;$i++) { 
        $ret += $i; 
    } 
    $cache[$id] = $ret; 
    return $ret; 
} 
?>

出力例

499501
499502
cached!!
499501
cached!!
499501
cached!!
499501

青色部分の計算が2回目以降は不要になります。cached!! が表示されているところはstatic変数からデータを読んだということです。
これがなかったら、毎回1000回のループを関数内で回して大変なことになります。
但し、この方法は、PHPのセッションが終わった時点でクリアされるので、何度も呼び出すような関数やメソッドで使います。

使いどころ: 何度も呼び出されるけど同じ結果を返す関数・メソッド内で返り値を予めキャッシュして無駄な計算を減らす用途

より詳しい情報をご連絡頂いたのでリンク:
PHP :: static を使って関数をメモ化する [Tipsというかメモ]

apcでキャッシュ
コードを中間形式にしてくれるapcですが、コード内でキーバリュー型で変数を持たせることも出来ます。
apcが有効になっていれば、apc_fetchapc_store 関数によってデータの取得・設定が出来ます。



PHPのセッションが終わってもデータは消えず、共有メモリにデータを保存するので、PHPで使える最も高速なキャッシュの機構として使えます。
memcachedを使ったキャッシュよりも高速にキャッシュできつつ、キャッシュの有効期限が決められます。
弱点として、メモリをどんどん圧迫するため、メモリをあまり積んでいないマシンで使えないということと、apacheの再起動で全部データが飛んでしまい、サービス復帰時にまたキャッシュする作業が入ることになり、アクセスの多いサービスではサービスが停止してしまうリスクがあります。
更に、複数のマシンに分散させることが出来ず、サーバが4台あったら、4台それぞれがキャッシュをするというモデルになります。

サンプルコード(リファレンスはこちら

<?php 
apc_store('foo', $bar); 
var_dump(apc_fetch('foo')); 
?>

使いどころ:最も高速に動作するということで、速度が求められる部分、そしてapacheの再起動が起きてキャッシュがクリアされてしまっても問題ない部分に利用

memcachedでキャッシュ
ご存知、memcached。memcached自体がメモリにデータをキャッシュしてくれるため、apcよりは低速ですが、ネットワークインタフェースを用いることができ、キャッシュサーバを他のサーバに分離したり、memcachedを分散させて、大きなキャッシュを作ることが可能。
phpのエクステンションで、memcachememcached の2種類あって、紛らわしいのですが、memcacheは他のライブラリを必要とせず、そのままインストール出来、memcachedはlibmemcachedという外部ライブラリに依存しているというものです。どちらもメリットがあるので、こちらを参考にさせて頂いたり、実際にベンチを取って選択するのがよさそう。



apacheはログのローテート時なんかに再起動させたり、以外と再起動のタイミングが多かったりしますが、memcachedに格納されていれば消えることはない(但しmemcachedを再起動したら消える)ので、apc と使い分ければよいです。

以下、memcached エクステンションでのサンプルコード(リファレンス)

<?php 
$md = new Memcached(); 
$md->addServer('localhost', 11211); 
$md->set('foo', 'bar', 3600); // 1時間有効 
echo $md->get('foo'); 
?>
使いどころ:速度はapcよりは劣るが高速。サーバを分散させたり色々便利な機能も使える。ただ、マシンやmemcacheデーモンの突然停止によってデータは消えるので消えてもいいデータを入れる。ネットワーク経由での格納なので、数台から同じキャッシュを参照することも出来る。但し、ネットワークの速度がでない場合はそこがボトルネックになる点に注意。

tokyotyrantでキャッシュ
tokyotyrant は本ブログでも何度か取り上げていますが、memcached よりちょっと遅いけど、memcached並のパフォーマンスが出る上、ファイルにも同期するのでデータが消えないというもの。ただし、データベースファイルが壊れたりすることもあるので、信頼性の必要なストレージには向いていない。 更に、サーバのIO負荷が高くなるとファイルに同期する仕様上、性能が悪くなるので注意。
<?php 
$tt = new TokyoTyrant('localhost', 1978); 
$tt->put('test', 'hogehoge'); 
echo $tt->get('test'); 
?> 

使いどころ:apcや、memcachedより速度は落としてでも、サーバが落ちてもデータは残したい、という場合に使えます。それでいてそれなりに速度が出ます。ネットワーク経由でも使えるので、複数台から参照することも可能。IO負荷には注意。

redisでキャッシュ
redis本体とphpredisでphpから利用。
tokyotyrant同様、key-value でデータを格納しつつ、ファイルにも非同期ですが同期を取ることも出来ます(TokyoTyrantは同期的)。
key-value の value のデータに型を持たせることが出来たり、レプリケーション機能なんかも備えています。
IOは非同期なのでそれほど激しくなさそうですが、同期されていなかったデータは当然消えてしまいます。
実運用で使ったことはないので、あまり多くを語れませんが、memcachedとtokyotyrant の中間的な使いどころになるのかな。

以下、redisの参考エントリ

Documentation – Redis
redisドキュメント日本語訳 — redis v2.0.3 documentation
redis 使ってますか? - Twisted Mind
DECOLOG TECH BLOG: redisの実用例。redis速いよ速いよredis
KOSHIGOE学習帳 - [KVS][Redis] Redis 概要

ファイルへのキャッシュ
ファイルへのキャッシュは自分で作ってもいいのですが、オープンなもので有名なのはPEAR::Cache_Liteです。
サイトへのアクセスやファイル数が相当多くなければ、ファイルベースのキャッシュであっても殆ど問題ありませんが、アクセスが多くなって参照するファイル数が増えメモリに載らなくなってくると、IO負荷が増えてサービス停止等、大変なことになるので注意。
メリットとしては、ハードディスクに保存するため、当然サーバ再起動などでデータは基本失われず、OSにファイルがキャッシュされていれば高速で、メモリも予め何GBと取っておく必要がない部分。

<?php 
$options = array( 
    'caching'  => true, 
    'lifeTime' => 60*60, 
    'cacheDir' => 'cache/', 
    'hashedDirectoryLevel' => 2 // ディレクトリ階層を分ける 
); 
$cache = new Cache_Lite($options); 
if ($data = $cache->get($cacheid)) { 
    echo $data; 
} else { 
    $output = "php"; 
    $cache->save($output); 
} 
 
?>

使いどころ:まず最初に入れられるお手軽な簡易キャッシュとして。重い処理部分をキャッシュすれば効果は大きいです。

その他のKVSでキャッシュ
他にもtokyocabinetをベースとした分散key-valueの仕組みとして以下のようなものもあります。
分散ストレージということで、より大きく、性能のいいキャッシュやストレージを構築する際に使えそう。

flare - GREE Lab さんの公開している分散KVS (ストレージはTokyoCabinet)
kumofs - えとらぼさんの公開している (ストレージはTokyoCabinet)

ここら辺もおいおい検証していこうと思います。

尚、誤記や間違いありましたら、@phpspot_kj のtwitterアカウントまでご連絡下さいませ。

関連の記事検索:PHP, キャッシュ
スポンサード リンク

By.KJ : 2011年03月10日 10:06 livedoor Readerで購読 Twitterに投稿

間違いの指摘をしていただける方はメール、あるいはTwitter/FBでお願いします(クリック)