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.

Marco Petersen

February 27, 2019
Tweet

More Decks by Marco Petersen

Other Decks in Programming

Transcript

  1. WHAT WE'LL COVER

    HTTP Caching Basics

    Expiration And Validation

    Caching With Symfony

    Edge side includes

    View full-size slide

  2. OUT OF SCOPE

    Varnish, Squid etc.

    Application Caching

    Specific Techniques (eg Russian Doll Caching)

    View full-size slide

  3. WHO DIS?
    !
    Marco Petersen
    "
    Software Developer @ SensioLabs
    #
    @ocrampete16

    View full-size slide

  4. ONCE UPON
    A CACHE

    View full-size slide

  5. HOW TO MAKE A WEB APPLICATION FASTER
    > Optimize database queries
    > Use more efficient algorithms
    > Rewrite Your Backend in a faster language
    > . . .

    View full-size slide

  6. SYMFONY — HTTP*
    * the HTTP/1.1 specification (RFC2616)

    View full-size slide

  7. TYPES OF CACHES
    > Browser Caches
    > Chrome, Firefox
    > Proxy Caches
    > Squid
    > Gateway Caches
    > Varnish, Nginx, Squid, Cloudflare

    View full-size slide

  8. Without Caching

    View full-size slide

  9. Browser Caches cache the sites you surf

    View full-size slide

  10. Proxy Caches cache incoming traffic

    View full-size slide

  11. Gateway Caches cache outgoing traffic

    View full-size slide

  12. LET'S GET
    CACHING

    View full-size slide

  13. CACHING MODELS
    > Expiration
    > Expires
    > Cache-Control
    > Validation
    > ETag / If-None-Match
    > Last-Modified / If-Modified-Since

    View full-size slide

  14. 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.

    View full-size slide

  15. EXPIRES SPECIFIES A
    SPECIFIC DATE AND TIME
    AFTER WHICH THE
    RESOURCE BECOMES
    STALE.

    View full-size slide

  16. /**
    * @Cache(expires="+600 seconds")
    */
    public function bar() {
    return $response;
    }
    // or
    public function foo() {
    $response->setExpires(new \DateTime('+600 seconds'));
    return $response;
    }

    View full-size slide

  17. HTTP/1.1 200 OK
    Expires: Wed, 21 Oct 2015 07:28:00 GMT
    Lorem ipsum dolor sit amet

    View full-size slide

  18. CACHE-CONTROL THE MULTI-TALENT!
    > defines several caching directives
    > for now, we're only interested in max-age and s-maxage

    View full-size slide

  19. MAX-AGE AND S-MAXAGE ARE
    LIKE EXPIRES, BUT THEY SPECIFY
    THE NUMBER OF SECONDS UNTIL
    A RESOURCE BECOMES STALE

    View full-size slide

  20. /**
    * @Cache(smaxage=600)
    */
    public function bar() {
    return $response;
    }
    // or
    public function foo() {
    $response->setSharedMaxAge(600);
    return $response;
    }

    View full-size slide

  21. HTTP/1.1 200 OK
    Cache-Control: s-maxage=600
    Lorem ipsum dolor sit amet

    View full-size slide

  22. 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.

    View full-size slide

  23. 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.

    View full-size slide

  24. AN ETAG IS A STRING THAT
    REPRESENTS A SPECIFIC
    VERSION OF A RESOURCE.

    View full-size slide

  25. /**
    * @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);
    }

    View full-size slide

  26. // 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

    View full-size slide

  27. LAST-MODIFIED SPECIFIES WHEN
    A RESOURCE WAS LAST MODIFIED

    View full-size slide

  28. /**
    * @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);
    }

    View full-size slide

  29. // 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

    View full-size slide

  30. CAN'T DECIDE WHICH
    MODEL TO PICK?

    View full-size slide

  31. BOTH WORK WELL TOGETHER, ALTHOUGH
    EXPIRATION TRUMPS VALIDATION.
    // max_age > etag
    $response->setCache([
    'max_age' => 20,
    'etag' => $etag,
    ]);

    View full-size slide

  32. NEED A GATEWAY CACHE FOR DEVELOPMENT?
    NO PROBLEM!

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  37. 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!

    View full-size slide

  38. EDGE SIDE
    INCLUDES

    View full-size slide

  39. FINAL RECAP
    > Cache to bypass your application.
    > Expiration - "When does this expire?"
    > Validation - "Is this still valid?"
    > ESI caches fragments of pages separately.

    View full-size slide

  40. 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

    View full-size slide

  41. $kernel->terminate($request, $response);

    View full-size slide