From d4d2236ab63037d03f83705f03b8af1b41a2466d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 11 Dec 2014 15:17:40 +0100 Subject: [PATCH 1/4] clean up cache invalidation information on the cache chapter --- book/http_cache.rst | 64 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/book/http_cache.rst b/book/http_cache.rst index 46e80ed4e73..048d1b96e75 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -328,6 +328,13 @@ its creation more manageable:: // set a custom Cache-Control directive $response->headers->addCacheControlDirective('must-revalidate', true); +.. tip:: + + If you need to set cache headers for many different controller actions, + you might want to look into the FOSHttpCacheBundle_. It provides a way + to define cache headers based on the URL pattern and other request + properties. + Public vs private Responses ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1051,21 +1058,35 @@ Cache Invalidation "There are only two hard things in Computer Science: cache invalidation and naming things." -- Phil Karlton -You should never need to invalidate cached data because invalidation is already -taken into account natively in the HTTP cache models. If you use validation, -you never need to invalidate anything by definition; and if you use expiration -and need to invalidate a resource, it means that you set the expires date -too far away in the future. +Once an URL is cached by a caching reverse proxy, the proxy will not ask the +application for that content anymore. This allows the cache to do fast +responses and reduces the load on your application. However, you risk +delivering outdated content. A way out of this dilemma is to use long +cache lifetimes, but to actively notify the caching proxy when content +changes. Reverse proxies usually provide a channel to receive such +notifications, usually through special HTTP requests. -.. note:: +.. tip:: + + While cache invalidation sounds powerful, avoid it when possible. If you + fail to invalidate something, outdated caches will stay for a potentially + long time. Instead, use short cache lifetimes or use the validation model, + and adjust your controllers to perform efficient validation checks as + explained in :ref:`optimizing-cache-validation`. - Since invalidation is a topic specific to each type of reverse proxy, - if you don't worry about invalidation, you can switch between reverse - proxies without changing anything in your application code. + Furthermore, since invalidation is a topic specific to each type of reverse + proxy, using this concept will tie you to a specific reverse proxy or need + additional efforts to support different proxies. -Actually, all reverse proxies provide ways to purge cached data, but you -should avoid them as much as possible. The most standard way is to purge the -cache for a given URL by requesting it with the special ``PURGE`` HTTP method. +Sometimes, however, you need that extra performance you can get when +explicitly invalidating. For invalidation, your application needs to detect +when content changes and tell the cache to remove the URLs which contain +that data from its cache. + +If one content corresponds to one URL, the ``PURGE`` model works well. +You send a request to the cache proxy with the HTTP method ``PURGE`` instead +of ``GET`` and make the cache proxy detect this and remove the data from the +cache instead of going to Symfony to get a response. Here is how you can configure the Symfony reverse proxy to support the ``PURGE`` HTTP method:: @@ -1085,11 +1106,15 @@ Here is how you can configure the Symfony reverse proxy to support the return parent::invalidate($request, $catch); } + if ('127.0.0.1' !== $request->getClientIp()) { + return new Response('Invalid HTTP method', Response::HTTP_BAD_REQUEST); + } + $response = new Response(); if ($this->getStore()->purge($request->getUri())) { $response->setStatusCode(200, 'Purged'); } else { - $response->setStatusCode(404, 'Not purged'); + $response->setStatusCode(200, 'Not found'); } return $response; @@ -1101,6 +1126,18 @@ Here is how you can configure the Symfony reverse proxy to support the You must protect the ``PURGE`` HTTP method somehow to avoid random people purging your cached data. +In many applications, content is used in various URLs. More flexible concepts +exist for those cases: + +* **Banning** invalidates responses matching regular expressions on the + URL or other criteria. +* **Cache tagging** lets you add a tag for each content used in a response + so that you can invalidate all URLs containing a certain content. + +If you need such features, you should use the `FOSHttpCacheBundle`_. This +bundle documents the configuration for the caching proxy and provides +services to send invalidation requests based on URLs and Symfony routes. + Summary ------- @@ -1128,3 +1165,4 @@ Learn more from the Cookbook .. _`P6 - Caching: Browser and intermediary caches`: http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache .. _`FrameworkExtraBundle documentation`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html .. _`ESI`: http://www.w3.org/TR/esi-lang +.. _`FOSHttpCacheBundle`: http://foshttpcachebundle.readthedocs.org/ From 2bddbb17ce1d7e676d6d3be846ad63dabde8e0f9 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 25 Dec 2014 17:57:51 +0100 Subject: [PATCH 2/4] move invalidation up into expiration and validation section --- book/http_cache.rst | 193 +++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 93 deletions(-) diff --git a/book/http_cache.rst b/book/http_cache.rst index 048d1b96e75..97d9de9959f 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -335,7 +335,7 @@ its creation more manageable:: to define cache headers based on the URL pattern and other request properties. -Public vs private Responses +Public vs Private Responses ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Both gateway and proxy caches are considered "shared" caches as the cached @@ -801,7 +801,105 @@ Additionally, most cache-related HTTP headers can be set via the single )); .. index:: - single: Cache; ESI +single: Cache; Invalidation + +.. _http-cache-invalidation: + +Cache Invalidation +~~~~~~~~~~~~~~~~~~ + + "There are only two hard things in Computer Science: cache invalidation + and naming things." -- Phil Karlton + +Once an URL is cached by a gateway cache, the cache will not ask the +application for that content anymore. This allows the cache to provide fast +responses and reduces the load on your application. However, you risk +delivering outdated content. A way out of this dilemma is to use long +cache lifetimes, but to actively notify the gateway cache when content +changes. Reverse proxies usually provide a channel to receive such +notifications, typically through special HTTP requests. + +.. tip:: + + While cache invalidation is powerful, avoid it when possible. If you fail + to invalidate something, outdated caches will be served for a potentially + long time. Instead, use short cache lifetimes or use the validation model, + and adjust your controllers to perform efficient validation checks as + explained in :ref:`optimizing-cache-validation`. + + Furthermore, since invalidation is a topic specific to each type of reverse + proxy, using this concept will tie you to a specific reverse proxy or need + additional efforts to support different proxies. + +Sometimes, however, you need that extra performance you can get when +explicitly invalidating. For invalidation, your application needs to detect +when content changes and tell the cache to remove the URLs which contain +that data from its cache. + +If one content corresponds to one URL, the ``PURGE`` model works well. +You send a request to the cache proxy with the HTTP method ``PURGE`` instead +of ``GET`` and make the cache proxy detect this and remove the data from the +cache instead of going to Symfony to get a response. + +Here is how you can configure the Symfony reverse proxy to support the +``PURGE`` HTTP method:: + + // app/AppCache.php + + // ... + use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; + + class AppCache extends HttpCache + { + protected function invalidate(Request $request, $catch = false) + { + if ('PURGE' !== $request->getMethod()) { + return parent::invalidate($request, $catch); + } + + if ('127.0.0.1' !== $request->getClientIp()) { + return new Response('Invalid HTTP method', Response::HTTP_BAD_REQUEST); + } + + $response = new Response(); + if ($this->getStore()->purge($request->getUri())) { + $response->setStatusCode(200, 'Purged'); + } else { + $response->setStatusCode(200, 'Not found'); + } + + return $response; + } + } + +.. caution:: + + You must protect the ``PURGE`` HTTP method somehow to avoid random people + purging your cached data. + +**Purge** instructs the cache to drop a resource in *all its variants* +(according to the ``Vary`` header, see above). An alternative to purging is +**refreshing** a content. Refreshing means that the caching proxy is +instructed to discard its local cache and fetch the content again. This way, +the new content is already available in the cache. The drawback of refreshing +is that variants are not invalidated. + +In many applications, the same content bit is used on various pages with +different URLs. More flexible concepts exist for those cases: + +* **Banning** invalidates responses matching regular expressions on the + URL or other criteria. +* **Cache tagging** lets you add a tag for each content used in a response + so that you can invalidate all URLs containing a certain content. + +If you need such features, you should use the `FOSHttpCacheBundle`_. This +bundle documents the configuration for the caching proxy and provides +services to send invalidation requests based on URLs and Symfony routes. + +.. index:: +single: Cache; ESI single: ESI .. _edge-side-includes: @@ -1047,97 +1145,6 @@ The ``render_esi`` helper supports two other useful options: to the ESI with a value of ``continue`` indicating that, in the event of a failure, the gateway cache will simply remove the ESI tag silently. -.. index:: - single: Cache; Invalidation - -.. _http-cache-invalidation: - -Cache Invalidation ------------------- - - "There are only two hard things in Computer Science: cache invalidation - and naming things." -- Phil Karlton - -Once an URL is cached by a caching reverse proxy, the proxy will not ask the -application for that content anymore. This allows the cache to do fast -responses and reduces the load on your application. However, you risk -delivering outdated content. A way out of this dilemma is to use long -cache lifetimes, but to actively notify the caching proxy when content -changes. Reverse proxies usually provide a channel to receive such -notifications, usually through special HTTP requests. - -.. tip:: - - While cache invalidation sounds powerful, avoid it when possible. If you - fail to invalidate something, outdated caches will stay for a potentially - long time. Instead, use short cache lifetimes or use the validation model, - and adjust your controllers to perform efficient validation checks as - explained in :ref:`optimizing-cache-validation`. - - Furthermore, since invalidation is a topic specific to each type of reverse - proxy, using this concept will tie you to a specific reverse proxy or need - additional efforts to support different proxies. - -Sometimes, however, you need that extra performance you can get when -explicitly invalidating. For invalidation, your application needs to detect -when content changes and tell the cache to remove the URLs which contain -that data from its cache. - -If one content corresponds to one URL, the ``PURGE`` model works well. -You send a request to the cache proxy with the HTTP method ``PURGE`` instead -of ``GET`` and make the cache proxy detect this and remove the data from the -cache instead of going to Symfony to get a response. - -Here is how you can configure the Symfony reverse proxy to support the -``PURGE`` HTTP method:: - - // app/AppCache.php - - // ... - use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - - class AppCache extends HttpCache - { - protected function invalidate(Request $request, $catch = false) - { - if ('PURGE' !== $request->getMethod()) { - return parent::invalidate($request, $catch); - } - - if ('127.0.0.1' !== $request->getClientIp()) { - return new Response('Invalid HTTP method', Response::HTTP_BAD_REQUEST); - } - - $response = new Response(); - if ($this->getStore()->purge($request->getUri())) { - $response->setStatusCode(200, 'Purged'); - } else { - $response->setStatusCode(200, 'Not found'); - } - - return $response; - } - } - -.. caution:: - - You must protect the ``PURGE`` HTTP method somehow to avoid random people - purging your cached data. - -In many applications, content is used in various URLs. More flexible concepts -exist for those cases: - -* **Banning** invalidates responses matching regular expressions on the - URL or other criteria. -* **Cache tagging** lets you add a tag for each content used in a response - so that you can invalidate all URLs containing a certain content. - -If you need such features, you should use the `FOSHttpCacheBundle`_. This -bundle documents the configuration for the caching proxy and provides -services to send invalidation requests based on URLs and Symfony routes. - Summary ------- From 979034a10a606516495bae3cbdba26d7c6d7ca5c Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 25 Dec 2014 18:07:22 +0100 Subject: [PATCH 3/4] move fos httpcache bundle tip up to beginning of invalidation section --- book/http_cache.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/book/http_cache.rst b/book/http_cache.rst index 97d9de9959f..19da513be99 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -401,8 +401,8 @@ header when none is set by the developer by following these rules: .. _http-expiration-validation: -HTTP Expiration and Validation ------------------------------- +HTTP Expiration, Validation and Invalidation +-------------------------------------------- The HTTP specification defines two caching models: @@ -419,7 +419,9 @@ The HTTP specification defines two caching models: header) to check if the page has changed since being cached. The goal of both models is to never generate the same response twice by relying -on a cache to store and return "fresh" responses. +on a cache to store and return "fresh" responses. To achieve long caching times +but still provide updated content immediately, *cache invalidation* is +sometimes used. .. sidebar:: Reading the HTTP Specification @@ -819,7 +821,7 @@ cache lifetimes, but to actively notify the gateway cache when content changes. Reverse proxies usually provide a channel to receive such notifications, typically through special HTTP requests. -.. tip:: +.. warning:: While cache invalidation is powerful, avoid it when possible. If you fail to invalidate something, outdated caches will be served for a potentially @@ -836,6 +838,13 @@ explicitly invalidating. For invalidation, your application needs to detect when content changes and tell the cache to remove the URLs which contain that data from its cache. +.. tip:: + + If you want to use cache invalidation, have a look at the + `FOSHttpCacheBundle`_. This bundle provides services to help with various + cache invalidation concepts, and also documents the configuration for the + a couple of common caching proxies. + If one content corresponds to one URL, the ``PURGE`` model works well. You send a request to the cache proxy with the HTTP method ``PURGE`` instead of ``GET`` and make the cache proxy detect this and remove the data from the @@ -894,10 +903,6 @@ different URLs. More flexible concepts exist for those cases: * **Cache tagging** lets you add a tag for each content used in a response so that you can invalidate all URLs containing a certain content. -If you need such features, you should use the `FOSHttpCacheBundle`_. This -bundle documents the configuration for the caching proxy and provides -services to send invalidation requests based on URLs and Symfony routes. - .. index:: single: Cache; ESI single: ESI From 0accf631a5b97b95823721d262ba9eeded230418 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sat, 27 Dec 2014 09:35:26 +0100 Subject: [PATCH 4/4] cleanup cache book chapter --- book/http_cache.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/book/http_cache.rst b/book/http_cache.rst index 19da513be99..e6903692dc8 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -400,6 +400,7 @@ header when none is set by the developer by following these rules: ``private`` directive automatically (except when ``s-maxage`` is set). .. _http-expiration-validation: +.. _http-expiration-and-validation: HTTP Expiration, Validation and Invalidation -------------------------------------------- @@ -775,7 +776,7 @@ at some interval (the expiration) to verify that the content is still valid. annotations. See the `FrameworkExtraBundle documentation`_. .. index:: - pair: Cache; Configuration + pair: Cache; Configuration More Response Methods ~~~~~~~~~~~~~~~~~~~~~ @@ -803,7 +804,7 @@ Additionally, most cache-related HTTP headers can be set via the single )); .. index:: -single: Cache; Invalidation + single: Cache; Invalidation .. _http-cache-invalidation: @@ -821,7 +822,7 @@ cache lifetimes, but to actively notify the gateway cache when content changes. Reverse proxies usually provide a channel to receive such notifications, typically through special HTTP requests. -.. warning:: +.. caution:: While cache invalidation is powerful, avoid it when possible. If you fail to invalidate something, outdated caches will be served for a potentially @@ -846,7 +847,8 @@ that data from its cache. a couple of common caching proxies. If one content corresponds to one URL, the ``PURGE`` model works well. -You send a request to the cache proxy with the HTTP method ``PURGE`` instead +You send a request to the cache proxy with the HTTP method ``PURGE`` (using +the word "PURGE" is a convention, technically this can be any string) instead of ``GET`` and make the cache proxy detect this and remove the data from the cache instead of going to Symfony to get a response. @@ -899,13 +901,13 @@ In many applications, the same content bit is used on various pages with different URLs. More flexible concepts exist for those cases: * **Banning** invalidates responses matching regular expressions on the - URL or other criteria. + URL or other criteria; * **Cache tagging** lets you add a tag for each content used in a response so that you can invalidate all URLs containing a certain content. .. index:: -single: Cache; ESI - single: ESI + single: Cache; ESI + single: ESI .. _edge-side-includes: