Akka HTTP vs Spray

こんにちは、t-hiroyoshiです。
今回は前回紹介したAkka HTTPの性能が気になったのでざっくりベンチマークを取ってみました。
ソースコードはGithubにあげました。

それぞれのバージョン等は以下の通りです。

// sbt.version = 0.13.11
// addSbtPlugin("io.spray" % "sbt-revolver" % "0.8.0")
// addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.2")
lazy val commonSettings = Seq(
name := "akka-http-vs-spray",
version := "1.0.0",
scalaVersion := "2.11.8",
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8", "-Xlint")
)
val akkaV = "2.4.4"
val sprayV = "1.3.3"
lazy val spraySettings = Seq(
libraryDependencies ++= {
Seq(
"com.typesafe.akka" %% "akka-actor" % akkaV,
"io.spray" %% "spray-can" % sprayV,
"io.spray" %% "spray-routing" % sprayV
)
}
)
lazy val akkaSettings = Seq(
libraryDependencies ++= {
Seq(
"com.typesafe.akka" %% "akka-actor" % akkaV,
"com.typesafe.akka" %% "akka-stream" % akkaV,
"com.typesafe.akka" %% "akka-http-experimental" % akkaV
)
}
)
lazy val sprayServer = (project in file("spray-server"))
.settings(commonSettings: _*)
.settings(spraySettings: _*)
.settings(assemblyOutputPath in assembly := file("./spray-server.jar"))
lazy val akkaServer = (project in file("akka-server"))
.settings(commonSettings: _*)
.settings(akkaSettings: _*)
.settings(assemblyOutputPath in assembly := file("./akka-server.jar"))
Revolver.settings
java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)

sbt assemblyしたjarをローカルでjava -jarしてベンチマークをとりました。

ローカル環境

MacBook Pro (Retina, 13-inch, Early 2015)
OS: OSX 10.11.4
Processor: 3.1 GHz Intel Core i7
Memory: 16 GB 1867 MHz DDR3

ベンチマークにはApacheBenchを用いました。

ab -k -c 10 -n 10000 http://localhost:8080/

以下それぞれの結果です。

Akka HTTP

Code

package akka.server
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
object Boot extends App {
implicit lazy val system = ActorSystem("akka-server")
implicit lazy val materializer = ActorMaterializer()
implicit val ec = system.dispatcher
private val route =
pathSingleSlash {
get {
complete("Hello world!")
}
}
Http().bindAndHandle(route, "localhost", 8080)
}

Result

This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Server Software: akka-http/2.4.4
Server Hostname: localhost
Server Port: 8080
Document Path: /
Document Length: 12 bytes
Concurrency Level: 10
Time taken for tests: 0.465 seconds
Complete requests: 10000
Failed requests: 0
Keep-Alive requests: 10000
Total transferred: 1780000 bytes
HTML transferred: 120000 bytes
Requests per second: 21490.49 [#/sec] (mean)
Time per request: 0.465 [ms] (mean)
Time per request: 0.047 [ms] (mean, across all concurrent requests)
Transfer rate: 3735.65 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 0 0 1.0 0 42
Waiting: 0 0 1.0 0 42
Total: 0 0 1.0 0 42
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 1
95% 1
98% 2
99% 3
100% 42 (longest request)

Spray-can

Code

package spray.server
import akka.actor._
import akka.io.IO
import spray.can.Http
import spray.routing._
import spray.http._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
object Boot extends App {
implicit val system = ActorSystem("spray-server")
implicit val timeout = Timeout(5.seconds)
val service = system.actorOf(Props[ServiceActor], "spray-service")
IO(Http) ? Http.Bind(service, "localhost", 8080)
}
class ServiceActor extends Actor with HttpService {
private val route =
pathSingleSlash {
get {
complete("Hello world!")
}
}
def actorRefFactory = context
def receive = runRoute(route)
}

Result

This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Server Software: spray-can/1.3.3
Server Hostname: localhost
Server Port: 8080
Document Path: /
Document Length: 12 bytes
Concurrency Level: 10
Time taken for tests: 0.430 seconds
Complete requests: 10000
Failed requests: 0
Keep-Alive requests: 10000
Total transferred: 1780000 bytes
HTML transferred: 120000 bytes
Requests per second: 23230.85 [#/sec] (mean)
Time per request: 0.430 [ms] (mean)
Time per request: 0.043 [ms] (mean, across all concurrent requests)
Transfer rate: 4038.18 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 0 0 0.9 0 20
Waiting: 0 0 0.9 0 20
Total: 0 0 0.9 0 20
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 1
95% 1
98% 2
99% 3
100% 20 (longest request)

まとめ

Akka HTTPが21490.49 req/sec、Spray-canが23230.85 req/secと割と近い数値が出た気がします。
Akka HTTPは前もっと使い物にならないくらい遅かったイメージだったんですがこれなら十分なリクエストがさばけそうです。