Going crazy with Varnish and Symfony

Post on 05-Aug-2015

61 views 0 download

Transcript of Going crazy with Varnish and Symfony

Going crazy with Symfony and Varnish

David de Boer15 May 2015

Varnish

Public content

Most requested

Most processing

Static assets

Authenticated content?

$ varnishtop -i BeReqUrl

Leiden

Driebit, Amsterdam

FOSHttpCache FOSHttpCacheBundle

Break up

only one TTL

don’t cache

15 mins

1 hour

24 hours

Enable ESI sub vcl_recv { set req.http.Surrogate-Capability = "abc=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; }}

Plain PHP<?phpheader('Surrogate-Control: ESI/1.0');?><html><body> <esi:include src="/blue.php" /> Your main content. <esi:include src="/red.php" /></body></html>

<?php// blue.phpheader('Cache-Control: no-cache');?>Blue is not cached.

<?php// red.phpheader('Cache-Control: s-maxage=3600');?>Red is cached for an hour.

ESI in Symfony# app/config/config.yml

framework: esi: enabled: true fragments: { path: /_fragment }

{# template.twig #}

{{ render_esi(controller('AppBundle:Red:list', {'max': 100})) }}

ESI performance<?php// blue.php

sleep(2);header('Cache-Control: no-cache');?>

Blue is kind of sleepy.

<?php// red.php

sleep(5);header('Cache-Control: no-cache');?>

And red even more so.

7 seconds

Client-side

Rich JavaScript apps

JSON data through Ajax

API design

ESI in JSONvarnishd -p esi_syntax=0x00000003

{ "id": 1, "name": "Martian Ambassador", "_embedded": { "category": <esi:include src="/categories/1"/> }}

Invalidation<?php

use FOS\HttpCache\ProxyClient\Varnish;use FOS\HttpCache\CacheInvalidator;

$varnishClient = new Varnish('127.0.0.1', 'http://mars-attacks.dev');$cacheInvalidator = new CacheInvalidator($varnishClient);

// If some data changes in your app:$cacheInvalidator->invalidatePath('/red.php')->flush();

Invalidation# app/config/config.ymlfos_http_cache: proxy_client: varnish: servers: 127.0.0.1 base_url: mars-attacks.dev

<?php

use FOS\HttpCacheBundle\Configuration\InvalidateRoute;

/** * @InvalidateRoute("red")*/public function editAction($id){ // This is where data changes}

Individual caching?// builtin.vcl

sub vcl_recv { // ... if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); } // ...}

Individual caching?sub vcl_recv { // ... if (req.http.Authorization || req.http.Cookie) { /* Cache all the personal things! */ return (hash); } // ...}

Individual caching?sub vcl_recv { // ... if (req.http.Authorization || req.http.Cookie) { /* Cache all the personal things! */ return (hash); } // ...}

sub vcl_deliver { // ... set resp.http.Vary = "Cookie,Authorization"; }

Group together

User context

Varnish

hash lookup

vary on credentials#

content request

vary on hash header

#

App ⟳

Varnish

User contexthash lookup

vary on credentials#

content request

vary on hash header

#

Varnish

User context

##

#

##

#

# ##

##

#

#

##

#

#

#

#

#

#

##

#

#

##

# # #

Configure user contextsub vcl_recv { if (req.restarts == 0 && (req.http.cookie || req.http.authorization) && (req.method == "GET" || req.method == "HEAD") ) { if (req.http.accept) { set req.http.X-Fos-Original-Accept = req.http.accept; } set req.http.accept = "application/vnd.fos.user-context-hash"; set req.http.X-Fos-Original-Url = req.url; set req.url = "/_fos_user_context_hash";

return (hash); }

if (req.restarts > 0 && req.http.accept == "application/vnd.fos.user-context-hash" ) { set req.url = req.http.X-Fos-Original-Url; unset req.http.X-Fos-Original-Url; if (req.http.X-Fos-Original-Accept) { set req.http.accept = req.http.X-Fos-Original-Accept; unset req.http.X-Fos-Original-Accept; } else { unset req.http.accept; }

return (hash); }}

Configure user contextsub vcl_backend_response { if (bereq.http.accept ~ "application/vnd.fos.user-context-hash" && beresp.status >= 500 ) { return (abandon); }}

sub vcl_deliver { if (req.restarts == 0 && resp.http.content-type ~ "application/vnd.fos.user-context-hash" ) { set req.http.X-User-Context-Hash = resp.http.X-User-Context-Hash;

return (restart); }

set resp.http.Vary = regsub(resp.http.Vary, "(?i),? *X-User-Context-Hash *", ""); set resp.http.Vary = regsub(resp.http.Vary, "^, *", ""); if (resp.http.Vary == "") { unset resp.http.Vary; }

unset resp.http.X-User-Context-Hash;}

Cleaning cookies$ varnishlog -c -i ReqHeader -I CookieCookie: __uvt=;PHPSESSID=ht8rl2tnbikpeoau7q5g677125;_ga=GA1.2.1332615739.14⏎

31368832;uvts=320PnWhzN5bW7V2D

sub vcl_recv { set req.http.cookie = ";" + req.http.cookie; set req.http.cookie = regsuball(req.http.cookie, "; +", ";"); set req.http.cookie = regsuball(req.http.cookie, ";(PHPSESSID)=", "; \1="); set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", ""); set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", "");}

Cookie: PHPSESSID=ht8rl2tnbikpeoau7q5g677125

FOSHttpCacheBundle# app/config/config.yml fos_http_cache: user_context: hash_cache_ttl: 3600 hash_header: "Custom-User-Hash-Header" role_provider: true

Custom provider<?php

use FOS\HttpCache\UserContext\ContextProviderInterface;use FOS\HttpCache\UserContext\UserContext;

class IsAwesomeProvider implements ContextProviderInterface{ private $userService;

public function __construct(YourUserService $userService) { $this->userService = $userService; }

public function updateUserContext(UserContext $userContext) { $userContext->addParameter('awesome', $this->userService->isAwesome()); }}

// <service id="app_bundle.provider" class="AppBundle\Provider\IsAwesomeProvider"> <tag name="fos_http_cache.user_context_provider" /></service>

Thanks!

david@driebit.nl @ddeboer_nl

FOSHttpCacheFOSHttpCacheBundle

https://joind.in/14546