Umbraco will work out of the box with Azure, including Examine + Lucene but you have to ensure everything is configured correctly. Umbraco’s documentation could use a little love since it’s a bit confusing and possibly overwhelming to find all of the correct settings and resources.
Here’s the docs for a simple Azure web app setup with Umbraco. Then, if you are load balancing things get a little more interesting.
And then you need to consider what load balancing actually means, what type of load balancing you are doing (i.e. auto-scaling, etc…), if you are using deployment slots, etc… since that can affect the types of configuration and settings required to make everything work.
The definition of Load Balancing in Umbraco
In Umbraco, load balancing is anytime you have more than one Umbraco process connecting to the same database instance.
So if you have a staging site connecting to your staging database and you also have a couple of developers working on their local machine also pointing their Umbraco instance at this same database, this is load balancing. That also means it’s load balancing in an unsupported way because you most likely have all of these processes writing to the database whereas Umbraco only supports having a single process being able to write to the database at once.
Umbraco has a queue of instructions that are stored in the umbracoCacheInstruction
table. This queue is written to by the primary Umbraco server and is read by all servers connecting to the database. This is how caches are distributed between all servers taking part in load balancing and in Umbraco these caches are both: Umbraco’s nucache (in memory IPublishedContent store) and the Lucene indexes. When the primary server makes changes to content, instructions are queued in this table and the other processes taking part in load balancing read this queue and update their local caches/indexes.
Lucene and Azure
One reason why the Umbraco/Azure configuration is tricky is due to the usage of Lucene which is the default indexing engine used by Umbraco (via Examine). Examine itself is a search/indexing abstraction and by default it implements searching and indexing with Lucene. Lucene is a file based indexing engine and the engine itself runs in-process (it runs within your ASP.NET web app).
Azure web apps infrastructure is based on network file shares which means all of the files used to run your web app do not actually reside on the physical file system that is hosting your web app. Lucene doesn’t play very well with remove file shares due to it’s heavy IO operations. For this article, we’ll call the network file share the “slow drive”.
It is possible to forcefully put some files on the local physical file system of the web server which is done by using the %temp% environment variable path in Azure web apps. We’ll call this the “fast drive”.
To work around the “slow drive” limitation, Umbraco configures Examine/Lucene to store the Lucene files on the “fast drive”. And depending on your site’s configuration, if it is load balancing, auto-scaling, primary server vs replica server, etc… this configuration will differ. An important thing to know about Azure and scaling out, is that when you scale out (manually or automatically), the same “slow drive” network share files are used by all processes involved in the scaling. As you can imagine this will be problematic for Lucene files (i.e. file locks) if the primary server is configured with SyncTempEnvDirectoryFactory
and is scaled out.
The reason why the “fast drive” is accessed via an environment variable called %temp% is because that storage is temporary. It’s volatile. Azure moves your site between it’s workers whenever it wants and when that happens, the %temp% storage area will be erased. This means that your local Lucene indexes will be removed and Umbraco will need to rebuild (or sync, depending on your config) them on site startup if they are not there. Rebuilding indexes comes with quite a lot of overhead because Umbraco needs to query all of your content, media and member data in the database to re-populate the indexes. And remember, each Umbraco process maintains it’s own local Lucene index which means if you are load balancing with 10x replica servers, if a few of those sites are moved to new workers your SQL server will incur a fairly hefty overhead in order to rebuild all of those local Lucene indexes.
The work arounds don’t end there though. Azure web apps are configured to have ‘overlapping app domains’ in IIS which means that there will be multiple concurrent processes trying to access Lucene files (and Umbraco’s other cache files) at the same time. This is not supported for the same reason that you cannot have more than one process concurrently trying to write to a file while they both also have it opened, that will result in file lock errors. Umbraco works around this by something called “MainDom” which is a technique used to identify which process (app domain) is the ‘active’ one to determine which process can access the files. Overlapping app domains will occur when the app is restarted (i.e. web.config bump, /bin change, etc…). With the correct configuration this should work, else it means you will end up with file lock issues.
What about this Azure Directory project?
Within the Examine project is a sub-project called Examine.AzureDirectory
. Currently this is only released for Umbraco 7 because it has known issues that are still being worked out in order to ship this for Umbraco v8.
Does this project solve the issues above? Nope. It only solves one issue = the rebuilding indexes overhead. This project essentially changes the “slow drive” from being the network file system for a web app proecess to being stored in Azure blob storage. This means that when a web app starts up and it doesn’t have an index in it’s local “fast drive”, the index can be synced from the blob storage to the %temp% location.
This still means that each Umbraco process maintains it’s own local index. It means that its still possible for local indexes to become out of sync with each other and it still means that the local indexes could be impacted by the volatility of the %temp% “fast drive”. The other challenge is that it is imperitive with this setup that there is not accidentally more than one primary Umbraco server configured.
Do I need ExamineX to run Umbraco on Azure?
Nope. But ExamineX does solve the above issues and challenges. It doesn’t require you to know and understand all of the various configuration settings for getting Lucene to work nicely with Umbraco primary servers, replica servers, auto-scaling, deployment slots, etc…
By using a hosted indexing and search service like Azure Cognitive Services it means you don’t have to worry about indexes getting out of sync, how the “fast drive” works, rebuilding indexes SQL overhead, file locks, or accidentally configuring multiple primary servers.
ExamineX is an implementation of Examine’s APIs so where you use Examine APIs, those same APIs will work with ExamineX.
Less configuration, less maintenance, less headaches.