How does magento full page cache work

  • Sharebar

Let’s decipher Magento full page cache and see how it works

We are going to try to explain how Magento full page cache works by looking at the code, it’d be cool if we’d have talked with some of the folks at Magento to get a better information but hey you should always trust xdebug over humans’ words, right?

Our approach is very simple, look at the workflow and try to translate it into words. So we are doing some reverse engineering here… take the code and explain the logic back.

Why write about Magento’s full page cache?

Two of the most requested articles I have been asked to write so far have been about magento’s full page cache and Magento’s SEO.

Today we are going to try to tackle the former and hope to get 2 things out of it:

  1. Magento’s Full Page Cache: how does it work and…
  2. How you can write your own module to handle Full Page Caching.

This article is pretty ambitious and we may need to write a follow up to crush all doubts. Don’t hesitate to use the comment section or twitter for clarification.

Understanding Magento Full page cache

Before we jump the gun into Magento’s implementation of full page caching, I think it is important that we review what full page cache (FPC) is:

FPC is a very useful technique or mechanism that allows us to copy web content by storing the output of a given URL to a temporary container (caching) to help reduce bandwidth usage, cpu load, memory comsuption, database stress, perceived lag among other benefits.

Well well that was almost poetic and awesome!!!

Now while I disagree that caching is the same as perfomance optimization I do agree that it helps tremendously when achieving high availability and good performance optimization.

Back to Magento Full Page Cache now, in order to understand it, we need to understand what the run function in Mage_Core_Model_App does and how it is architected:

    /**
     * Run application. Run process responsible for request processing and sending response.
     * List of supported parameters:
     *  scope_code - code of default scope (website/store_group/store code)
     *  scope_type - type of default scope (website/group/store)
     *  options    - configuration options
     *
     * @param  array $params application run parameters
     * @return Mage_Core_Model_App
     */
    public function run($params)
    {
        $options = isset($params['options']) ? $params['options'] : array();
        $this->baseInit($options);
        Mage::register('application_params', $params);
        if ($this->_cache->processRequest()) {
            $this->getResponse()->sendResponse();
        } else {
            $this->_initModules();
            $this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
            if ($this->_config->isLocalConfigLoaded()) {
                $scopeCode = isset($params['scope_code']) ? $params['scope_code'] : '';
                $scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store';
                $this->_initCurrentStore($scopeCode, $scopeType);
                $this->_initRequest();
                Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
            }
            $this->getFrontController()->dispatch();
        }
        return $this;
    }

The most important part in that function is:

$this->_cache->processRequest()

what that line does is that checks if you have defined a caching node like this under app/etc/cache.xml:

<config>
    <global>
        <cache>
            <request_processors>
                <lt>Performance_PageCache_Model_Processor</lt>
            </request_processors>
        </cache>
     </global>
</config>

cache.xml is just an arbitrary name I chose for this blog post (It’s not really arbitrary as you will see later).

The request processor node gets checked whenever the cache model gets instantiated:

    /**
     * Class constructor. Initialize cache instance based on options
     *
     * @param array $options
     */
    public function __construct(array $options = array())
    {
        $this->_defaultBackendOptions['cache_dir'] = Mage::getBaseDir('cache');
        /**
         * Initialize id prefix
         */
        $this->_idPrefix = isset($options['id_prefix']) ? $options['id_prefix'] : '';
        if (!$this->_idPrefix && isset($options['prefix'])) {
            $this->_idPrefix = $options['prefix'];
        }
        if (empty($this->_idPrefix)) {
            $this->_idPrefix = substr(md5(Mage::getConfig()->getOptions()->getEtcDir()), 0, 3).'_';
        }
        $backend    = $this->_getBackendOptions($options);
        $frontend   = $this->_getFrontendOptions($options);
        $this->_frontend = Zend_Cache::factory('Varien_Cache_Core', $backend['type'], $frontend, $backend['options'],
            true, true, true
        );
        if (isset($options['request_processors'])) {
            $this->_requestProcessors = $options['request_processors'];
        }
        if (isset($options['disallow_save'])) {
            $this->_disallowSave = $options['disallow_save'];
        }
    }

This piece of code:

if (isset($options['request_processors'])) {
            $this->_requestProcessors = $options['request_processors'];
        }

Is what matters most.

The next thing that magento does is to find / initialize the class you have defined and it expects that you have an extractContent function defined in your model. How you do that is totally up to you but look at Magento’s implementation and get a hint or two.

Simple right? Yea. A least so far is not rocket science.

But we are almost getting to the point where we are going to need a couple of scientists to explain some of the magic… anyways let’s continue.

Magento Full Page Cache has its own config model that loads your module’s (see no arbitrary) cache.xml file which gets initialized whenever you dispatch this event core_block_abstract_to_html_after and do you know where that event gets dispatched?

If you thought in the toHtml method in Mage_Core_Block_Abstract then you should be writing this article not me.

Anyhow, the Enterprise_PageCache_Model_Observer::renderBlockPlaceholder observes that event and initializes the Enterprise config model.

This model is the one that basically takes control of filling the holes you defined in the cache.xml which has a syntax similar to this:

  <config>
      <placeholders>
          <some_unique_name>
              <block>block_type_as_in_the_layout</block>
              <placeholder>name</placeholder>
              <container>container_model</container>
              <cache_lifetime>duration</cache_lifetime>
          </some_unique_name>
      </placeholders>
  </config>

