Elementキャッシュ

ホームなど、ポータル系の画面で
新着情報エリア
自分の情報エリア
RSS情報エリア
・・・などのように更新タイミングが分かれている場合は、Elementキャッシュがよいようです。

Elementキャッシュ導入で、参考にしたのは以下。
http://text.tklabo.net/blog/8/view-cache


Elementキャッシュ導入で、表示が1.4回/秒から、3.9回/秒に向上しました*1


今回適用する画面は、現状3つのパーツにわかれています。

 A:ユーザ表示
 B:自分の新着
 C:全体の新着

で、Cのみログイン/未ログインを問わず、全員で共通表示します。


A/B/Cを、それぞれElementキャッシュしました。


ポイントは、 A/Bは、キャッシュ名(key)にセッションIDをいれた点です。


B(Aも同様)

	echo $this->renderElement('character_picture_table', array(
	'header' => sprintf(__("%s's Characters", true), $target_user['User']['name']),
	'characters' => $target_user_characters,
(中略)
+	'cache' => array(
+		'time' => time() + Configure::read('Cache.expire'),
+		'key' => $session->id(),
+	) 
));

C

echo $this->renderElement('character_picture_table', array(
	'header' => __('Latest Characters', true),
	'characters' => $public_characters,
(中略)
+	'cache' => array(
+		'time' => time() + Configure::read('Cache.expireShort'),
+		'key' => null,
+	) 
));

オプションパラメータに $options['cache']['key']を指定すると、キャッシュファイル名が
 element_[key]_[エレメントファイル名]
となります。


keyにセッションIDを入れることで、それぞれのユーザごとに
「ホーム用自分の新着」キャッシュを持たせる事ができます。

実際のキャッシュファイル作成状態

キャッシュが無い状態で、未ログインユーザがアクセス。

[cake@cake chara-shee]$ ls -l app/tmp/cache/views/
合計 44

  • rw-r--r-- 1 apache apache 3163 7月 16 15:15 element__character_picture_table
  • rw-rw-r-- 1 cake cake 0 7月 13 15:05 empty

まず、Cのキャッシュができます。


ここから、ユーザ1でログイン。

[cake@cake chara-shee]$ ls -l app/tmp/cache/views/
合計 44

  • rw-r--r-- 1 apache apache 3163 7月 16 15:15 element__character_picture_table
  • rw-r--r-- 1 apache apache 2800 7月 16 15:21 element_ekg7u0r93oa1j486f1k99mkpe7_character_picture_table
  • rw-r--r-- 1 apache apache 295 7月 16 15:21 element_ekg7u0r93oa1j486f1k99mkpe7_home_left
  • rw-rw-r-- 1 cake cake 0 7月 13 15:05 empty

ユーザ1用のA/Bのキャッシュが作成されます。
この時、Cは更新されてないのがポイント。


さらに、別窓からユーザ2でアクセスすると、ユーザ2用のキャッシュが別途作成されます。

[cake@cake chara-shee]$ ls -l app/tmp/cache/views/
合計 44

  • rw-r--r-- 1 apache apache 3163 7月 16 15:15 element__character_picture_table
  • rw-r--r-- 1 apache apache 2800 7月 16 15:21 element_ekg7u0r93oa1j486f1k99mkpe7_character_picture_table
  • rw-r--r-- 1 apache apache 295 7月 16 15:21 element_ekg7u0r93oa1j486f1k99mkpe7_home_left
  • rw-r--r-- 1 apache apache 2868 7月 16 15:23 element_l6o3bnorfrm87r1nsdlnlm4sa5_character_picture_table
  • rw-r--r-- 1 apache apache 319 7月 16 15:23 element_l6o3bnorfrm87r1nsdlnlm4sa5_home_left
  • rw-rw-r-- 1 cake cake 0 7月 13 15:05 empty


仕上げに、ユーザ情報の更新/削除/ログアウトがあった場合のキャッシュ削除を入れて完成*2

