Successfully reported this slideshow.
Your SlideShare is downloading. ×

Taking Laravel to the edge with HTTP caching and Varnish

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad

Check these out next

1 of 98 Ad

Taking Laravel to the edge with HTTP caching and Varnish

Slides for my Laracon EU 2022 presentation in Amsterdam about caching Laravel applications with Varnish.

See https://feryn.eu/speaking/taking-laravel-edge-leverage-http-caching-varnish-maximum-scalability/ for more information.

Slides for my Laracon EU 2022 presentation in Amsterdam about caching Laravel applications with Varnish.

See https://feryn.eu/speaking/taking-laravel-edge-leverage-http-caching-varnish-maximum-scalability/ for more information.

Advertisement
Advertisement

More Related Content

Similar to Taking Laravel to the edge with HTTP caching and Varnish (20)

Advertisement

Recently uploaded (20)

Taking Laravel to the edge with HTTP caching and Varnish

  1. 1. TAKING LARAVEL TO THE EDGE WITH HTTP CACHING & VARNISH By Thijs Feryn
  2. 2. Slow websites SUCK
  3. 3. WEB PERFORMANCE IS AN ESSENTIAL PART OF THE USER EXPERIENCE
  4. 4. SLOW~DOWN
  5. 5. THROWING SERVERS ATTHEPROBLEM
  6. 6. MO' MONEY MO' SERVERS MO' PROBLEMS
  7. 7. IDENTIFY SLOWEST PARTS
  8. 8. OPTIMIZE
  9. 9. AFTER A WHILE YOU HIT THE LIMITS
  10. 10. CACHE
  11. 11. HI, I'M THIJS
  12. 12. I'M THE TECH EVANGELIST AT
  13. 13. 9,000,000 WEBSITES 21% OF THE TOP 10K WEBSITES
  14. 14. I'M @THIJSFERYN
  15. 15. USER SERVER
  16. 16. REVERSE CACHING PROXY
  17. 17. USER PROXY SERVER
  18. 18. USER PROXY SERVER THE EDGE
  19. 19. USER VARNISH SERVER THE EDGE
  20. 20. BUILT FOR PERFORMANCE
  21. 21. THE POWER OF http://
  22. 22. Cache-Control: public, max-age=3600
  23. 23. Cache-Control: public, max-age=3600, s-maxage=86400
  24. 24. Cache-Control: private, no-cache, no-store
  25. 25. Cache-Control: public, max-age=3600, stale-while-revalidate=300
  26. 26. ORIGIN VARNISH GRACE SERVE STALE OBJECT BACKGROUND FETCH
  27. 27. Vary: Accept-Encoding, Accept-Language, X-Forwarded-Proto
  28. 28. FOR YOUR EYES ONLY NOT CACHED
  29. 29. VARNISH CONFIGURATION LANGUAGE
  30. 30. VCL CAPABILITIES ✓ REQUEST HANDLING ✓ REQUEST ROUTING ✓ RESPONSE MANIPULATION ✓ BACKEND SELECTION ✓ CONTROLLING THE CACHE ✓ DECISION-MAKING "ON THE EDGE"
  31. 31. vcl 4.1; backend default { .host = "127.0.0.1"; .port = "8080"; } sub vcl_recv { if(req.url ~ "^/admin(/.*|$)") { return(pass); } unset req.http.Cookie; }
  32. 32. I ANSWER TO #VARNISH ON STACKOVERFLOW
  33. 33. THIJS@VARNISH-SOFTWARE.COM
  34. 34. Route::middleware('cache.headers:public;max_age=3600;etag') ->group(function () { Route::get('/', function () { return view('welcome'); }); });
  35. 35. HTTP/1.1 200 OK Host: localhost:8000 Date: Mon, 25 Apr 2022 15:44:58 GMT Connection: close Content-Type: text/html; charset=UTF-8 Cache-Control: no-cache, private Date: Mon, 25 Apr 2022 15:44:58 GMT Set-Cookie: XSRF- TOKEN=eyJpdiI6IjRvRndmL2pHcnFQamZBYnBxSFgyQWc9PSIsInZhbHVlIjoiM200RUU0N0h Lc3YzN3Jaa21MQVdzaENDSEg4cEU4bG1TWk5pWlgwMjZyTko0cjVmUC9kYjhGVmtYem8xanBu ZlFwT1ZJT3grR0RwWURoMGppTnh2K09kOGtHQmc4V3JYUmZrVyt2OERIdGNkZXloNHYzZWNDd GJ3MGZRWk1oMkwiLCJtYWMiOiIxOTZlMTAwNTY2MTM5NmY2Zjg1OGIwNTQxNjUzZDlhZjQ2ZG JlZDQzZjRjZTQ2MjBkNzQxYzc2MTc2NzJmY2QwIiwidGFnIjoiIn0%3D; expires=Mon, 25-Apr-2022 17:44:58 GMT; Max-Age=7200; path=/; samesite=lax Set-Cookie: laravel_session=eyJpdiI6Im1PcExWeWZkVkpDTFZpajR2TUtheWc9PSIsInZhbHVlIjoid EpTRGpldjJYREFYOTBvaHI0RDlOeTI0NHM0bGh5cVE3QmlqMjBBZ3p1QWZRdC92ek9OUThaaU tDQndjSi9adnBtQTRaWlpUVk9EQk80Z2drUjREQmJJdDBicGZ0bjNiTlNxckd4Mm5zNWpkM1B mcTMzREtzMUsrMVBZeUdXd0kiLCJtYWMiOiIyNDY0NmU5ZTMzNTAxODM2Y2E4YzNhMDRhMWU4 NjBkMzRiYzg4MDc4MjQ1MDk3NDczZDI5ZjVlNzc3MzcxOWU3IiwidGFnIjoiIn0%3D; expires=Mon, 25-Apr-2022 17:44:58 GMT; Max-Age=7200; path=/; httponly; samesite=lax
  36. 36. Route::withoutMiddleware([StartSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class]) ->group(function () { Route::middleware('cache.headers:public;max_age=3600;etag') ->group(function () { Route::get('/', function () { return view('welcome'); }); }); });
  37. 37. Route::withoutMiddleware([StartSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class]) ->group(function () { Route::middleware('cache.headers:public;max_age=3600;etag') ->group(function () { Route::get('/', function () { return view('welcome'); }); }); });
  38. 38. HTTP/1.1 200 OK Host: 127.0.0.1:8000 Date: Mon, 25 Apr 2022 15:34:44 GMT Connection: close Content-Type: text/html; charset=UTF-8 Cache-Control: max-age=3600, public Date: Mon, 25 Apr 2022 15:34:44 GMT ETag: "13b73edae8443990be1aa8f1a483bc27"
  39. 39. ONLY FETCH PAYLOAD THAT HAS CHANGED
  40. 40. HTTP/1.1 200 OK
  41. 41. OTHERWISE: HTTP/1.1 304 Not Modified
  42. 42. VARNISH SUPPORTS CONDITIONAL REQUESTS FOR CLIENTS & BACKENDS
  43. 43. GET / HTTP/1.1 Host: 127.0.0.1:8000 If-None-Match: "13b73edae8443990be1aa8f1a483bc27" HTTP/1.1 304 Not Modified Host: 127.0.0.1:8000 Date: Mon, 25 Apr 2022 15:34:44 GMT Connection: close Content-Type: text/html; charset=UTF-8 Cache-Control: max-age=3600, public Date: Mon, 25 Apr 2022 15:34:44 GMT ETag: "13b73edae8443990be1aa8f1a483bc27"
  44. 44. QUICKLY
  45. 45. EARLY
  46. 46. <?php namespace AppHttpMiddleware; use IlluminateHttpRequest; use IlluminateSupportFacadesCache; use Closure; use SymfonyComponentHttpFoundationResponse; class NotModified { public function handle(Request $request, Closure $next) { if (!$request->isMethodCacheable()) { return $next($request); } $etag = Cache::get('etag:'.md5($request->getUri())); $cacheControl = Cache::get('etag-cache-control:'.md5( $request->getUri())); $response = new Response('',304, ['ETag' => $etag, 'Cache-Control' => $cacheControl]); if($response->isNotModified(($request))) { return $response; }
  47. 47. $response = $next($request); Cache::put('etag:'.md5($request->getUri()), $response->headers->get('ETag'),10); Cache::put('etag-cache-control:'.md5($request->getUri()), $response->headers->get('Cache-Control'),10); return $response; } }
  48. 48. NO CACHE
  49. 49. PLACEHOLDERS
  50. 50. SEPARATE HTTP REQUEST
  51. 51. AJAX
  52. 52. EDGE-SIDE INCLUDES ESI
  53. 53. <esi:include src="/header" />
  54. 54. ESI ✓ PLACEHOLDER ✓ PARSED BY VARNISH ✓ OUTPUT IS A COMPOSITION OF BLOCKS ✓ STATE PER BLOCK ✓ TTL PER BLOCK
  55. 55. VARNISH Surrogate-Capability: key="ESI/1.0" Surrogate-Control: content="ESI/1.0" <esi:include src="/header" /> LARAVEL Parse ESI placeholders VARNISH
  56. 56. sub vcl_recv { set req.http.Surrogate-Capability = "key=ESI/1.0"; } sub vcl_backend_response { if (beresp.http.Surrogate-Control ~ "ESI/1.0") { unset beresp.http.Surrogate-Control; set beresp.do_esi = true; } }
  57. 57. COMPOSITION AT THE VIEW LAYER
  58. 58. Route::middleware('cache.headers:public;max_age=3600;etag')->group(function () { Route::get('/', function () { return view('welcome'); }); }); Route::middleware('cache.headers:private')->group(function () { Route::get('/header', function () { return view("header"); }); });
  59. 59. Route::middleware('cache.headers:public;max_age=3600;etag')->group(function () { Route::get('/', function () { return view('welcome'); }); }); Route::middleware('cache.headers:private')->group(function () { Route::get('/header', function () { return view("header"); }); });
  60. 60. <!DOCTYPE html> <html> <body> @esi(/header) <p>Welcome</p> </body> </html>
  61. 61. <!DOCTYPE html> <html> <body> <esi:include src="/header" /> <p>Welcome</p> </body> </html>
  62. 62. <!DOCTYPE html> <html> <body> <p>The current time is 21:07:53.</p> <p>Welcome</p> </body> </html>
  63. 63. composer require myerscode/laravel-sub-request
  64. 64. <?php namespace AppProviders; use IlluminateSupportServiceProvider; use IlluminateSupportFacadesBlade; class EsiServiceProvider extends ServiceProvider { public function boot(): void { Blade::directive('esi', function (string $url) { if(str_contains($this->app->request->headers->get('Surrogate-Capability'), 'ESI/1.0')) { return "<?php echo '<esi:include src="$url" />'; ?>"; } else { return "<?php echo subrequest('GET','$url')->getContent(); ?>"; } }); } }
  65. 65. @esi(/header)
  66. 66. @esi(/header) @esi(/nav) <p>Main content</p> @esi(/footer)
  67. 67. <?php namespace AppHttpMiddleware; use IlluminateHttpRequest; use Closure; class Surrogate { public function handle(Request $request, Closure $next) { $response = $next($request); if(str_contains($request->headers->get('Surrogate-Capability'), 'ESI/1.0')) { $response->headers->set('Surrogate-Control', 'content="ESI/1.0"'); } return $response; } }
  68. 68. HOW DO YOU IDENTIFY AN OBJECT IN CACHE?
  69. 69. sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } return (lookup); }
  70. 70. sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } return (lookup); }
  71. 71. <p>{{ __('Welcome') }}</p>
  72. 72. <?php return [ 'locale' => 'en', 'fallback_locale' => 'en' ];
  73. 73. composer require orkhanahmadov/laravel-accept-language-middleware
  74. 74. HTTP/1.1 200 OK Host: localhost Content-Language: en GET / HTTP/1.1 Host: localhost Accept-Language: en HTTP/1.1 200 OK Host: localhost Content-Language: en GET / HTTP/1.1 Host: localhost Accept-Language: nl
  75. 75. Vary: Accept-Language
  76. 76. HTTP/1.1 200 OK Host: localhost Content-Language: en GET / HTTP/1.1 Host: localhost Accept-Language: en HTTP/1.1 200 OK Host: localhost Content-Language: nl GET / HTTP/1.1 Host: localhost Accept-Language: nl
  77. 77. <?php namespace AppHttpMiddleware; use IlluminateHttpRequest; use Closure; class Vary { public function handle(Request $request, Closure $next) { $response = $next($request); $response->headers->set('Vary','Accept-Language'); return $response; } }
  78. 78. YOU CAN DO ALL OF THIS IN VCL TOO
  79. 79. sub vcl_recv { set req.http.Surrogate-Capability = "key=ESI/1.0"; } sub vcl_backend_response { set beresp.ttl = 1h; set beresp.grace = 2h; set beresp.http.Vary = "Accept-Language, Accept-Encoding, X-Forwarded-Proto"; if (beresp.http.Surrogate-Control ~ "ESI/1.0") { unset beresp.http.Surrogate-Control; set beresp.do_esi = true; } }
  80. 80. THIS IS JUST THE TIP OF THE ICEBERG
  81. 81. HTTPS://VARNISH-SOFTWARE.COM/DEVELOPERS
  82. 82. HTTPS://WWW.VARNISH-SOFTWARE.COM/ PRODUCTS/VARNISH-CLOUD/

×