ElixirとRailsのベンチマーク比較をした話

業務でAPIサーバーを作る事になり、何で実装しようか検討したという話です。

候補としてRails(定番)が上がっていたものの、

  • 大量のリクエストを捌く必要があるので大変そう
  • ビジネスの成長に合わせてスケールさせ辛い(スゴい勢いで成長する)
  • そこまで複雑な処理はしない(別のサブシスでごりごりやる、こっちはRails製)

という事で他の選択を検討しました。
選択しとして

  • Erlang ( + cowboy )
  • Elixir ( + cowboy )
  • Scala ( + akka )
  • Go

があがったので、RailsとElixirでAPIサーバーのプロトタイプを作ってベンチマーク比較をしてみました。

※ ElixirはErlangと同水準のBeamを吐くのでErlangは除外しています(ベンチを実際に計った結果、同程度の性能でした、こちらは別途結果を公開しようと思います)
またGo/Scalaについては僕自身そこまで熟知しているわけではないので今回は対象から外しています。

以下、プロトタイプのAPIサーバーの仕様です

https://github.com/ohr486/server_bench

使用したサーバーはAWS/EC2の、t2microインスタンス、OSは64bit CentOS7です。

以上の環境でabを使い、以下の様に計測しました。

  • Rails: Rails4.2 + Ruby2.2 + nginx1.6.2 + unicorn4.8.2
  • Elixir: Erlang17.4 + Elixir1.0.2 + Cowboy2.0
  • DBアクセスをしないpingに対してリクエストをかける
  • 各同時接続数毎に5回測定を行い、その平均を結果とする
    • ab -n <同時接続数> -c <同時接続数>
  • 同時接続を投げてエラーにならない最大同時接続数
  • ElixirとRailsの最大接同時続数で接続数xNのアクセスを投げた場合の
    • Request/Sec
    • Time/Req

結果は以下となります。
https://docs.google.com/spreadsheets/d/1J8Rk9EwImbRifUPkqYdJuH9qzx8-szuLmNootQO6Z6U/edit#gid=0

(Failedが出ないギリギリの)最大同時接続数は
Rails: 130 / Elixir: 4900

最大同時接続時のRequest/Secは
Rails: 689 / Elixir: 4175

最大同時接続時のTime/Req(1リクエストあたり)は
Rails: 1.47msec / Elixir: 0.37msec

でした。

結論として、(webだけの性能を見れば)Elixirの方が良い結果が出ました。
もちろんRailsにもチューニングの余地がかなりあり、まだまだベンチ結果を上げる事は可能と思います。
ただどう頑張っても(僕のスキルでは)Elixirでの結果並みにRailsをチューニングで性能改善ができるイメージはわきませんでした。
(またRailsではなくSinatra等の軽量F/Wを使えばもっと良いベンチマーク結果がでると思います)

また今回のベンチマークではDBアクセスがありません(単純なping)が、DBアクセスのあるAPIベンチマークを取れば、ElixirはDBがボトルネックになりここまでの性能は出ないと思います。(事実DBがボトルネックで他のAPIでは性能劣化しました)

以上をふまえて、僕の携わってるプロジェクトにてElixirの採用を決定しました。

おわり。

(注意)
このエントリは、Railsオセーという事を主張するものではありません。
APIサーバーにビジネスロジックをごりごり組み込むのであれば、Elixir/CowboyよりRailsを採用していたと思います。
事実、管理システムサイドはRailsを採用しております、要は適材適所という話で、たまたまElixir/Cowboyという選択肢があったので採用したのです。はい。