Home > CakePHP | PHP | Web+DB > CakePHPとnginx+memcachedで手軽にキャッシュを活用する

CakePHPとnginx+memcachedで手軽にキャッシュを活用する

この記事の所要時間: 439

nginx+memcachedがめちゃ気になったので試してみました。

元ネタは下記です。

A 53,900% speedup: Nginx, Drupal, and Memcache bring concurrency up and page load time way down | TechnoSophos

nginxをリバースプロキシに利用した構成で、バックエンドの出力をmemcachedにキャッシュしておけば、次回リクエストではnginxがそのキャッシュを読み取ってそのまま出力してくれます。

つまりバックエンドにリクエストを経由させずにnginxから即出力するのでかなりの高速化が見込めるという優れものです。

リンク先ではバックエンドにDrupalを利用していたのですが、ここではCakePHPを利用してみます。

1. 全体構成

リバースプロキシにnginx(Port: 80)を使い、バックエンドにはapache+mod_php(Port: 8080)を使います。

nginxはリクエストが来るとURLをキーとしたキャッシュがmemcachedにあるかを調べます。キャッシュがあればそれをレスポンスとしてそのまま返します。

キャッシュが無い場合はバックエンドにリクエストが飛びます。バックエンドではページ生成処理を行い、出力内容をmemachedURLにキャッシュします。

これにより次回リクエストからはこのキャッシュがnginxから出力されます。

試したバージョンは以下。

  • nginx 0.7.65
  • memcahed 1.2.8
  • apache 2.2.14
  • PHP 5.2.10
  • CakePHP 1.2.6

2. nginx+memcached設定

nginxのmemcached連携を行うためにNginxHttpMemcachedModuleを利用します。NginxHttpMemcachedModuleはnginxをデフォルトでインストールすれば含まれています。

nginx.confを以下のように設定します。

# バックエンド
upstream backends {
    server 127.0.0.1:8080;
}

http {
    #(snip)

    server {
        #(snip)

        location / { 
            # POSTはそのままバックエンドへ
            if ($request_method = POST) {
                proxy_pass http://backend;
                break;
            }

            # memcachedにキャッシュがあればキャッシュを
            # 無ければバックエンドへ
            set $memcached_key $uri;
            memcached_pass     127.0.0.1:11211;
            default_type       text/html;
            error_page         404 502 = @fallback;
        }

        location @fallback {
            proxy_pass         http://backend;
        }
    }
} 

ここで注意が必要なのが「error_page 404 502 = @fallback;」の箇所。

memcachedにキャッシュが無い場合はバックエンドへリクエストを投げるのですが、この箇所を[=]抜きにすると404(キャッシュが無い)や502(memcachedが繋がらない)がステータスコードとして出力されてしまいます。

つまりキャッシュが無い場合だとページ自体はバックエンドが生成した内容が出力されるのですが、ステータスコードが404となってしまいます。

[=] を付けるとバックエンドで出力されたステータスコードがそのままレスポンスとして出力されるので、[=]を忘れないようにしましょう。(はまりました。。。)

3. バックエンドでキャッシュ処理

次にバックエンドで生成した内容をmemcachedにキャッシュします。

まずPHPからMemcacheにアクセスするために、pecl::memcacheをインストールします。

$ sudo pecl install memcache

ここではCakePHPでの処理を想定しており、MemcacheViewHelperというヘルパを作成してキャッシュを行います。

MemcacheViewHelperはafterLayoutメソッドでビューからの出力全体をmemcachedにキャッシュします。

ちなみにHelper#afterLayout()はフレームワークから呼ばれるフックメソッドで、下記のように出力全体に対して処理を行うことが出来ます。例えば文字エンコーディングを変換する時などなかなか便利なメソッドです。

[app/views/helpers/memcache_view.php]

<?php
class MemcacheViewHelper extends AppHelper {
  public function afterLayout() {
    if (!empty($this->params['memcache_view']['is_cache'])) {
      $view = ClassRegistry::getObject('view');

      $memcache = new Memcache();
      $memcache->addServer('localhost', 11211);
      $memcache->set(Router::url(), $view->output, false, 3600);
    }   
  }
}

コントローラでMemcacheViewHelperを読み込みます。キャッシュを有効にするアクションでは$this->params[‘memcache_view’][‘is_cache’]にtrueをセットします。

下のUsersControllerの場合、indexアクションはキャッシュされますが、viewアクションはキャッシュされません。

[app/controllers/users_controller.php]

<?php
class UsersController extends AppController {
  public $name = 'Users';
  public $helpers = array('MemcacheView');

