最小の Owin アプリケーションを Heroku にデプロイしてベンチマーク計測してみた

はじめに

heroku-buildback-mono を使えば C# で書いた WEB アプリを Heroku で動かすことができる。 ランタイムは .NET Framework じゃなくて Mono だけど。

Heroku + Mono のパフォーマンスが知りたくなったので 最小の Owin アプリケーションをデプロイして計測することにした。

コンソールアプリケーションのプロジェクトを作成

セルフホストなのでコンソールアプリケーションのプロジェクトを作成する。

NuGet パッケージを追加

NuGet パッケージマネージャーで

を追加。

Visual Studio の場合は、NuGet Package の復元を有効化しておく。 MonoDevelop(Xamarin Studio) の場合は不要だった。

最小の Owin アプリケーションを作成

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Owin;
using Microsoft.Owin.Hosting;
using Microsoft.Owin.Host.HttpListener;

namespace OwinSample
{
  using AppFunc = Func<IDictionary<string, object>, Task>;

  public class SampleApp
  {
    public SampleApp(AppFunc next)
    {
    }

    public Task Invoke(IDictionary<string, object> environment)
    {
      var stream = (Stream)environment["owin.ResponseBody"];
      using (var writer = new StreamWriter (stream))
      {
        return writer.WriteAsync ("Hello World");
      }
    }
  }

  public class Startup
  {
    public void Configuration(IAppBuilder app)
    {
      app.Use(typeof(SampleApp));
    }
  }

  class MainClass
  {
    private static readonly ManualResetEvent _quitEvent = new ManualResetEvent(false);

    public static void Main (string[] args)
    {
      var port = 5000;
      if (0 < args.Length)
      {
        int.TryParse (args [0], out port);
      }

      Console.CancelKeyPress += (sender, e) =>
      {
        _quitEvent.Set();
        e.Cancel = true;
      };

      using (WebApp.Start<Startup>(string.Format("http://*:{0}", port)))
      {
        Console.WriteLine("Started");
        _quitEvent.WaitOne();
      }
    }
  }
}

Procfile を作成

Procfile には、コンソールアプリケーションを実行するコマンドを記述する。

web: mono OwinSample.exe $PORT

ビルドするとプロジェクトルートに exe が出力されるので、mono コマンドでそいつを起動している。

Heroku にデプロイ

Heroku のユーザー登録と SSH キー登録は済んでいる前提。

$ heroku create <your-app-name>
$ heroku config:add BUILDPACK_URL=https://github.com/friism/heroku-buildpack-mono
$ git push heroku master

を実行し、 Mono のビルドパックを使うようにしておく。

デプロイに成功したら Webブラウザでアクセスしてみる。

f:id:griefworker:20141231143512p:plain

Apatch Bench でベンチマーク計測

Ruby スタックと比較したいので、同じ合計リクエスト発行数と同時接続数で計測した。

合計リクエスト発行数&同時接続数 Requests per second[#/sec] Time per request(mean, across all concurrent requests)[ms]
-n 100 -c 100 29.40 34.015
-n 1000 -c 100 55.60 17.985
-n 1000 -c 1000 42.18 23.710
-n 3000 -c 1000 47.78 20.930
-n 2500 -c 2500 39.52 25.305
-n 3000 -c 2500 43.83 22.815

Mono スタックよりも Ruby スタックの方が性能が良かった。 今回の計測では、ともにアプリケーションサーバーを使っていないから、参考にしかならないけど。