5 votes
rbcUmbracoOnAzure
The goal of this package is to get Umbraco 6.1.x (and likely earlier versions) working on Azure Websites AND scaling out to multiple servers (Azure Websites calls servers "instances").
This package is currently experimental and very much a PoC and has a number of issues, however the issues mentioned below that others seemed to have run into in the past when attempting to get Umbraco to scale on Azure Websites have been solved. You will need a pretty deep understanding of Azure Websites and Umbraco to get this package working - it is only meant as a "springboard" for such technical folks. If you do not have that knowledge I suggest you look at the Umbraco as a Service offering.
Issues I was trying to solve - Umbraco does not scale on Azure Websites, because:
- You need to be able to hit a single back-office server/instance, otherwise Examine locks occur - Azure Websites does not allow you to specify one of the scaled servers as your back-office
- You cannot directly access scaled Azure servers/instances over http and Umbraco's distributed cache updates from the back-office server/instance to other servers does not work as Umbraco requires you to put the full dns server names into a config file (server1.host.com, server2.host.com, etc). You cannot access Azure Websites servers/instances via such host names.
How the package works (and how I solved the above issues)
To solve issue 1:
- I run two Azure Websites:
- I run the back-office on a single (Shared) Azure Website (backoffice-azurewebsites.net)
- I run the front-end on a scaled Azure Website (frontend.azurewebsites.net)
- I run a common database that both share in SQL Azure
To solve issue 2:
- on ApplicationStarting on front-end, I write the Azure server/instance id into a database table - onApplicationEnd, I remove it (set it to IsActive=false) - this means I always know how many instances are available or "scaled out to" which can be used by the back office server
- I plugin to the on Umbraco Cache Update event on the back-office website that fires whenever a back-office operation occurs that needs to update the front-end
- The above event will call each of the front-end servers/instances found in the custom database table - the same url is used for each request, however a custom cookie for each request is used so that we get routed to each instance/server:
- More info on above: All Azure Websites servers/instances when you scale out have the same domain name (mywebsite.azurewebsites.net), however when you scale out, Application Request Routing (ARR) is used along with each servers "InstanceId" in a cookie named "ARRAffinity" so that you stay on the same server when making requests to it. I already know the "InstanceId" for each server from my db table, so we simply construct a cookie with the instance id and fire it off via the normal Umbraco distributed cache web service call to /umbraco/webservices/cacheRefresher.asmx
What this package does not solve:
- Due to the "2 websites" approach (1 back-office that does not scale and 1 front-end that does), you will need to handle getting the rendering files (css,scripts,templates,etc) onto both servers file systems.
- Due to the "2 websites" approach you'll need to work out how to get the /media folder files from the back-office server to the front-end server file structure. One such approach would be using the Azure Blob Storage provider for Umbraco which is available as a package - then both websites would essentially share the same location for their /media folder - package is available at: http://our.umbraco.org/projects/backoffice-extensions/ast-azure-media-sync
Install Instructions:
- Setup 2 Azure Websites - one that you will scale (front-end) and one that you will not (back-office). I found that I had to setup the back-office website as "Shared" so that it would not scale along with the front-end - it is easiest to use the Azure Gallery to setup the websites with 2 separate databases which is quicker than uploading files, etc. Once you have both setup (e.g. back-office.azurewebsites.net and front-end.azurewebsites.net), just delete one of the databases and point both sites to the single remaining database. At this point do not scale out the front-end website.
- On the Backoffice website only, add an App Config name/value of IsUmbracoBackOffice=true - the package uses this to determine the back-office website from the front-end website (no app config name/value set)
- On the Front-end website only, modify your global.asax to inherit from rbcUmbracoOnAzure.UmbracoApplication - the package uses this to hook into the ApplicationEnd event
- On the Front-end website only add an App Config name/value of umbracoContentXMLUseLocalTemp=true (as per the umbraco load balancing instructions for shared file structure)
- Install the package on both websites - it will add a single dll to the /bin folder and add a folder with a view under App_Plugins
- That's it - you can now scale out your front-end website in Azure and look at the page at: /App_Plugins/rbcUmbracoOnAzure/CurrentInstances/ to see the current azure instances - this page also allows you to force the browser to each instance by setting your ARR cookie for you - this page simply pulls values from teh custom db table (called AzureWebsitesInstance)
To test your installation:
- create a simple doc type with one RTE on it and deploy to root of your site - remember to copy the template (and any other "on disk files" to both websites)
- In the template have it pull from umbraco via Umbraco.Field as well as from the Examine index, so you can test and ensure both are updating via the distributed cache call - it is also handy to put @Environment.MachineName in the template so you can tell one server from another
- spin up multiple instances of front-end website and check the url mentioned in step 6 above to ensure they are "registering on app startup" - use the "Clear My Cookie" link to "fool" ARR into possibly sending you to another server - once you have multiple instances active:
- go to the back-office server /umbraco and make a change to your one piece of content and publish it
- go to your front-end website root (not /umbraco) and the change should also be seen - to access each box you can use the links in step 6 above to dynamically change your cookie
Other Notes:
- Please provide any feedback in the forums.
- Source code will be on github.
- You should never access /umbraco from your front-end website
- The front-end website essentially uses the load balancing setup explained at http://our.umbraco.org/documentation/installation/load-balancing using the "File Storage with SAN/...etc" method - the only other thing I did not mention above is implementation of log4net to work across multiple servers with shared storage
- Even though you scale out to 5 instances, it seems Azure will not actually start those instances until traffic warrants it, so you may only see 2 instances in your database table or at the above debugging url
- If your site uses Session state, then you'll need to solve the "multiple server" issue like you'd have to with any load balanced environment - storing Session State in App Fabric or SQL would both work - demo's/examples available via google :-)
UPDATE - 3/25/2014
- added link in description text for how to use media in shared server environment
- added source link on github - this is my first use of git and open sourcing something via git - let me know if i did anything "wrong"
- Package Files
- Documentation
- Archived Files