www.drupaleurope.org
Building high-performance Thunder sites by Wolfgang Ziegler
Wolfgang Ziegler img CEO/CTO drunomics GmbH @the_real_fago ● Typed data API maintainer, past Form API & Entty API ● Creator of many modules like Rules, Entty API, Field collecton, … ● Track chair Drupal + Technology
B a c k g r o u n d Thunder-based mult-site project ● Typical publishing project: ● Editors publish content (artcles, recipes, …) – Paragraphs, Media, Related content, Listngs, Mega-Menu, – Search with autocompleton and facets With interactve elements: ● Votng, Comments –
G o a l s Fast responses for logged-out site visitors via cached pages ● Long-lived caches by default ● Keep some caches when nodes are edited – Allow editors to purge cache per page – Good (cached) performance & UX for logged-in users ● (commentng, votes) Reasonable performance for uncached responses ●
Architecture
F a s t , c a c h e d p a g e l o a d s ! CDN (Cloudfare) → Varnish → Drupal (Page cache) ● Ensure cached responses → Warm caches afer editng ● Enhance cached pages via Javascript ●
U n c a c h e d p a g e r e n d e r p e r f o r m a n c e ? Without caches, rendering easily can get slow ● Can decoupling help us to obtain beter performance? ● → Evaluate performance of two possible architectures: Traditonal approach – Decoupled approach –
D e c o u p l e d a r c h i t e c t u r e SSR for SEO and fast page loads ● Nuxt.js (Ready-to-go universal Vue.js) ● Backend: ● Drupal + JSON API + Subrequests module –
A p r o t o t y p e f o r c o m p a r i s o n Contenta CMS example ● Recipe page ● Main recipe node – 4 related repices by category – A main menu block –
P r o t o t y p e s : D e c o u p l e d v s . T r a d i t i o n a l Decoupled: ● Nuxt/vue.js example – Improved with Subrequests – Main-Menu added as subrequest Contenta CMS frontend (material theme) of a recipe page ● ("node view page"), unstyled.
S i m p l e b e n c h m a r k Non-scientfc approach on notebook ● Measure page generaton tme in multple scenarios ● Repeated each scenarios multple tmes, take best result ● Goal: Get an idea on performance diferences ●
C o m p a r i s o n r e s u l t s : C a c h e d r e s p o n s e 40 35 30 25 Traditonal 20 Decoupled 15 10 5 0 Request tme [ms] → Decoupled system stll renders, Drupal not.
C o m p a r i s o n r e s u l t s : Wa r m e d s i t e , n o p a g e - c a c h e 600 500 400 Traditonal 300 Decoupled 200 100 0 Request tme [ms] → API requests are all uncached, Drupal has internal caches.
C o m p a r i s o n r e s u l t s : A f t e r e d i t i n g t h e p a g e 450 400 350 300 250 Traditonal 200 Decoupled 150 100 50 0 Request tme [ms] → Drupal invalidates render cache
C o m p a r i s o n r e s u l t s : A f t e r e d i t i n g , l o a d i n g a n o t h e r p a g e 250 200 150 Traditonal 100 Decoupled 50 0 Request tme [ms] → Decoupled can keep page caches, Drupal not.
C o m p a r i s o n : R e n d e r i n g p a r t i a l l y c a c h e d p a g e s 100 90 Traditonal with 80 render cache 70 60 dynamic page cache 50 40 Decoupled with page 30 20 cache 10 0 Request tme [ms] → Decoupled is fasted when combining cached chunks
P e r f o r m a n c e c o m p a r i s o n t a k e a w a y s Vue.js is faster rendering cached responses than Drupal ● delivering cached elements Unoptmized JSON API requests are rather slow with ● embedded enttes (~200ms) JSON API without embedded enttes ~70ms – comparable request including embedded enttes with Views – REST plugin: ~110ms → Optmizaton needed
T r a d i t i o n a l v s d e c o u p l e d Decoupled setup misses cache of rendered pages ● Decoupled setup has performance advantages due to beter re- ● use of partally cached pages, but.. performance gains are not huge compared to dynamic page cache – decoupled system requires more complex hostng & development – Young projects pose a maintenance risk, future updates? ● → Go with traditonal approach & use dynamic page cache!
Caching with Drupal
T h e f o u n d a t i o n : D r u p a l c a c h e m e t a d a t a Everywhere in the APIs ● Every rendered element provides it ● Metadata is aggregated during rendering ● Cache metadata: ● Cache context (by-user, by-path, …) – Cache tags (“dependencies” - invalidate when X changes) – Max-Age – 0 (no-cache), permanent –
C a c h e d p a g e s i n D r u p a l (Internal) Page cache: ~20ms ● Dynamic page cache: ~80ms ● Render cache ● Typically blocks & rendered enttes (view-modes) –
I n t e r n a l p a g e c a c h e Keeps an internal copy of cached pages (afer CDN, Varnish) ● Defaults to database backend, pluggable ● Invalidated based upon cache tags ● Possible with CDNs – but not on cheap plans – Possible with Varnish – but not yet stable – Risk of too frequent updates & bad cache usage – → Need to avoid high-frequent cache invalidaton
I n t e r n a l p a g e c a c h e : K e e p i t ! Customize it to cache 7 days / 1h depending on page ● Do not invalidate automatcally ● except node/{ id } – → Module: drupal.org/project/preserve_page_cache ● Custom purger for editors to invalidate by URL ● Invalidates page cache, varnish, CDN – Database based for storage ●
Wa r m c a c h e s a f t e r e d i t i n g drupal.org/project/prefetcher ● Run regularly on cron to warm caches ● Keeps track of pages and their cache lifetme ● Warms a certain number of pages per run ●
D y n a m i c p a g e c a c h e Caches authentcated + anonymous pages ● Caches pages minus personalized parts ● lazy-builders render un-cached bits – Auto-placeholdering auto-creates lazy-builders for high- ● cardinality cache-contexts user, session –
A u t o m a t i c p l a c e h o l d e r i n g Confgurable via service parameter in services.yml ● renderer.config auto_placeholder_conditionsg max-aieg 0 contextsg ['session', 'user'] taisg [] Dynamic page cache only applies to elements which are ● excluded by this confguraton!
D y n a m i c p a g e c a c h e – R o o m f o r i m p r o v e m e n t If auto-placeholdering fails, dynamic page cache fails! ● And it happened all the tme for editors! ● #2949457: Toolbar's renderPlain() is incompatble with dynamic – page cache [needs review] #2899392: user_hook_toolbar() makes all pages uncacheable – [done, 8.5 ] #2914110: Shortcut hook_toolbar implementaton makes all – pages uncacheable [needs work ] Can happen when adding features → Add tests! ●
D y n a m i c p a g e c a c h e – R o o m f o r i m p r o v e m e n t s ( 2 ) Automatc per-permission-hash cache context ● Helps preventng permission issues – But – it’s bad for cache-reuse across roles – Doubles page cache of anonymous pages – Idea: ● Remove permission cache-context (& take care!) – → Beter cache-usage → Anonymous page loads warms cache for authentcated pages
R e n d e r c a c h e Typically blocks & rendered enttes (view-modes) ● Mostly ● Dynamic page cache is already by URL – Render cache elements duplicate dynamic page cache! – Stll it’s useful ● For lazy-built elements – For speeding up “uncached” page generaton tme –
R e n d e r c a c h e : T u n e i t ! Ofen many, many items end up in the cache ● Per user, per URL (query), per role – Usually does not ft into memcache/Redis – Since 8.4.x – limited to 5.000 items in database – → See htps:/ /www.drupal.org/node/2891281 → Inspect your cache items → Disable unwanted items via d.o./project/cache_split → Remove all per-URL caches
C a c h e i n v a l i d a t i o n v i a c a c h e t a g s Drupal’s cache metadata is a sensible default ● But the default is ofen to generic ● list_node, list_taxonomy – Every page depends on list_node ● → every edit, invalidates dynamic page cache of every page!
C u s t o m i z e c a c h e m e t a d a t a o n r e n d e r e d e l e m e n t s Remove too generic cache tags (list_node) & context ● Add new cache tags ftng to use-cases ● node.feld_channel – cache_tools – Sanitze cache metadata of blocks & Views ● Strip cache contexts (route, url.query_args) – htps:/ /www.drupal.org/project/cache_tools ●
Recommend
More recommend