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

Preview:

Citation preview

Going to production ona Raspberry Pi with

varnish tags

Who am I?

Jérémy DERUSSÉ

Web Technical Leader

AptusHealth

@jderusse

How to get fast responsesfrom a Symfony application?

you can't

How to get fast responsesfrom a Symfony application?your backend

you can't

Solution

using http shared cachedescribe in RFC-2616 RFC-7234

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

Advanced usage with FriendsOfSymfony/FOSHttpCacheBundle

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

Issue #2Cache invalidation

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

Phil Karlton

Cache models

Validation modeletaglast-modified

drawbacks

application is bootedhard to implement

Expiration modelexpirescache-control

drawback

no control on invalidation

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

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

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" } ] }

Automate Tagging

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

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', ], ]; } }

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()); } //... }

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

Automate Tagging

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

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

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 } } }

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 } }

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); } }

Automate Tagging

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

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

Enjoy

Silver bullet?

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

DrawbackOperations are not AtomicB ackend handles writesBackend knows infrastructureIt slows writes

Demo

Software - env=dev

- fetch=lazy

symfony/symfonydoctrine/doctrine-bundle

friendsofsymfony/rest-bundlejms/serializer-bundle

friendsofsymfony/http-cache-bundle

marmelab/admin-on-rest

Demo

HardwareRaspberry Pi Orange Pidocker

MySQLNGINXPHP7-FPMVarnish

$9.59

Demo

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

Thank You

Questions?

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

Recommended