Try our conversational search powered by Generative AI!

Johan Björnfot
Nov 7, 2019
  3833
(10 votes)

A smarter output cache

During Ascend I saw on Linus Ekströms whishlist for better CDN support that he would like to be able to get a list of all content items that are part of a pages rendered output. I then recalled that I had done something in a related area before, see Russian doll caching. So now when we had a hackday I decided to see if I could build something that would fulfil Linus wish. So I took some inspiration from my previous work and created a context ContentRenderingTrackerContext that stores information about all content items that are used during rendering of a request. It also keeps track if something on the rendering is personalized (ContentArea or XHtmlString). I then intercepted some components in CMS like PropertyRenderer (used by PropertyFor) to collect data in the context. This component is available in project ContentRenderingTracker.

Smarter output cache

Then to test my tracker component I decided to create a ContentAwareOutputCacheAttribute. It works a bit as the built-in attribute ContentOutputCacheAttribute but it is a little smarter. So for example when a content item is changed will it only invalidates the output cache for those pages that actually has used the changed content item, compared to the built-in who invalidates the output cache for all pages (since it does not know where the content item is used). The new attribute also uses the knowledge about usage of personalized content from the context and will not output cache pages that has personalized content (meaning the attribute can be used on all controllers and it will take care of if it should output cache or not due to personalized content usage). The attribute is available in project ContentAwareOutputCache.

Output cache in Redis

The output cache attribute worked nice but it still requires that the page is rendered once (on that specific instance) before it gets output cached. I therefore decided to write a mvc filter that works in a similar way as the ContentAwareOutputCacheAttribute but with the difference that it caches the rendered page in Redis instead. The nice thing with this is that it also adresses the cold-start scenario (for example when a new instance of the web application is spun up due to scaling out). In that case can a new empty instance directly utilize the output cache without the need to do an initial rendering. That implementation is available in project RedisOutputCache

I also added two versions of alloy, one that uses the attribute and one that uses the Redis caching. All code is available in repository ContentRenderingTracker.

Disclaimer

This is nothing offically supported by EPiServer, you are free to use it as you like at your own risk.

Nov 07, 2019

Comments

Stefan Holm Olsen
Stefan Holm Olsen Nov 8, 2019 03:50 AM

Very nice, Johan. 👍 I am generally very fond of caching with Redis. Great to see more of it.

I know that it would be a huge and unlikely breaking change, but I still wish that the object cache would be compatible with Redis.

Johan Björnfot
Johan Björnfot Nov 8, 2019 07:04 PM

I can definetly see benefits with a distirbuted object cache. But performance wise I think you probably gain more using a "higher level" cache (as html output cache in redis) as distributed cache because then you dont need to pay the serialization penalty but can rather deliver the cached entity directly as is. I think the russian doll caching where the whole page output is included (same as page output cache) is the most performant option since in that case you can utilize cache for components like menu even on personalized pages. It is however a bit more complicated than just full page output cache.

Linus Ekström
Linus Ekström Nov 11, 2019 06:51 AM

Nice work Johan. I'll definitivelly give it a try! 

Henrik Fransas
Henrik Fransas Nov 12, 2019 09:29 AM

Great work Johan! Thanks!

Ravindra S. Rathore
Ravindra S. Rathore Nov 12, 2019 10:08 AM

Great work Johan! Thanks for sharing.

Please login to comment.
Latest blogs
Why C# Developers Should Embrace Node.js

Explore why C# developers should embrace Node.js especially with Optimizely's SaaS CMS on the horizon. Understand the shift towards agile web...

Andy Blyth | May 2, 2024 | Syndicated blog

Is Optimizely CMS PaaS the Preferred Choice?

As always, it depends. With it's comprehensive and proven support for complex business needs across various deployment scenarios, it fits very well...

Andy Blyth | May 2, 2024 | Syndicated blog

Adding market segment for Customized Commerce 14

Since v.14 of commerce, the old solution  for adding market segment to the url is not working anymore due to techinal changes of .NET Core. There i...

Oskar Zetterberg | May 2, 2024

Blazor components in Optimizely CMS admin/edit interface

Lab: Integrating Blazor Components into Various Aspects of Optimizely CMS admin/edit interface

Ove Lartelius | May 2, 2024 | Syndicated blog

Anonymous Tracking Across Devices with Optimizely ODP

An article by Lead Integration Developer, Daniel Copping In this article, I’ll describe how you can use the Optimizely Data Platform (ODP) to...

Daniel Copping | Apr 30, 2024 | Syndicated blog

Optimizely Forms - How to add extra data automatically into submission

Some words about Optimizely Forms Optimizely Forms is a built-in add-on by Optimizely development team that enables to create forms dynamically via...

Binh Nguyen Thi | Apr 29, 2024