Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

1,833 views

Published on

Le moyen le plus rapide d'obtenir une réponse d'un Backend est de ne pas l'appeler ;-) Une solution fournie par les "reverse-proxy" me direz-vous, mais pas si simple d'invalider le cache...

Ce talk aborde une fonctionnalité méconnue de Varnish: les tags. Nous verrons comment en tirer partie via les "event listeners" d'une application Symfony standard. Au menu, un cluster de Rasberry Pi, une API, et des données toujours fraîches sous la milliseconde.

Published in: Software

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

  1. 1. Going to production on a Raspberry Pi with varnish tags
  2. 2. Who am I? Jérémy DERUSSÉ Web Technical Leader AptusHealth @jderusse
  3. 3. How to get fast responses from a Symfony application? you can't
  4. 4. How to get fast responses from a Symfony application?your backend you can't
  5. 5. Solution using http shared cache describe in RFC-2616 RFC-7234
  6. 6. Integration in Symfony use SensioBundleFrameworkExtraBundleConfigurationCache; /** * @Cache(smaxage="3600") */ public function indexAction() { // ... } Advanced usage with FriendsOfSymfony/FOSHttpCacheBundle
  7. 7. Issue #1 Unsharable resources private resources (ie. invoice, shopping cart, ...) per role representations Solution vary cache on user/role/other see SfLive 2015 Jérôme Vieilledent & David Buchmann Repousser les limites : HTTP cache et utilisateurs connectés
  8. 8. Issue #2 Cache invalidation “ There are only two hard things in Computer Science: cache invalidation and naming things. Phil Karlton
  9. 9. Cache models Validation model etag last-modified drawbacks application is booted hard to implement Expiration model expires cache-control drawback no control on invalidation
  10. 10. cache model In a real world Backend can't validate every cache HIT Life time is not predictable BUT Varnish can be requested to partially invalidate responses Backend knows when resources change Responses are build on top of resources
  11. 11. 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
  12. 12. Varnish tags curl "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" } ] }
  13. 13. Automate Tagging Tagging Response 1. Collect displayed resources 2. Generate resource identifier 3. Tag response
  14. 14. Automate Tagging Tagging Response - 1. Collect displayed resources namespace AppEventListener; use JMSSerializerEventDispatcherEvents; use JMSSerializerEventDispatcherEventSubscriberInterface; use JMSSerializerEventDispatcherObjectEvent; 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', ], ]; } }
  15. 15. Automate Tagging Tagging Response - 2. Generate resource identifier namespace AppEventListener; use AppTagTagExtractorInterface; use FOSHttpCacheBundleHandlerTagHandler; use JMSSerializerEventDispatcherEventSubscriberInterface; use JMSSerializerEventDispatcherObjectEvent; 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()); } //... }
  16. 16. Automate Tagging Tagging Response - 3. Tag response namespace AppEventListener; use AppTagTagExtractorInterface; use FOSHttpCacheBundleHandlerTagHandler; use JMSSerializerEventDispatcherEventSubscriberInterface; use JMSSerializerEventDispatcherObjectEvent; 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); } //... }
  17. 17. Automate Tagging Tagging Response 1. Collect displayed resources 2. Generate resource identifier 3. Tag response Invalidate cache 1. Listen changes 2. Generate resource identifier 3. Call varnish
  18. 18. Automate Tagging Invalidate Cache - 1. Listen changes namespace AppEventListener; use DoctrineCommonEventSubscriber; use DoctrineORMEventOnFlushEventArgs; use DoctrineORMEvents; 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 } } }
  19. 19. Automate Tagging Invalidate Cache - 2. Generate resource identifier namespace AppEventListener; use AppTagTagExtractorInterface; use DoctrineCommonEventSubscriber; 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 } }
  20. 20. Automate Tagging Invalidate Cache - 3. Call varnish namespace AppEventListener; use AppTagTagExtractorInterface; use DoctrineCommonEventSubscriber; use FOSHttpCacheHandlerTagHandler; 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); } }
  21. 21. Automate Tagging Tagging Response 1. Collect displayed resources 2. Generate resource identifier 3. Tag response Invalidate cache 1. Listen changes 2. Generate resource identifier 3. Call varnish Enjoy
  22. 22. Silver bullet? Works well when HIT >> MISS Read >> Write Application knows resources used to build response Drawback Operations are not Atomic Backend handles writes Backend knows infrastructure It slows writes
  23. 23. Demo Software - env=dev - fetch=lazy symfony/symfony doctrine/doctrine-bundle friendsofsymfony/rest-bundle jms/serializer-bundle friendsofsymfony/http-cache-bundle marmelab/admin-on-rest
  24. 24. Demo Hardware Raspberry Pi Orange Pi docker MySQL NGINX PHP7-FPM Varnish $9.59
  25. 25. Demo
  26. 26. ab -n 8000 -c 26 192.168.1.17:81/comments/1 This is ApacheBench, Version 2.3 <$Revision: 1757674 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net Licensed to The Apache Software Foundation, http://www.apache.org/ Server Software: nginx/1.10.3 Server Hostname: 192.168.1.16 Server Port: 80 Document Path: /comments/1 Document Length: 576 bytes Concurrency Level: 26 Time taken for tests: 26.912 seconds Complete requests: 200 Failed requests: 0 Total transferred: 193400 bytes HTML transferred: 115200 bytes Requests per second: 7.43 [#/sec] (mean) Time per request: 3498.553 [ms] (mean) Time per request: 134.560 [ms] (mean, across all concurrent Transfer rate: 7.02 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 1 2 1.4 1 6 Processing: 546 3342 1156.7 3020 7204 Waiting: 546 3342 1156.7 3020 7204 Total: 550 3344 1156.5 3021 7205 in numbers ab -n 8000 -c 26 192.168.1.17/comments/1 This is ApacheBench, Version 2.3 <$Revision: 1757674 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net Licensed to The Apache Software Foundation, http://www.apache.org/ Server Software: nginx/1.10.3 Server Hostname: 192.168.1.17 Server Port: 80 Document Path: /comments/1 Document Length: 576 bytes Concurrency Level: 26 Time taken for tests: 2.340 seconds Complete requests: 8000 Failed requests: 0 Total transferred: 8948504 bytes HTML transferred: 4608000 bytes Requests per second: 3418.52 [#/sec] (mean) Time per request: 7.606 [ms] (mean) Time per request: 0.293 [ms] (mean, across all concurrent Transfer rate: 3734.21 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 2 0.8 2 7 Processing: 2 5 3.3 5 55 Waiting: 2 5 3.3 4 55 Total: 2 8 3.3 7 56 app varnish
  27. 27. Thank You
  28. 28. Questions?
  29. 29. 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-.html https://de.wikipedia.org/wiki/Carambar https://rcgo.com.br/recursos.html

×