It has a method called _initPlaceholders which iterates through all of the cache.xml nodes and finds the definition of the holes and fillers.

Pretty cool right? Still not rocket science.

So now we know how Magento finds the cache, config, events and adds the container name in the page.

However we don’t know what the containers are? Essentially they are the ones responsible for filling the holes you have defined.

Each container has two important methods applyWithoutApp and applyInApp that Vinai has explained exceptionally well here. But it will be awesome if you go take a look and be amazed because trust me YOU will need to, to fully understand it.

The function that will probably will matter most for you is:

   /**
     * Render block content from placeholder
     *
     * @return string|false
     */
    protected function _renderBlock()
    {
    }

As that is the one that will get your dynamic content (read holes).

So what have we learned? We now know how Magento uses full page caching instead of just regular caching and we also know the workflow (let’s say we do)
Also we know how to use holepunching in Magento’s implementation of Full Page Cache because we know that if we define a cache.xml in our module with the syntax above Magento will read it and do its magic.

Writing your own full page cache

So now we know how Magento Full Page Cache implementation works we can create our own, right? Of course.
However by now you should also know that I will explain how things work and give you some homework because that’s how I was taught how people will eventually learn.

Your homework is, knowing all you know now, to create your own implementation of a magento full page cache without changing templates or doing crazy things like I did here. A word of warning be weary of http cache headers because you need to decide to honor them or not.

Let’s improve our magento full page cache

Why settle to understand how magento full page cache works and clone it?
Let’s be more ambitious and make it so much better that it becomes the standard way to do it.

Let’s combine nginx and memcache with our Magento’s Full page cache implemention for an even better and faster implementation than magento’s own as it will never make it to your php stack to serve static content. Nginx now will be doing it for you. Of course this means a little bit more work on your end to define a cache and cleanup strategy as well as a time to live for the objects in cache and more importantly you need to account for other web servers.

But If you do it know that the result is response time is extremely fast, believe me it is lightning fast that way. How fast? I’d dare to compare it to Varnish not just in speed but also in handling workloads. And mine is just an experimental attempt, no even coded properly.

So this might be one of your secret weapons when making magento faster and more capable of handling higher concurrent loads.

This was so simple, why do we need rocket scientists here? Well because my English grammar is so confusing that it takes a long time to dechiper it, so while you may understand the concepts you may not understand me icon razz How does magento full page cache work

VN:F [1.9.22_1171]
Rating: 8.0/10 (14 votes cast)
VN:F [1.9.22_1171]
Rating: +4 (from 6 votes)
How does magento full page cache work, 8.0 out of 10 based on 14 ratings

Author: Luis Tineo

Husband, Father, performance improvement junkie, biker and video gamer, Linux user and in my day job I'm a Systems Architect at Blue Acorn.

Share This Post On
  • Drew

    Luis you’re really pushing the envelope in the quality of Magento content available these days. Keep it up! Great posts lately.

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • nevvermind

    Relax with the English grammar. It’s fine.
    And yes, like Drew said, you really like to push things. Your blog reminds of askapache, another great one. Thanks.

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • Luis Tineo

    Thanks Drew and nevvermind, really appreciate it. I will put the English grammar issue to rest. By the way any topics in particular you will like to see – btw nevvermind I didn’t even know of askapache and after looking at it I can see the resemblance :-) thanks for sharing that

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • OSdave

    very interesting post, now I have some homework to do this week-end :)

    thanx for this, looking forward to read your next piece

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • http://www.kingletas.com Luis Tineo

      hehe I am glad I could help :-D

      VN:F [1.9.22_1171]
      Rating: 0.0/5 (0 votes cast)
      VN:F [1.9.22_1171]
      Rating: 0 (from 0 votes)
  • http://www.mindinventory.com/hire-magento-developers.php hire magento developer

    The next factor that magento does is to discover / initialize the category you have described and it desires that you have an extractContent operate described in your design.

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • http://www.magentodevelopments.com/magento-development.php magento development

    So we now need to have a storage space place area place area storage space place area place storage space place area storage space place storage space cache.xml pc computer information file which shows us which stops on the website needs to have unique activities design than other stops on the website. For example the latest buy prevent in my dash would need to upgrade each time the deal is placed.

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • Parvej Vohra

    Thanks to share
    such interesting post with the other readers as they will get clear out their
    doubts from this.for more knowledge-
    https://www.facebook.com/hiremagentodeveloper

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • Tim

    Actually there were a word from Magento guys explaining the subject. Here is the video http://www.youtube.com/watch?v=Eimm7v7vWiw and here are the slides http://www.developers-paradise.com/wp-content/uploads/NRG_-MDP_Presentation_Max_Gubar_Ibiza_2012.pdf

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • Julia

    We implemented AJAX hole-punching system for dynamic content into our extension Adavnced Cache Optimizer, which can be found on our website magepro.org

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • http://itharagroup.com/ LillyBracey

    Thanks to
    share such interesting post with the other readers as they will get clear out
    their doubts from this.for more knowledge-

    Jogging track

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
  • Richard Maurice

    This is a great article, thank you very much.

    is there any way to hole-punch the product prices?

    We have Magento Enterprise and we implemented a geolocation script that detects the country of the shoppers and preselect the currency of the shopper based on the country detected.

    But it seems that the first time Magento loads the pre-selected currency based on the IP of the shopper doesn’t work, it starts working as soon as the shopper start browsing in the other links of the store. It just doesn’t work the first time the page loads.

    Thanks,

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)