Performance always interests me. Now, when I host my sites in Cloud, it interests me even more. Better performance = less money spent.

My current setup: Windows Server 2012 Standard, IIS 8.0, SQL Server 2012 Express, 2 GHz core, 1.5 GB RAM, Umbraco 7.0.3. I have tried first two google pages of “website online stress testing tools” and it’s variations, the best and the only leader there is https://www.blitz.io/, nothing changed here since my previous article. Really great tool.

So, my results (really approximate):

~50 requests / sec takes a 2GHz core

~100 requests / sec takes 10 Mbps

~200 MB RAM per each Umbraco instance (less than 1000 nodes)

More specifics:

I’m testing it on a simple Umbraco site, with less than 1000 nodes. It only have uBlogsy package installed, and my custom .dll with few extensions. Page I’m testing is 2nd level deep in Layout, it have about 10 Partials, but every one of them is CachedPartial with 60 seconds cache time (more than enough for the test). Uncached part of page contains moderate amount of logic. In real world you can’t expect all the code to be 100% optimized and always be perfect. Code happens. But if I remove that code, I get up to 160 hits / second:

Content-only page with no logic at all, this is unlikely to happen in real life Content-only page with no logic at all, this is unlikely to happen in real life

Here is how same page with absolutely no logic looks when I set my cloud PC to have 2x 2GHz cores (twice as much CPU power):

Same content page with no logic as above, but this time with 2x cores of 2GHz Same content page with no logic as above, but this time with 2x cores of 2GHz

Back to real life. Page with moderate amount of logic. How will it act on 10 cores?

Windows Server 2012 Task Manager during stress test, 10x 2GHz cores Windows Server 2012 Task Manager during stress test, 10x 2GHz cores

Stress test image for page with logic, server is 10x 2GHz cores Stress test image for page with logic, server is 10x 2GHz cores

You can see, Umbraco scales pretty much linear.

Whether this numbers big or not is up to you to decide. Most sites won’t ever experience this many visitors anyway: 50 hits per second translates into up to ~4 000 000 views per day.

And it scales linear with CPU: want 40 000 000 views per day? Throw 9 more cores and you are fine. Want 4 000 000 000 views per day (do such numbers even exist?) and your server can’t scale that high? Scale horizontally: add few more servers and do a load balancing. I’ve never seen this myself, but Umbraco claims it supports load balancing and it works well. Exciting video about Umbraco serving Red Bull Stratos project, how they did it:

One more trick to serve many static pages at once: OutputCache. With Umbraco MVC is is really easy to enable and it gives more than 10 times boost. Here is image for 1x 2GHz core and OutputCache enabled:

Umbraco 7.0.3 MVC with [OutputCache] attribute specified on hijacked route controller action. Server side. Umbraco 7.0.3 MVC with [OutputCache] attribute specified on hijacked route controller action. Server side.

[OutputCache] stress test results. 1x 2GHz CPU core. [OutputCache] stress test results. 1x 2GHz CPU core.

Now this is what I call good performance! Important thing to remember here is network bandwidth. This example alone was generating more than 70 Mbps of outgoing traffic. And stress test is not requesting any resources like CSS, JS or images. If you are about to have this much real users, you’d be using much more bandwidth!

Code:

<span class="keyword">public</span> <span class="keyword">class</span> UBlogsyDeckspageController : Umbraco.Web.Mvc.RenderMvcController { [OutputCache(Duration = <span class="number">60</span>)] <span class="keyword">public</span> <span class="keyword">override</span> ActionResult Index(RenderModel model) { <span class="keyword">return</span> <span class="keyword">base</span>.Index(model); } } 1 2 3 4 5 6 7 8 < span class = "keyword" > public < / span > < span class = "keyword" > class < / span > UBlogsyDeckspageController : Umbraco . Web . Mvc . RenderMvcController { [ OutputCache ( Duration = < span class = "number" > 60 < / span > ) ] < span class = "keyword" > public < / span > < span class = "keyword" > override < / span > ActionResult Index ( RenderModel model ) { < span class = "keyword" > return < / span > < span class = "keyword" > base < / span > . Index ( model ) ; } }

This is Umbraco route hijacking. In short words, you create a controller class with name that starts with your Document Type alias and ends with “Controller”. It’s Index action is called to display page of this document type. Do whatever you like with it. In our case, apply OutputCache attribute.

Also, like mentioned in comments to this article, one could take a look at Donut Caching, here is a nice article on MVC Donut Caching. It promises to solve caching problems for pages that have changing parts (like Logged In user partial). Would love to hear about successful Donut Cahing use cases on Umbraco.