Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cache Me If You Can: HTTP-Caching and ESI with Symfony

Cache Me If You Can: HTTP-Caching and ESI with Symfony

We all know we should be caching to reduce our application's workload and make it run more efficiently. The HTTP protocol lets us solve this problem quite elegantly, but doing it properly isn't exactly a walk in the park. How do you prevent stale caches? Which HTTP headers should you be using? And what on earth is ESI? This talk will focus on the caching mechanisms HTTP offers us as Symfony developers, and how we can utilize them for maximum benefit.

3dd28ad260d202a12c2e93fc28fad5d7?s=128

Marco Petersen

February 27, 2019
Tweet

Transcript

  1. None
  2. WHAT WE'LL COVER ✅ HTTP Caching Basics ✅ Expiration And

    Validation ✅ Caching With Symfony ✅ Edge side includes
  3. OUT OF SCOPE ❌ Varnish, Squid etc. ❌ Application Caching

    ❌ Specific Techniques (eg Russian Doll Caching)
  4. WHO DIS? ! Marco Petersen " Software Developer @ SensioLabs

    # @ocrampete16
  5. ONCE UPON A CACHE

  6. HOW TO MAKE A WEB APPLICATION FASTER > Optimize database

    queries > Use more efficient algorithms > Rewrite Your Backend in a faster language > . . .
  7. None
  8. SYMFONY — HTTP* * the HTTP/1.1 specification (RFC2616)

  9. TYPES OF CACHES > Browser Caches > Chrome, Firefox >

    Proxy Caches > Squid > Gateway Caches > Varnish, Nginx, Squid, Cloudflare
  10. Without Caching

  11. Browser Caches cache the sites you surf

  12. Proxy Caches cache incoming traffic

  13. Gateway Caches cache outgoing traffic

  14. LET'S GET CACHING

  15. CACHING MODELS > Expiration > Expires > Cache-Control > Validation

    > ETag / If-None-Match > Last-Modified / If-Modified-Since
  16. EXPIRATION

  17. THE GAME PLAN 1. Client requests a resource and receives

    a response. 2. Cache intercepts and stores resouce with expiration date. 3. Client requests same resource. 4. Cached resource is returned if it is still fresh. > The server is not hit.
  18. EXPIRES SPECIFIES A SPECIFIC DATE AND TIME AFTER WHICH THE

    RESOURCE BECOMES STALE.
  19. /** * @Cache(expires="+600 seconds") */ public function bar() { return

    $response; } // or public function foo() { $response->setExpires(new \DateTime('+600 seconds')); return $response; }
  20. HTTP/1.1 200 OK Expires: Wed, 21 Oct 2015 07:28:00 GMT

    Lorem ipsum dolor sit amet
  21. CACHE-CONTROL THE MULTI-TALENT! > defines several caching directives > for

    now, we're only interested in max-age and s-maxage
  22. MAX-AGE AND S-MAXAGE ARE LIKE EXPIRES, BUT THEY SPECIFY THE

    NUMBER OF SECONDS UNTIL A RESOURCE BECOMES STALE
  23. /** * @Cache(smaxage=600) */ public function bar() { return $response;

    } // or public function foo() { $response->setSharedMaxAge(600); return $response; }
  24. HTTP/1.1 200 OK Cache-Control: s-maxage=600 Lorem ipsum dolor sit amet

  25. MAX-AGE AND S-MAXAGE > Browser caches only look for max-age.

    > Shared caches look for s-maxage if it exists, otherwise it follows max-age.
  26. VALIDATION

  27. THE GAME PLAN 1. Client requests a resource. 2. Server

    returns a response with validation information. 3. Client requests same resource with the validation information. 4. 304 (Not Modified) is returned if the resource is still valid. > The server is hit, but the response is much smaller.
  28. ETAG?

  29. AN ETAG IS A STRING THAT REPRESENTS A SPECIFIC VERSION

    OF A RESOURCE.
  30. /** * @Cache(Etag="post.getId() ~ post.getUpdatedAt().getTimestamp()") */ public function bar(Post $post)

    { return $response; } // or public function foo(Request $request) { $reponse = new Response(); // Compute the ETag $response->setEtag($etag) if ($response->isNotModified($request)) { return $response; } return $this->render('foo.html.twig', [], $response); }
  31. // server responds HTTP/1.1 200 OK ETag: "qwerasdfyxcv" Lorem ipsum

    dolor sit amet // client requests same resource again GET /foo HTTP/1.1 If-None-Match: "qwerasdfyxcv" // server responds HTTP/1.1 304 NOT MODIFIED
  32. LAST-MODIFIED SPECIFIES WHEN A RESOURCE WAS LAST MODIFIED

  33. /** * @Cache(lastModified="post.getUpdatedAt()") */ public function bar(Post $post) { return

    $response; } // or public function foo(Request $request, Post $post) { $reponse = new Response(); $response->setLastModified($post->getUpdatedAt()) if ($response->isNotModified($request)) { return $response; } return $this->render('foo.html.twig', [], $response); }
  34. // server responds HTTP/1.1 200 OK Last-Modified: Wed, 21 Oct

    2015 07:28:00 GMT Lorem ipsum dolor sit amet // client requests same resource again GET /foo HTTP/1.1 If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT // server responds HTTP/1.1 304 NOT MODIFIED
  35. CAN'T DECIDE WHICH MODEL TO PICK?

  36. None
  37. BOTH WORK WELL TOGETHER, ALTHOUGH EXPIRATION TRUMPS VALIDATION. // max_age

    > etag $response->setCache([ 'max_age' => 20, 'etag' => $etag, ]);
  38. NEED A GATEWAY CACHE FOR DEVELOPMENT? NO PROBLEM!

  39. // public/index.php use App\Kernel; use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; // ... $kernel =

    new Kernel($env, $debug); if ('prod' === $env) { $kernel = new HttpCache($kernel); }
  40. // public/index.php use App\Kernel; use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; // ... $kernel =

    new Kernel($env, $debug); if ('prod' === $env) { $kernel = new HttpCache($kernel); }
  41. // src/CacheKernel.php namespace App; use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; final class CacheKernel extends

    HttpCache { protected function getOptions(): array { return [ 'default_ttl' => 0, ]; } }
  42. // src/CacheKernel.php namespace App; use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; final class CacheKernel extends

    HttpCache { protected function getOptions(): array { return [ 'default_ttl' => 0, ]; } }
  43. DEMO TIME

  44. RECAP

  45. RECAP > Expiration asks "When does it become stale?" >

    Expires specifies a future point in time > Cache-Control is like Expires, but relative > Validation asks "Is it still fresh?" > Etag specifies an identifier to compare > Last-Modified specifies a point in time in the past > All work well with Symfony!
  46. EDGE SIDE INCLUDES

  47. DEMO TIME

  48. None
  49. FINAL RECAP

  50. FINAL RECAP > Cache to bypass your application. > Expiration

    - "When does this expire?" > Validation - "Is this still valid?" > ESI caches fragments of pages separately.
  51. WHERE TO GO FROM HERE > Set up your own

    gateway cache > Read the HTTP/1.1 spec (RFC-2616) > Check out HTTP/2's new features (RFC-7540) > Server Push > Multiplexing
  52. $kernel->terminate($request, $response);

  53. None