ソース差分抜粋
app/models/app_model.php
+
+       /* キャッシュ削除 */
+       // ホーム関連
+       function deleteCacheHome()
+       {
+               $this->deleteCacheLastCharacters();
+               $this->deleteCacheAnonymousHome();
+               $this->deleteCacheMyHome();
+       }
+
+       // 最近更新されたキャラクター
+       function deleteCacheLastCharacters()
+       {
+               @unlink(CACHE.'views'.DS.'element__character_picture_table');
+       }
+
+       // 未ログインホーム
+       function deleteCacheAnonymousHome()
+       {
+               @unlink(CACHE.'views'.DS.'element__home_right');
+       }
+
+       // マイホーム
+       function deleteCacheMyHome()
+       {
+               $Session = CorePlus::set_behavoir('Session');
+
+               if (!$Session->id()) {
+                       return false;
+               }
+
+               @unlink(CACHE.'views'.DS.'element_'.$Session->id().'_character_picture_table');
+               @unlink(CACHE.'views'.DS.'element_'.$Session->id().'_home_left');
+       }
+
 }

app/models/behaviors/session.php
@@ -0,0 +1,27 @@
+<?php
+class SessionBehavior extends CakeSession {
+       function setup(&$Model,$config = array()){
+               $base = null;
+               $start = Configure::read('Session.start');
+               extract($config);
+
+               $session = null;
+               if(ClassRegistry::isKeySet('CakeSession')){
+                       $session = ClassRegistry::getObject('CakeSession');
+               }else{
+                       App::import('Core','CakeSession');
+                       $session = new CakeSession($base,$start);
+
+                       ClassRegistry::addObject('CakeSession',$session);
+               }
+
+               $Model->Session = $session;
+               if($start && !$Model->Session->started()){
+                       $Model->Session->start();
+               }
+       }
+
+       function id($id = null) {
+               return parent::id($id);
+       }
+}

app/models/user.php
@@ -135,6 +135,16 @@ class User extends AppModel {
        {
                return parent::beforeSave($options);
        }
+       function afterSave($created) {
+               $this->deleteCache4User();
+
+               return parent::afterSave($created);
+       }
+       function afterDelete() {
+               $this->deleteCache4User();
+
+               return parent::afterDelete();
+       }

@@ -156,4 +166,13 @@ class User extends AppModel {

                return parent::betweenWrapper($check[0], $idLength['min'], $idLength['max']);
        }
+
+       /* キャッシュ削除 */
+       function deleteCache4User()
+       {
+               // Home
+               $this->deleteCacheHome();
+       }
+
+
 }

app/views/elements/home_right.ctp
@@ -17,7 +17,10 @@
                        'action' => 'index',
                        $target_user['User']['id'],
                ),
-
+               'cache' => array(
+                       'time' => time() + Configure::read('Cache.expire'),
+                       'key' => $session->id(),
+               )
        ));
 ?>
 <?php endif; ?>
@@ -37,7 +40,10 @@
                        'controller' => 'characters',
                        'action' => 'index'
                ),
-
+               'cache' => array(
+                       'time' => time() + Configure::read('Cache.expireShort'),
+                       'key' => null,
+               )
        ));
 ?>

app/views/users/index.ctp
@@ -1,14 +1,23 @@
 <div id="home" class="layout2colums users view">
 <?php
-if (!empty($user['User']['id'])) {
-       echo $this->renderElement('home_left', array(
-               'user' => $user,
+$key = null;
+
+if ($user['User']['id']) {
+       $key = $session->id();
+
+       echo $this->element('home_left', array(
+               'target_user' => $user,
                'owner' => true,
+               'cache' => array(
+                       'time' => time() + Configure::read('Cache.expire'),
+                       'key' => $key,
+               )
        ));
 }

*1:ApacheBench測定。向上の度合いは内容や環境によります

*2:モデルでセッション情報の取得は、http://d.hatena.ne.jp/hiromi2424/20100203 を参考にしました