Tips to optimize the performance of Umbraco powered websites

Umbraco is a popular, ASP.NET powered, content management system (CMS). Even though it performs pretty well, here are 11+ optimization tips for Umbraco on IIS.

In Umbraco you can make a couple of changes to make Umbraco a bit more performant. As I’m not an ASP.NET programmer, there was one tip I couldn’t test but took for granted. Use these tips to your advantage, but some tips may require assistance of your IIS web server administrator. Remember him next System Administrator Appreciation Day :-)

Key for a better performing Umbraco website is less writing to disk, or reading from disk. I find that a bottleneck, even with SSD’s. Less reading and writing also saves on RAM (memory) and CPU usage, and thus process execution time in IIS.

In random order I’ll address the following topics:

  • ASP.NET Compilation tempDirectory
  • File Change Notification (FCN)
  • NumRecompilesBeforeAppRestart
  • Disable ~/App_Data/umbraco.config
  • Umbraco ModelsBuilder ModelsMode
  • HTTP Expires headers
  • ~/Config/log4net.config
  • ~/Config/ExamineSettings.config
  • ImageProcessor cache folders, ~/Config/imageprocessor/cache.config
  • AllowSubDirConfig, SqlCe database file to SQL Server
  • SQL Server sessionState

Note

Some changes might degrade performance, especially when done wrong. When in doubt, consult your system administrator first. These settings below work in my environment, maybe not yours.

ASP.NET Compilation tempDirectory

All to often in a shared hosting environment, you may share your ASP.NET compilation temporary directory with other users. This may not be particularly a bad thing, but when a lot of IIS worker processes are reading and writing in one directory, you may find your website waits for other disk operations. And that takes time.

If ASP.NET 4 runs in a Full trust configuration, you can overwrite ASP.NET’s compilation tempDirectory setting to a folder in your website. For example, if the physical path to the content for the virtual directory of your website is z:\shared\sites\example.com\www, and the msIIS-FTPRoot is configured as z:\shared\sites\example.com, you can create an extra folder temp in the FTPRoot and configure that as your compilation tempDirectory.

Locate Umbraco’s compilation node in <system.web>, and add the tempDirectory:


<compilation tempDirectory="z:\shared\sites\example.com\temp" />

Make sure this folder is writable for the user your website runs as.

This may interest you:   Start all stopped application pools that have Autostart set to true

File Change Notification (FCN)

Change the file change notification in ASP.NET, so less resources are used for keeping track of changed files. Especially in large media folders FCN can degrade performance. The All about ASP.Net File Change Notification (FCN) post on Shazwazza’s blog has more insights about this.

Locate the httpRuntime key in your web.config and add fcnMode="Disabled"to completely disable File Change Notification for that folder, or set it to Single. Single is the default since Umbraco 7.5.3, see U4-7712.

NumRecompilesBeforeAppRestart

Indicates the number of dynamic recompiles of resources that can occur before the application restarts. This attribute is supported at the global and application configuration levels, but not at the directory configuration level.

Note

ASP.NET increases the NumRecompilesBeforeAppRestart property value every time an assembly is invalidated and fails to be deleted.

By default, IIS restarts the Umbraco web application after 15 dynamic recompiles of resources. When you have a large Umbraco website, you may experience a long time before the compilation process of your scripts is finished. During the compilation, CPU usage spikes and your sites become unresponsive.

You can decrease the number of application restarts by increasing the NumRecompilesBeforeAppRestart property in your web.config file. Umbraco has this value set to 50, you can increase this to 150, 200, or whatever:


<compilation defaultLanguage="c#" debug="false" batch="false" targetFramework="4.5" numRecompilesBeforeAppRestart="250">

Disable ~/App_Data/umbraco.config

Every time you publish a page in Umbraco, the ~/App_Data/umbraco.config file is saved as cache. In ASP.NET’s mind this is a configuration change, and the application is restarted by IIS with reason ConfigurationChanged.

This behavior is easily disabled in ~/Config/Umbracosettings.config:

  • add the following two (2) lines to ~/Config/umbracoSettings.config:
    • <ContinouslyUpdateXmlDiskCache>False</ContinouslyUpdateXmlDiskCache>
    • <XmlContentCheckForDiskChanges>False</XmlContentCheckForDiskChanges>
  • delete the ~/App_Data/umbraco.config file!

This is addressed in U4-7101. I had to fiddle a bit with where to put these lines, and after some testing, lines 38/39 seemed fine.

Umbraco ModelsBuilder ModelsMode

The thing I could not test, unfortunately: Umbraco ModelsBuilder ModelsMode.

Umbraco ships with a NuGet package called ModelsBuilder. This generates strongly typed models that can be used in Umbraco views. The default behaviour is to generate the models on the fly, in memory, at runtime. This has the advantage of the models always being up to date whenever a content type is modified.

[…]

We changed the setting to Dll mode, which compiles the models to a Dll that is then copied into the bin folder. This fixed the 10s slowdowns, and also fixed the Max Recompilations Reached errors we were seeing above. The downside with this is that it requires a manual step after a deploy to build the models from within the back office.

