Microsoft recently release the HttpPlatformHandler module for IIS 8+. This module will allow any process that can receive request on some port to be used in IIS. What this means is that you can now host server of any language i.e. GO, Ruby, Erlang, Elixir, Python using IIS. The same module is being used by Azure Websites to host Java.
The first thing that came into my mind was to run a service/website written in Elixir to run on it. In this tutorial we are going to see how to host a Cowboy server behind IIS 8 which is running an Elixir application. Then I have some benchmarks to compare a Cowboy server running behind IIS vs Cowboy server in Windows vs Cowboy server in Ubuntu. The results are interesting (scroll to the bottom if you want to see them).
Hosting Elixir web application using Cowboy behind IIS:
I will be using Windows Server 2012 R2 VM (A1 tier) on Azure to host the application.
1. Setting up Elixir
First lets install chocolatey on the server using which we will install elixir on the machine. Open administrative powershell and run the following
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
Close and open command prompt and run
cinst elixir git, this will install Erlang & Elixir. We also need to install git so we can get the sample project to use in this tutorial. Lets add the Elixir to the PATH environment variable.
My Computer > Properties > Advance System Settings > Environment Variables
C:\tools\Elixir\bin;C:\Program Files\erl6.1\bin; (or where ever the Elixir or Erlang is installed on your system) to the PATH.
2. Setting up IIS
The IIS is not enabled by default on the server, lets enable it.
Goto Manage Server and then under Manage select Add Roles and Features
Select Web Server and under Application Development select all except CGI and then install.
After the installation is done you will have IIS and can access it from IIS Manager. The HttpPlatformHandler module needs to be downloaded and installed. Do that from WebPI/x86/x64, install it and restart the PC.
3. Cowboy behind IIS
Lets clone the example application
cd c:\inetpub\wwwroot\ git clone https://github.com/zabirauf/cowboy-iis-elixir.git mix.bat deps.get mix.bat compile
There are two extra files in there i.e. run.bat & web.config
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <handlers> <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" requireAccess="Script"/> </handlers> <httpPlatform stdoutLogEnabled="true" stdoutLogFile="elixir.log" startupTimeLimit="20" processesPerApplication="1" processPath="C:\inetpub\wwwroot\cowboy-iis-elixir\run.bat" arguments=""> <environmentVariables> <environmentVariable name="PORT" value="%HTTP_PLATFORM_PORT%"/> </environmentVariables> </httpPlatform> </system.webServer> </configuration>
The PORT is set as environment variable and in lib\cowboy_iis.ex it gets the port and starts the cowboy server accordingly. The processPerApplication tells IIS that how much process to start. If you start more than one then I believe IIS load balances requests among them. All the logs get pushed to files prefixed with elixir.log
cd C:\inetpub\wwwroot\cowboy-iis-elixir && @echo Y|mix.bat do deps.get, compile && iex -S mix.bat
In run.bat we get dependencies of project, compile and then run the application.
Open IIS manager and create a new website and put
c:\inetpub\wwwroot\cowboy-iis-elixir in the Physical path. Make sure that IIS has permission to that folder. For quick testing I usually change the corresponding application pool to run under LocalSystem, it should be under Identity in the application pool Advance settings. Make sure the website is started.
Just browse to localhost and the port you set in IIS application and Voila you have Cowboy server running behind IIS. IIS also acts as process manager so in case if anything goes down IIS will make sure to start the necessary process again. The first visit will take few extra seconds as IIS starts the first process.
You can see the result in action at http://elixir-win.cloudapp.net
I ran the tests on A1 Azure VM tier for both Windows & Ubuntu VM. The following benchmark consists comparison between requests to IIS on Windows, requests to Cowboy server on Windows & requests to Cowboy server in Ubuntu. I used Loader.io to run tests. All tests were ran for 1 minute duration.
Following table consists of running 300 clients per second hitting the server.
The difference between all of them is very low. As expected IIS has some overhead which seems to be around 11ms in above case. Lets turn it up a notch.
Following table consists of running 1000 clients per second hitting the server.
The IIS is twice as slower as Cowboy on windows and with more than double the error rate. Cowboy in Ubuntu is performing really well. Lets push it a little bit more
Following table consists of running 2000 clients per second hitting the server.
The IIS was not able to handle that many clients hence the rate of error was so high that loader.io stopped the test and reported nothing. In case of Cowboy in Windows the latency was still high. You might be wondering why is the latency lower than when it was 1000 client, the reason is that the failure rate is high in case of 2000 client. Ubuntu latency increases significantly but it was still the fastest.
I have not played with any settings in IIS for optimization. Probably tweaking few things might change that number
So we saw how to host an Elixir application in IIS. It is still not ready for prime time but a commendable effort by the team in releasing HttpPlatformHandler. The other thing I observed is that Elixir/Erlang or Cowboy in windows is significantly slower, or the culprit might be something deep such as the network stack. I am just speculating, a deeper investigation is needed.
6. Whats Next
We can use the approach to see how to run Cowboy or Phoenix in Azure Cloud Service & Websites.