  public function index() {
    $this->User->recursive = 0;
    $this->set('users', $this->paginate());
    // キャッシュする
    $this->params['memcache_view']['is_cache'] = true;
  }

  public function view($id = null) {
    if (!$id) {
      $this->Session->setFlash(__('Invalid User', true));
      $this->redirect(array('action' => 'index'));
    }   
    $this->set('user', $this->User->read(null, $id));
  }
}

これでブラウザからnginx(ex. http://localhost/users/index)にアクセスすると 1 回目はバックエンドにリクエストが飛びますが、2回目以降はmemcachedのキャッシュが出力されます。

4. パフォーマンス

キャッシュの効果を見るために、nginx+memachedを使ったパターンとバックエンドに直接接続した場合とでパフォーマンスを計測してみました。

計測はabで行っています。(-c 100 -n 1000)数値はRequests per secondで、5回行った平均値です。

参考にキャッシュをファイルに出力してnginxから出力するパターンも計測しました。

構成 Requests per second
apache+mod_php+CakePHP
(ダイレクト)
13.814 100%
nginx+memcached 2034.262 14726%
nginx+ファイル(参考) 5806.798 42037%

やはりapache+mod_php+CakePHPよりnginx+memcachedが圧倒的に早いですね:D ここまで大きな差があると使ってみたくなります。

5. memcached or ファイル

上記パフォーマンスを見るとmemcachedよりfileの方がより多くのリクエストを捌いています。

パフォーマンスだけを見るとファイルが有利ですが、memcachedの方はnginxサーバやWebサーバが複数台になった場合にキャッシュの取り扱いが簡単(複数台で共有しやすい)という利点があります。また、memcachedなら有効期限が簡単に付けられるというのもあります。

どちらを使うのが良いかはケースバイケースですが、キャッシュの取り扱いを考えると個人的にはmemcachedが良いバランスかなと思っています。更新頻度が少ないがアクセス数が多いページだけはファイルに出力してしまうという方法もあります。

いかに遅い箇所を経由させずにレスポンスを返すかという視点で見るとnginx+memcachedはまさに願ったり叶ったりの構成です。ここではバックエンドにCakePHPを使いましたが、他のフレームワークでも他のシステムでも他の言語でも何でも理屈は同じです。

多くの環境から操作できるmemcachedをキャッシュエンジンに使うということは、バックエンドを選ばずにキャッシュ機構が使えるということで、これはよく考えられていますね。

Pocket

follow us in feedly

トラックバック:6

このエントリーのトラックバックURL
http://www.1x1.jp/blog/2010/04/cakephp_nginx_memcached.html/trackback
Listed below are links to weblogs that reference
CakePHPとnginx+memcachedで手軽にキャッシュを活用する from Shin x blog
pingback from » CakePHPとnginx+memcachedで手軽にキャッシュを活用する | Shin x blog My_Room-bookmarks 10-04-07 (水) 11:34

[…] CakePHPとnginx+memcachedで手軽にキャッシュを活用する | Shin x blog […]

pingback from 12時のヘッドライン | CROSS SBM 10-04-07 (水) 12:05

[…] CakePHPとnginx+memcachedで手軽にキャッシュを活用する | Shin x blogはてブ:15 […]

pingback from CakePHPとnginx+memcachedで手軽にキャッシュを活用する | Shin x blog | とっても! ちゅどん(雑記帳) 10-04-07 (水) 13:55

[…] CakePHPとnginx+memcachedで手軽にキャッシュを活用する | Shin x blog […]

pingback from Ikemasa Blog - jQuery UI のサーバは nginx を使っていた 10-05-24 (月) 1:45

[…] CakePHPとnginx+memcachedで手軽にキャッシュを活用する リバースプロキシとして利用。memcached と組み合わせてものすごい高速化。やる価値がありそう。 […]

pingback from Nginx + memcached で WordPress をキャッシングしてみる : dogmap.jp 12-01-12 (木) 4:03

[…] + memcached が気になったので試してみました。元ネタは、下記です。CakePHPとnginx+memcachedで手軽にキャッシュを活用する – Shin x blogNginx では、HttpMemcachedModule を用いることで memcached […]

pingback from WordPressのMemcachedプラグインを使ったMemcachedとKyotoTycoonパフォーマンスの比較 | Cloud Berry 12-01-21 (土) 19:43

[…] [1] CakePHPとnginx+memcachedで手軽にキャッシュを活用する http://www.1×1.jp/blog/2010/04/cakephp_nginx_memcached.html […]

Home > CakePHP | PHP | Web+DB > CakePHPとnginx+memcachedで手軽にキャッシュを活用する

検索
フィード
メタ情報

Return to page top