Performance is one of the key points when it comes to websites, please find here some quick wins I’ve learnt while dealing with server side performance on my projects.
Yes, this is an obvious one, but is also the first place to start. So, first thing is to make sure you have a proper caching strategy.
I’m not deeping into sitecore cache configuration, there is a lot in the internet and also official documentation:
Great! But, don’t cache that much! Take care about cache sizes!
Caching is a good strategy to improve the website performance and CPU usage, but be careful! you might be ending on moving the issue form CPU to Memory. This is something I noticed a lot on some Sitecore implementations. Also, if the cache size is too big, and the dictionary contains a huge number ok keys, then the processes to resolve the key or to clean up the caches will also impact on the performance.
There are a lot of posts on google explaining how to extend Sitecore with your custom cache.
Sitecore provides this setting that removes the cache limitation giving the full memory size from the server to each cache. This is not a good option, even though Sitecore recommends to disable cache limits when running with enough RAM (>16GB), like an P3V2 plan in Azure, I encountered some issues, like the one mentioned before, or also some bad HTML caching configuration that eats a lot of memory ending up on a server recycle due to high memory consumption as the caches are never scavenged and grow uncontrollably.
The cache key indexing
Cache key indexing can significantly reduce the time it takes to perform operations on a large cache, and is particularly useful in large solutions where items are frequently renamed, moved, copied, and deleted. Cache key indexing is available for the following caches:
- Access Result cache
- Item cache
- Item paths cache
- Paths cache
To enable those, we can apply this config patch:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/"> <sitecore> <settings> <setting name="Caching.CacheKeyIndexingEnabled.AccessResultCache" set:value="true"/> <setting name="Caching.CacheKeyIndexingEnabled.ItemCache" set:value="true"/> <setting name="Caching.CacheKeyIndexingEnabled.ItemPathsCache" set:value="true"/> <setting name="Caching.CacheKeyIndexingEnabled.PathsCache" set:value="true"/> </settings> </sitecore> </configuration>
The AccessResults Cache
This particular cache is really interesting when it comes to performance analysis. I had cases where this cache was increasing exponentially during the load tests, no matter how much memory you assign to it, it will reach the limit at some point. Also, the log is flooded by messages saying this cache is getting flushed.
But, what is this cache for? Each and every time a user requests an item, it resolves the security rights and then stores it in this cache. So, first question is, has our website an account feature? Do we have restricted items? If the answer is no, we can gain 20/30% performance by disabling security access on the web DB:
<database id="web"> <securityEnabled>false</securityEnabled> ... </database>
An obvious but important thing to mention is to check logs. Before deep dive into your code and to find any potential bottleneck, make sure that your application is running smoothly, and the logs are empty, no errors nor exceptions. If you have any, first thing to do is to fix any issue in your code.
We can gain some performance disabling WebDAV from our CD servers and, if we are not making use of it, from the CM as well. Sitecore recommends disabling WebDAV on the production content delivery servers to reduce the number of log files being created. Also, Sitecore recommends disabling WebDAV on the content management servers if the WebDAV functionality is not being used.
This is also a quick win, seems to be another obvious thing, but I still finding it a lot. Normally the indexes are maintained on the CM, this means the server that has the responsibility of updating those is the CM, but sometimes the index configuration is not proper and we’re using CD resources to update the indexes. Disable it if you are not doing it in purpose for any specific reason.
You just need to patch the update strategy on the CD servers:
<index id="sitecore_index" type="Sitecore.ContentSearch.SolrProvider.SolrSearchIndex, Sitecore.ContentSearch.SolrProvider"> <param desc="name">$(id)</param> <param desc="core">$(id)</param> <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" /> <strategies hint="list:AddStrategy"> <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/manual" /> </strategies>
Disable Performance Counters
Performance counters are useful when troubleshooting performance, but also generate some overhead, so disable those until you those:
<setting name="Counters.Enabled" value="false" />
Disable Bucket Debug
If bucket debugging is enabled, every query executed against an item bucket is written to the search log file. Sitecore recommends disabling bucket debug logging on content delivery servers to reduce log file size, mitigate pollution of the log files, and help minimize any overhead
required to write and maintain log files.
<setting name="BucketConfiguration.EnableBucketDebug" value="false" />
Disable Memory Monitor
Memory Monitor creates frequent CPU spikes and should only be enabled when troubleshooting memory related issues.
Sitecore recommends disabling the Memory Monitor in production environments, and only enabling it for troubleshooting memory related issues.
<hooks> <hook type="Sitecore.Diagnostics.HealthMonitorHook, Sitecore.Kernel" /> <!--<hook type="Sitecore.Diagnostics.MemoryMonitorHook, Sitecore.Kernel"> <param desc="Threshold">800MB</param> <param desc="Check interval">00:00:05</param> <param desc="Minimum time between log entries">00:01:00</param> <ClearCaches>false</ClearCaches> <GarbageCollect>false</GarbageCollect> <AdjustLoadFactor>false</AdjustLoadFactor> </hook>--> </hooks>
The next steps
If after applying all the above your solution still not performing as expected, then is time to go deeper and analyze what’s going on.
I’d suggest to start by running some performance or load tests while profiling your app with Visual Studio or dotTrace, you can have a quick look at this post if you’re running your local instance in Docker containers. Find here a quick script to stress your app with JMeter.
This will point you to the code bottlenecks, this task can take hours but will definitely help you to improve your solution.
Sitecore provides some useful tools that helps the developers on this topic, like the pipelines profiling: https://[yoursite]/sitecore/admin/pipelines.aspx and the “debug mode”.
Those are just some quick actions than can help you on improving performance. Of course there are a lot more to do, troubleshooting performance is a complex, time consuming (sometimes tedious) but funny thing to do. I hope this helps you a bit, let’s make your website blazing fast!