Make your CakePHP app ridiculously faster with “view caching”

Big or small, once your app goes to production you’d better start thinking about utilizing view caching ;)

Granted, view caching in a dynamic application can be tricky or impossible(?)…
but with proper usage wherever and whenever needed, it can make your app go off the charts in terms of performance.
If you are not familiar with view caching at all, you should read the CakePHP manual… yet I will give you some basic examples and couple of things that may not be so well known.

1. Enable view caching for 10 minutes for the main (index) page

public function index() {
$this->helpers[] = 'Cache';
$this->cacheAction = '10 minutes';
}

In this little snippet we’ll add the Cache helper, only when required by the given action. No need to load for the entire controller. (Once the page is “visited” for the first time, the given view will be cached… you can see the evidence of this in your app/tmp/cache/views directory).

2. Be mindful of what you are caching, certain things should remain dynamic

Whenever there is dynamic content within the the view, such as a div, which is updated by AJAX, for example, you’d want to utilize the cake:nocache tags, like so:

<cake:nocache><?php echo microtime(); ?></cake:nocache>

… but there are a few “gotchas” to be aware of…

a. Callbacks such as beforeRender() or beforeFilter() do not fire by default.

For larger scale apps this nearly kills the ability to use view caching.
However, not all is lost… In your controller you can setup a property to ensure that callbacks do run for certain actions where they are truly required (as shown in CakePHP manual):

public $cacheAction = array(
  'view' => array('callbacks' => true, 'duration' => 21600),
  'add' => array('callbacks' => true, 'duration' => 36000),
  'index'  => array('callbacks' => true, 'duration' => 48000)
);

Additional option proposed by jrbasso, is to fire-up the necessary logic by adding the following snippet to the layout:

<cake:nocache><?php
if (isset($controller) && is_a($controller, 'Controller')) {
  $controller->constructClasses();
  $controller->startupProcess();
}
?></cake:nocache>

Still a little overhead, but much much much faster overall. Both options achieve the same basic goal and I will leave it up to you to see, which one suits your needs better.

b. Spaces

Another excellent catch by mr. jrbasso is that if you have spaces between your cake:nocache and php tags, the “no-caching features” may not work as expected.
So be sure to always place your dynamic PHP code like so:

<cake:nocache><?php
if($dynamic) {
  echo 'This is a timestamp: ' . microtime();
}
?></cake:nocache>

c. Don’t surround your elements with cake:nocache tags.

Your entire element will not be cached by doing this:

<cake:nocache><?php echo $this->element('my_element'); ?></cake:nocache>

Yep, you have to go inside the element and decide what to cache or what not to cache. Which, in some cases makes sense, depends on the element really.
Alternatively, you can cache an entire element using the ‘cache’ key:

<?php echo $this->element('my_element', array('cache' => array(
   'time' => '+1 day',
   'key' => 'my_cached_element'
))); ?>

Since the element itself can have dynamic content, the ‘key’ can be used to create different “versions” of the cached element. Of course in the above example it is a static key, but in other cases you could create a dynamic key based on some conditions or criteria, which would make sense for your application.

Real-time updates vs view caching

It goes without saying that once your view is cached any changes to the underlying model will not be reflected until the cache is invalidated. In some cases it is perfectly fine, in others you might want to clear the cache once the model has been updated.
It is quite easily achieved by adding the following to your model:

public function afterSave() {
  clearCache('related_view*');
}

Granted, on the first hit to the page the cache will be rebuilt and some “extra” weight will be put on the application, yet by using this technique you’ll have the benefit of using the cache and real-time reflection of the updated data.

Don’t let APC get in the way

I am not sure if other PHP opcode engines can cause the same trouble, but at least with APC we’ve found that it can conflict with cake’s view caching. It would be a bit too much to go into details of the issue, but if you use both APC and view caching for your application and notice some strange behavior be sure to run APC with stat “ON” (which is the default behavior).

To learn a little more about this, you can take a look here

In summary I might as well throw this out: when comparing framework performance, using examples such as “Hello world!” don’t forget that any framework or application requires caching. As many other things, ensuring high-availability and excellent performance is quite easy in cake, and beyond that be sure to utilize other tools (APC, memcached, etc.), which are just as necessary in any modern web application as a web server itself.

m4s0n501
  • Pingback: Tweets that mention Make your CakePHP app ridiculously faster with “view caching” | nuts and bolts of cakephp -- Topsy.com()

  • http://deansofer.com ProLoser

    Why do you have to nocache an ajax-populated div? Isn’t cache server-side, while AJAX is client-side?

  • teknoid

    @ProLoser

    AJAX is a typical way to facilitate communication between the client and the server.
    If there is a need for an AJAX call to the server, it is likely that the data requested should be served in real-time… otherwise why bother with making the request? There could be exceptions, of course, but then maybe AJAX is not the way to go in the first place.

    Anyways, for the purpose of this article it was just an example of one common view part that is not likely to require caching.

  • Pingback: CakePHP : signets remarquables du 03/01/2011 au 14/02/2011 | Cherry on the...()

  • http://cake-php.ir Saleh Souzanchi

    very nice , tnx

  • BiBi

    Thanks very much, it saves my time to understand what cache of CakePHP does. I love you so much.

  • http://grahamweldon.com Graham Weldon

    Is there any reason you’re recommending Model::afterSave instead of Model::_clearCache ?

    I’d recommend Model::_clearCache as it allows you to clear the cache after a delete as well as a save, and is provided for precisely this purpose.

  • teknoid

    @Graham Weldon

    Great point…but in case of multiple servers the above approach helps in the situation where you have cache on each server. You wouldn’t want to change on one and not the others.

    Of course with session affinity and central cache this point is moot, but that’s a whole other topic.

  • http://homedesign5.com virgi

    Great post!
    i like cakePHP Framework :D
    very fast if using a cache..

  • http://www.kadnad.com ลงประกาศฟรี

    Fantastic! how can I do with cakePHP 2.x

    • teknoid_cakephp

      pretty much the same, look for those methods in the manual to see if there’s any significant difference.

  • Pingback: the echothis blog - Controlling element caching in CakePHP 2.3()

  • http://www.facebook.com/yogeshsaroya Yogesh Saroya

    Great post , thanks

    Technology News

  • Raj

    doesnt work,Why?