HTTP Expires headers

Expires headers? Yes, expires headers. Apparently, they’re not set everywhere for your static Umbraco resources.

By configuring expires headers you tell the browser to keep a local copy of the resource in its cache. This speeds up a next visit or page view. The following example, that you add to your web.config tells the browser to save it for 14 days, change the duration if you’d like. First determine which folders you have in your Umbraco installation, and then select the appropriate lines to add.


<locationpath="Umbraco_Client">
	<system.webServer>
		<staticContent>
			<clientCachecacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
		</staticContent>
	</system.webServer>
</location>
<locationpath="Umbraco_Client/assets">
	<system.webServer>
		<staticContent>
			<clientCachecacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
		</staticContent>
	</system.webServer>
</location>
<locationpath="Umbraco_Client/Js">
	<system.webServer>
		<staticContent>
			<clientCachecacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
		</staticContent>
	</system.webServer>
</location>
<locationpath="css">
	<system.webServer>
		<staticContent>
			<clientCachecacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
		</staticContent>
	</system.webServer>
</location>
<locationpath="Media">
	<system.webServer>
		<staticContent>
			<clientCachecacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
		</staticContent>
	</system.webServer>
</location>
<locationpath="scripts">
	<system.webServer>
		<staticContent>
			<clientCachecacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
		</staticContent>
	</system.webServer>
</location>

There already is a line <location path="umbraco"> in your web.config, add the three lines there as well.

Keep in mind these folders might be different for different versions of Umbraco.

 ~/Config/log4net.config

If you don’t use the logfiles Umbraco creates through log4net, then log as less as possible. This limits the number of writes to your disks. In the file ~/Config/log4net.config change the value “true” in “false” for the key <appendToFile value="true" /> and WARN in ERROR for <level value="WARN" />.

~/Config/ExamineSettings.config

Umbraco examine is an extensible indexer and search engine. Add useTempStorage="Sync" to the nodes as described in U4-5993 and https://our.umbraco.com/forum/umbraco-7/using-umbraco-7/72801-fixing-poor-performance-on-azure.

Specifying “Sync” will mean that the index that is stored in ~/App_Data/TEMP/ExamineIndexes/[IndexName] will get restored to the ASP.NET process’s local temp folder (i.e. C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\vs\7a807fb2\7d5e4942\App_Data\TEMP\ExamineIndexes[IndexName], or z:\shared\sites\example.com\temp if you’ve changed ASP.NET’s Compilation tempDirectory mentioned above).

ImageProcessor cache folders, ~/Config/imageprocessor/cache.config

Umbraco’s ImageProcessor creates a lot of cache folders for uploaded images and media by default. To decrease the number of reads writes, and to decrease the number of directories the ASP.NET process has to go through, it’s advised to limit the cache folders created.

This may interest you:   Connect to SqlCe (SQL Server Compact) database from ASP

Configure folderDepth="x" in in ~/Config/imageprocessor/cache.config  (DiskCache key). For example folderDepth=”2″ to create a two level deep cache directory structure. The complete line becomes:


<cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web" maxDays="365" browserMaxDays="7" folderDepth="2" trimCache="false">

AllowSubDirConfig

This last one is tricky: AllowSubDirConfig controls whether or not IIS searches for a web.config file in every subdirectory. If you have a lot of directories with a lot subdirectory’s (for example the imageprocessor cache mentioned above), the ASP.NET process goes through every directory looking for web.config configuration settings. This takes a lot of time (relatively).

It is enabled by default. System administrators may choose to disable this setting using appcmd:


appcmd set vdir "/vdir.name:"example.com/ /allowSubDirConfig:false /commit

Migrate SqlCe SDF database file to an SQL Server database

If you want to be able to use Umbraco in a load-balancing hosting environment, you must have an SQL Server database for your site, and not the default SqlCe SDF database file. That doesn’t scale.

There is a how to migrate SDF database to Sql Server post on Nicola Ayan’s blog. I haven’t tested it myself yet, but I plan to.

Having your SqlCe database file converted to SQL Server has the great advantage you now can save your sessions in that database too! No more InProc sessions that are lost after application restarts (application pool recycles), but Out-of-Process sessions, properly saved in an SQL Server database or table (the latter in my case).

I have a how to configure SQLServer sessionState for Umbraco post ready for you.

Conclusion optimizing Umbraco’s performance

Out of the box, an Umbraco website runs pretty great. But the default configuration makes it read from and write to disk a lot. That is unnecessary, particularly if you don’t use some of the information provided, the log4net logs for example. This post gave you some pointers to optimize Umbraco’s performance, especially when you host dozens or hundreds on a single server or web-farm.

Let me know if this post helped  you in optimizing your Umbraco site! But be careful though, different optimization tips may be valid for different Umbraco versions. Always test first before putting it into production.

If you enjoyed this article, then please consider making a donation.
Thank you for your support. ♥