Insights
Bringing our best ideas and thinking to you.
Blog Post
September 7, 2016
Share this page:
The Curious Case of Sitecore Cache
By Kevin Huynh
“The Curious Case of Sitecore Cache” is intended to provide the curious Sitecore community clarity with respect to Sitecore’s cache layers and lifecycle. Sitecore provides a number of caching layers, where numerous caches may exist at any given layer. For example, Sitecore maintains one or more caches containing data retrieved from each content database. The layout engine uses this cached data to generate the HTML markup, with separate caches for the markup associated with each managed Site per instance.
In Sitecore, the data is stored primarily in the SQL database instances where the data is retrieved on demand. Over time, the data grows and the real time requests stress the application, which is less than optimal. Caching data in memory decreases the load on the processor by increasing memory load. When portions of the site are not regularly updated or they are shared across all the pages (e.g. Header, Footer, Menu) by using HTML Caching, we can cache that output for better performance.
The Curious Case of Benjamin Button is a 2008 American romantic fantasy drama film. The film is about a man whose body ages in reverse. Let’s take a look at some loosely coupled similarities of both curious cases.
Daisy: “I wanna remember us just as we are now.”
Similarly, as Benjamin and Daisy appearances intersect a Sitecore application can reach a consistent state of design and functionality. When the appearance and state of your application is consistent, it’s time to remember (or cache) the renderings most used on the website to optimize performance. Using Sitecore’s caching capabilities, especially HTML Caching, you can cache the output HTML of any rendering.
The HTML cache is really important, especially if you have renderings or sublayouts, which are rather slow. An example can be a header, which iterates over a large number of items. When a rendering like this is HTML cached, it renders in constant time no matter how many items are to be rendered in the header.
You can configure your HTML cache per presentation control and either set this generally on the control or where it is assigned.
In this image below, you can see that I have opened the configuration of a given sublayout. You can specify that it is cacheable, so it will create an HTML cache for the given page.
You can specify that the cache should vary by data, which means that the HTML should be different if the Sitecore.Context. Item is different.You can configure your HTML cache per presentation control. Also, you can specify the HTML cache to vary on different parameters.
In this way the HTML cache will be different depending on which item you are trying to access. Below describes the different vary by parameters:
- Vary by Data: Sitecore caches the output based on the item accessed. When the same item is accessed for the second time, the HTML will be loaded from the cache. Typically used for headers and footers.
- Vary by Device: Sitecore caches copies of the output for each Device being used. Recommended for adaptive designs.
- Vary by Login: Sitecore caches two copies of the output. One is for authenticated Extranet users and one is for unauthenticated Extranet users.
- Vary by Param: Sitecore caches the output for each parameter accepted by the rendering. Used in conjunction with rendering parameters.
- Vary by QueryString: Sitecore caches the output for each unique combination of query string parameters. Used with forms that have been embedded into the site.
- Vary by User: Sitecore caches the output for each authenticated user. Used with personalization enabled on websites.
Programmatically you can modify the cache capabilities using the C# helper methods below:
Creating the Cache
Creating a cache consists of creating a new instance of Sitecore.Caching.Cache
. When the instance is created, the cache is automatically registered within the system. This means that Sitecore recognizes the cache and can control it.
var mycache = new Sitecore.Caching.Cache("test cache", 1024);
Referencing the Cache
A cache is accessed by name using the Cache Manager.
var mycache = Sitecore.Caching.CacheManager.FindCacheByName("test cache");
Adding a Value to the Cache
A value is added to the cache using the Add
method.
var mycache = Sitecore.Caching.CacheManager.FindCacheByName("test cache");
mycache.Add("name", "value");
Reading a Value from the Cache
A value is read from the cache using the GetValue
method. Reading a value notifies that the value has been read, which resets the expiration timer.
var mycache = Sitecore.Caching.CacheManager.FindCacheByName("test cache");
var value = mycache.GetValue("name");
Removing a Value from the Cache
A value is removed from the cache using the Remove
method.
var mycache = Sitecore.Caching.CacheManager.FindCacheByName("test cache");
mycache.Remove("name");
Clearing the Cache
A cache can be cleared using the Clear
method.
var mycache = Sitecore.Caching.CacheManager.FindCacheByName("test cache");
mycache.Clear();
Benjamin Button: “I was thinking how nothing lasts, and what a shame that is”
Benjamin exhibits maturity by understanding that unfortunately “nothing lasts”. By comparison, Sitecore developers must prepare for changes and updates to existing caching methods and configurations. For example, different users (e.g. administrators) will have a separate set of requirements and menu options (e.g. admin tabs).
Once you’ve set the ‘Cacheable’ option on an item, any page that uses this rendering will always cache it. Moreover, you can’t cancel the caching for this rendering on pages that you don’t want to be cached.
To disable the caching setting for any rendering, you must:
- Create a new rendering parameters template, which includes a checkbox field called "Cancel Cache Settings'
- Go to your rendering definition item, and set the parameter template to the new template.
If your site runs on Sitecore MVC, implement this method to toggle caching:
namespace Sitecore.SharedResources.Pipelines.Rendering
{
public class SetCacheState : Sitecore.Mvc.Pipelines.Response.RenderRendering.SetCacheState
{
protected override bool IsCacheable(Sitecore.Mvc.Presentation.Rendering rendering, Sitecore.Mvc.Pipelines.Response.RenderRendering.RenderRenderingArgs args)
{
if (!String.IsNullOrEmpty(rendering.Parameters["Disable Cache Setting"])
rendering.Parameters["Disable Cache Setting"] == "1")
{
return false;
}
return base.IsCacheable(rendering, args);
}
}
}
Create a config file inside your 'Include' folder:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<mvc.renderRendering>
<processor patch:instead="processor[@type='Sitecore.Mvc.Pipelines.Response.RenderRendering.SetCacheState, Sitecore.Mvc']"
type="Sitecore.SharedResources.Pipelines.Rendering.SetCacheState, [name of assembly]" />
</mvc.renderRendering>
</pipelines>
</sitecore>
</configuration>
If your code runs on ASP.NET forms:
public override bool IsCacheable
{
get
{
if (!string.IsNullOrEmpty(Parameters["Disable Cache Setting"]) && Parameters["Disable Cache Setting"] == "1")
{
return false;
}
return base.Cacheable;
}
set
{
base.Cacheable = value;
}
}
Publishing - The new chapter in the Sitecore lifecycle.
Benjamin begins a new chapter in his life by publishing a note to Daisy. A familiar metaphor for publishing Sitecore items is that anytime you publish Sitecore items, the complete cache is cleared and starts the cache lifecycle. The HTML/Web/Output cache is the actual HTML generated from your sublayouts and renderings. Therefore, if you publish even a single item, the complete cache is cleared. This is due to the fact that parts of the HTML can be built from multiple items, so the cache has no way of knowing if the item being published has influence on the presentation.
NOTE: In environments that separate a content management instance from some number of content delivery instances, Sitecore clears the site HTML (output) caches after each publishing operation, while all other caches are updated.
You may ask, “Does publishing clear the output cache for all managed sites?”
No, the default implementation of the event handler (the Sitecore.Publishing.HtmlCache class) only clears the output caches for the sites specified for the event handler.
Specifically, all the sites added within the <site> tags will be cleared as shown below:
<event name="publish:end">
<handler type="Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel" method="ClearCache">
<sites hint="list">
<site>website</site>
<site>website</site>
<site>SITE1</site>
<site>SITE2</site>
</sites>
</handler>
<handler type="Sitecore.EventHandlers.CredentialCacheClearer, Sitecore.EventHandlers" method="ClearCache">
<sites hint="list">
<site>website</site>
</sites>
</handler>
</event>
Therefore, if you add and modify sites, you need to remember to update these configurations.
“Can I automate clearing of cache for all sites?”
Yes, you can achieve this objective by overriding this event handler based on the following prototype:
namespace Sitecore.Sharedsource.Publishing
{
using System;
using SC = Sitecore;
public class HtmlCacheClearer : SC.Publishing.HtmlCacheClearer
{
public void ClearCaches(object sender, EventArgs args)
{
SC.Diagnostics.Assert.ArgumentNotNull(sender,"sender");
SC.Diagnostics.Assert.ArgumentNotNull(args, "args");
string[] siteNames;
if (this.Sites.Count > 0)
{
siteNames = (string[])this.Sites.ToArray();
}
else
{
siteNames = SC.Configuration.Factory.GetSiteNames();
}
SC.Diagnostics.Log.Info(
this + " clearing HTML caches; " + siteNames.Length + " possible sites.", this);
foreach (string siteName in siteNames)
{
SC.Diagnostics.Assert.IsNotNullOrEmpty(siteName, "siteName");
SC.Sites.SiteContext site = SC.Configuration.Factory.GetSite(siteName);
SC.Diagnostics.Assert.IsNotNull(site, "siteName: " + siteName);
if (!site.CacheHtml)
{
continue;
}
SC.Caching.HtmlCache htmlCache = SC.Caching.CacheManager.GetHtmlCache(site);
SC.Diagnostics.Assert.IsNotNull(htmlCache, "htmlCache for " + siteName);
if (htmlCache.InnerCache.Count < 1)
{
SC.Diagnostics.Log.Info(
this + " no entries in output cache for " + siteName,
this);
continue;
}
SC.Diagnostics.Log.Info(
this + " clearing output cache for " + siteName, this);
htmlCache.Clear();
}
SC.Diagnostics.Log.Info(this + " done.", this);
}
}
}
If you use the <sites> element within the <handler> element to specify sites, the ClearCaches() method clears the output caches for those sites. Otherwise, it clears the output caches for all sites that cache output and have entries in those caches.
You can use a Web.config include file (/App_Config/Include/Sitecore.Sharedsource.HtmlCacheClearer.config in my case) such as the following to enable this event handler for these events:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<events>
<event name="publish:end">
<handler type="Sitecore.Sharedsource.Publishing.HtmlCacheClearer, Sitecore.Sharedsource"
patch:instead="handler[@type='Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel']">
<patch:attribute name="method">ClearCaches</patch:attribute>
<sites>
<patch:delete />
</sites>
</handler>
</event>
<event name="publish:end:remote">
<handler type="Sitecore.Sharedsource.Publishing.HtmlCacheClearer, Sitecore.Sharedsource"
patch:instead="handler[@type='Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel']">
<patch:attribute name="method">ClearCaches</patch:attribute>
<sites>
<patch:delete/>
</sites>
</handler>
</event>
</events>
”We are using WebControls for our renderings. Do I have to do anything extra to make them HTML Cache supportable?”
- To answer this question, you will need to make sure your control does the following:
- 1. Inherits from Sitecore.Web.UI.WebControl abstract base class
- 2. Implements the DoRender() method
- 3. Implements the GetCachingID() method
Benjamin Button: “It’s a funny thing coming home. Nothing changes. Everything looks the same, feels the same, even smells the same. You realize what’s changed, is you.”
Benjamin visits a familiar room and realizes everything looks, feels and smells the same. Similarly, a website user visiting the same site over and over again will not be able to quantify performance gains, as everything looks and feels the same. Below are tools to realize what has changed in the Sitecore cache.
The Cache Administration Page
The Cache Administration page provides information about each of the Sitecore caches. You can use the Cache Administration page to monitor Sitecore cache utilization and to clear the Sitecore caches. It can be accessed by entering the URL: http://yoursite.com/sitecore/admin/cache.aspx. Here, you can see all the caches, how much memory can be allocated to it, and how much of it is in use. If you are in doubt whether a certain cache is getting cleared, use this tool and refresh it after you have cleared it. You will be able to see the delta of the used cache, giving you an indication of just how much has been cleared.
The Rendering Statistics Page
The Rendering Statistics page provides information about each of the renderings for which an entry exists in each site HTML (output) cache. You can use the rendering statistics page to identify under-performing renderings and renderings for which you can improve cache configuration. You can access the Rendering Statistics page at the following URL: http://yoursite/sitecore/admin/stats.aspx
Important: The amount of data to cache increases as you add items, languages, and versions. Continue to monitor and tune cache sizes over the life of the solution.
In conclusion, understanding Sitecore’s caching lifecycle can improve the website’s overall performance and also minimize issues with missing or updated items and publishing irregularities.