There are many different articles on the internet about how to make an application faster when hosting it on Azure. This has been a real pain point with big PHP applications or applications which involve a lot if IO operations - like loading modules with Node.js. Recently, I was working with one startup and they approached me with a very interesting issue: Their Node.js application was running about 35x faster on Heroku than on Azure App Service and that is what actually made me to write this article.
Persistent storage in App Service
The way storage is designed for Azure App Service is very interesting. Unlike with Heroku (or other similar providers), App Service offers a shared, persistent storage for your application. This generally means, that when one instance in a farm makes a write to the file system (D:\home) it will be available for all the other instances in the farm and it is going to persist even if the farm restarts or recycles.
This feature is really important for most of the “old-school” applications (well, it is kind of habit which has been overcome, right?), which use the file system for storage - like WordPress for uploads, plugins and themes (there are plugins which allow you to use Azure Storage for that or even an entire fork of WordPress called Project Nami modified to run on Azure as smoothly as possible), Moodle, Joomla, phpBB and many more.. It allows you to rapidly migrate any existing application to Azure, leverage the scalability and many other cool features, which App Service offers.
However, modern applications usually separate the storage from the application tier and allow you to easily use CDNs and blob storage, because it allows for bigger scale and takes some load off from the application tier, so there is no need for such persistent storage since none of the instances are writing to the shared storage (assuming uploads go to Temp folder and then are uploaded to the blob storage for example).
Let's dive just a bit deeper
The storage in App Service is using Azure Storage in the background. Generally, each App Service instance has an agent called Azure Drive which emulates the file system calls from IIS and proxies it to Azure Storage along with some caching layer. If you would like to learn more about the stuff that is behind it, I suggest watching Windows Azure Web Sites: Under the Hood from TechEd 2012:
The way that persistent storage is handled in App Service (and it is done in a very clever and admirable way) kind of obviously adds another layer of latency which you have to add to your requests. And it can have quite a big impact on running applications like WordPress, Moodle and similar. So, is there any solution for apps, which don’t need persistent storage on the application tier?
Introducing App Service Local Cache
The answer is yes! About half a year ago, App Service team introduced a feature called App Service Local Cache. Not many people have however heard about it, which kind of surprised me and that is the main motivation for writing this article.
The Local Cache basically sort of “removes” the persistent storage from your Web App and makes the instances pre-load and cache the file system beforehand (you can find more about the impacts and features in the docs). Thanks to that, your application is going to be most likely faster.
So back to my case with the startup. When their application was running without Local Cache, the server-side processing of the request took 70ms. When we enabled it, the processing time was down to 2-3ms on average - which is a HUGE improvement in my opinion.
One little fact
When using the Local Cache, you can still use Kudu or FTP to work with the files. The only difference is that when you change something there, it will not be propagated to the instances unless you restart the Web App.
This brings a challenge with deployment - when you push new change to source control, the changes will be deployed, however the instances won’t pick it up unless you restart the site. So how to automate this, so you can do this in a single push? The answer is simple - make use of Visual Studio Team Services and just add the site restart as final deployment step in the build definition. You can find out more about those in my previous article about PHP and DevOps with VSTS.
What if I still need persistent storage?
If you need to use persistent storage with your application, there are still certain steps which can be taken to make the application faster - like enabling WinCache in PHP, which basically caches the bytecode in the memory and does bunch of other optimizations.
To submit comments, go to GitHub Discussions.