29
Going to production on a Raspberry Pi with varnish tags

Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Embed Size (px)

Citation preview

Page 1: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Going to production ona Raspberry Pi with

varnish tags

Page 2: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Who am I?

Jérémy DERUSSÉ

Web Technical Leader

AptusHealth

@jderusse

Page 3: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

How to get fast responsesfrom a Symfony application?

you can't

Page 4: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

How to get fast responsesfrom a Symfony application?your backend

you can't

Page 5: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Solution

using http shared cachedescribe in RFC-2616 RFC-7234

Page 6: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Integration in Symfonyuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; /** * @Cache(smaxage="3600") */ public function indexAction() { // ... }

Advanced usage with FriendsOfSymfony/FOSHttpCacheBundle

Page 7: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Issue #1Unsharable resources

private resources (ie. invoice, shopping cart, ...)per role representations

Solutionvary cache on user/role/othersee SfLive 2015 Jérôme Vieilledent & David Buchmann Repousser les limites : HTTP cache et utilisateurs connectés

Page 8: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Issue #2Cache invalidation

“ There are only two hard things in Computer Science: cacheinvalidation and naming things.

Phil Karlton

Page 9: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Cache models

Validation modeletaglast-modified

drawbacks

application is bootedhard to implement

Expiration modelexpirescache-control

drawback

no control on invalidation

Page 10: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

cache modelIn a real world

Backend can't validate every cache HITLife time is not predictable

BUT

Varnish can be requested to partially invalidate responsesBackend knows when resources changeResponses are build on top of resources

Page 11: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

curl -I "http://varnish.myapp.com/c"

curl -I "http://varnish.myapp.com/b"

curl -I "http://varnish.myapp.com/a"

HTTP/1.1 200 OK Cache-Control: public, s-maxage=3600 X-Cache-Tags: Foo,Bar

HTTP/1.1 200 OK Cache-Control: public, s-maxage=3600 X-Cache-Tags: Foo

Varnish tags

curl \ -X "BAN" \ -H "X-Cache-Tags: Foo" \ "http://varnish.myapp.com"

HTTP/1.1 200 OK Cache-Control: public, s-maxage=3600 X-Cache-Tags: Bar,Qux

Page 12: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Varnish tagscurl "http://varnish.myapp.com/posts/42"

HTTP/1.1 200 OK Cache-Control: public, s-maxage=86400 X-Cache-Tags: Post:42,Author:12,Comment:314,Comment:1337 { "id": 42, "title": "My blog post.", "body": "Lorem Ipsum.", "author": { "id": 12, "username": "jderusse" }, "comments": [ { "id": 314, "message": "Wow such post" }, { "id": 1337, "message": "much performance" } ] }

Page 13: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate Tagging

Tagging Response1. Collect displayed resources2. Generate resource identifier3. Tag response

Page 14: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate TaggingTagging Response - 1. Collect displayed resources

namespace App\EventListener; use JMS\Serializer\EventDispatcher\Events; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; class SerializationTagListener implements EventSubscriberInterface { public function onPostSerialize(ObjectEvent $event) { $resource = $event->getObject(); // TODO } public static function getSubscribedEvents() { return [ [ 'event' => Events::POST_SERIALIZE, 'format' => 'json', 'method' => 'onPostSerialize', ], ]; } }

Page 15: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate TaggingTagging Response - 2. Generate resource identifier

namespace App\EventListener; use App\Tag\TagExtractorInterface; use FOS\HttpCacheBundle\Handler\TagHandler; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; class SerializationTagListener implements EventSubscriberInterface { private $tagExtractor; public function __construct(TagExtractorInterface $tagExtractor) { $this->tagExtractor = $tagExtractor; } public function onPostSerialize(ObjectEvent $event): void { //... $tags = $this->tagExtractor->extract($event->getObject()); } //... }

Page 16: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate TaggingTagging Response - 3. Tag response

namespace App\EventListener; use App\Tag\TagExtractorInterface; use FOS\HttpCacheBundle\Handler\TagHandler; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; class SerializationTagListener implements EventSubscriberInterface { private $tagExtractor; private $tagHandler; public function __construct(TagExtractorInterface $tagExtractor, TagHandler $tagHandler) { $this->tagExtractor = $tagExtractor; $this->tagHandler = $tagHandler; } public function onPostSerialize(ObjectEvent $event): void { $tags = $this->tagExtractor->extract($event->getObject()); $this->tagHandler->addTags($tags); } //... }

Page 17: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate Tagging

Tagging Response1. Collect displayed resources2. Generate resource identifier3. Tag response

Invalidate cache1. Listen changes2. Generate resource identifier3. Call varnish

Page 18: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate TaggingInvalidate Cache - 1. Listen changes

namespace App\EventListener; use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Events; class DoctrineInvalidationTagListener implements EventSubscriber { public function getSubscribedEvents() { return [Events::onFlush]; } public function onFlush(OnFlushEventArgs $eventArgs) { $uow = $eventArgs->getEntityManager()->getUnitOfWork(); foreach ($uow->getScheduledEntityUpdates() as $resource) { // TODO } foreach ($uow->getScheduledEntityDeletions() as $resource) { // TODO } } }

Page 19: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate TaggingInvalidate Cache - 2. Generate resource identifier

namespace App\EventListener; use App\Tag\TagExtractorInterface; use Doctrine\Common\EventSubscriber; class DoctrineInvalidationTagListener implements EventSubscriber { private $tagExtractor; public function __construct(TagExtractorInterface $tagExtractor) { $this->tagExtractor = $tagExtractor; } public function onFlush(OnFlushEventArgs $eventArgs) { $uow = $eventArgs->getEntityManager()->getUnitOfWork(); $tags = []; foreach ($uow->getScheduledEntityUpdates() as $resource) { $tags = array_merge($tags, $this->tagExtractor->extract($resource)); } foreach ($uow->getScheduledEntityDeletions() as $resource) { $tags = array_merge($tags, $this->tagExtractor->extract($resource)); } // TODO } }

Page 20: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate TaggingInvalidate Cache - 3. Call varnish

namespace App\EventListener; use App\Tag\TagExtractorInterface; use Doctrine\Common\EventSubscriber; use FOS\HttpCache\Handler\TagHandler; class DoctrineInvalidationTagListener implements EventSubscriber { private $tagExtractor; public function __construct(TagExtractorInterface $tagExtractor, TagHandler $tagHandler) { $this->tagExtractor = $tagExtractor; $this->tagHandler = $tagHandler; } public function onFlush(OnFlushEventArgs $eventArgs) { // ... $this->tagHandler->invalidateTags($tags); } }

Page 21: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Automate Tagging

Tagging Response1. Collect displayed resources2. Generate resource identifier3. Tag response

Invalidate cache1. Listen changes2. Generate resource identifier3. Call varnish

Enjoy

Page 22: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Silver bullet?

Works well whenHIT >> MISSRead >> WriteApplication knows resources used to buildresponse

DrawbackOperations are not AtomicB ackend handles writesBackend knows infrastructureIt slows writes

Page 23: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Demo

Software - env=dev

- fetch=lazy

symfony/symfonydoctrine/doctrine-bundle

friendsofsymfony/rest-bundlejms/serializer-bundle

friendsofsymfony/http-cache-bundle

marmelab/admin-on-rest

Page 24: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Demo

HardwareRaspberry Pi Orange Pidocker

MySQLNGINXPHP7-FPMVarnish

$9.59

Page 25: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Demo

Page 26: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

ab -n 8000 -c 26 192.168.1.17:81/comments/1This is ApacheBench, Version 2.3 <$Revision: 1757674 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.netLicensed to The Apache Software Foundation, http://www.apache.org/

Server Software: nginx/1.10.3Server Hostname: 192.168.1.16Server Port: 80

Document Path: /comments/1Document Length: 576 bytes

Concurrency Level: 26Time taken for tests: 26.912 secondsComplete requests: 200Failed requests: 0Total transferred: 193400 bytesHTML transferred: 115200 bytesRequests per second: 7.43 [#/sec] (mean)Time per request: 3498.553 [ms] (mean)Time per request: 134.560 [ms] (mean, across all concurrentTransfer rate: 7.02 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median maxConnect: 1 2 1.4 1 6Processing: 546 3342 1156.7 3020 7204Waiting: 546 3342 1156.7 3020 7204Total: 550 3344 1156.5 3021 7205

in numbers

ab -n 8000 -c 26 192.168.1.17/comments/1This is ApacheBench, Version 2.3 <$Revision: 1757674 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.netLicensed to The Apache Software Foundation, http://www.apache.org/

Server Software: nginx/1.10.3Server Hostname: 192.168.1.17Server Port: 80

Document Path: /comments/1Document Length: 576 bytes

Concurrency Level: 26Time taken for tests: 2.340 secondsComplete requests: 8000Failed requests: 0Total transferred: 8948504 bytesHTML transferred: 4608000 bytesRequests per second: 3418.52 [#/sec] (mean)Time per request: 7.606 [ms] (mean)Time per request: 0.293 [ms] (mean, across all concurrentTransfer rate: 3734.21 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median maxConnect: 0 2 0.8 2 7Processing: 2 5 3.3 5 55Waiting: 2 5 3.3 4 55Total: 2 8 3.3 7 56

app varnish

Page 27: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Thank You

Page 28: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Questions?

Page 29: Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi

Credits

http://linuxgizmos.com/10-dollar-orange-pi-one-pits-quad-core-cortex-a7-against-pi-zero/http://toutsurlesbisounours.centerblog.net/rub-bisounours-3eme-generation-.htmlhttps://de.wikipedia.org/wiki/Carambarhttps://rcgo.com.br/recursos.html