Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala Play 2.5 vs golang benchmark, and optimizing performance in play framework

I'm benchmarking a simple hello world example in scala play framework 2.5 and in golang. Golang seems to be out performing play by a significant margin and I would like to know how I could optimize play framework to improve performance. I'm using the following to benchmark

ab -r -k -n 100000 -c 100 http://localhost:9000/

I'm running play 2.5 in prod mode using the default configuration everywhere in my project. Can someone help me with performance tuning the play server in order to get the most performance? I read up on the default-dispatcher thread pool, but I'm not sure what settings to use for my pc. Also are there any other areas I could check that would help with performance?

here are my marchine specs

Intel(R) Xeon(R) W3670 @ 3.20GHz 3.19GHz, 12.0 GM RAM, running windows 7 64-bit

Please note that I'm using sbt (clean and stage) to run the server in place in prod mode and executing the bat file found at target/universal/stage/bin/. Here is the source code for play

package controllers

import play.api.mvc._


class Application extends Controller {


  def index = Action {
    Ok("Hello, world!")
  }

}

here are the result from the ab benchmark

ab -r -k -n 100000 -c 100 http://localhost:9000/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:
Server Hostname:        localhost
Server Port:            9000

Document Path:          /
Document Length:        13 bytes

Concurrency Level:      100
Time taken for tests:   1.537 seconds
Complete requests:      100000
Failed requests:        0
Keep-Alive requests:    100000
Total transferred:      15400000 bytes
HTML transferred:       1300000 bytes
Requests per second:    65061.81 [#/sec] (mean)
Time per request:       1.537 [ms] (mean)
Time per request:       0.015 [ms] (mean, across all concurrent requests)
Transfer rate:          9784.69 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:     0    2   1.9      1      72
Waiting:        0    2   1.9      1      72
Total:          0    2   1.9      1      72

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      2
  75%      2
  80%      2
  90%      3
  95%      3
  98%      5
  99%      8
 100%     72 (longest request)

here is the source code for golang

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, world!")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

here are the result from ab benchmark for golang

ab -r -k -n 100000 -c 100 http://localhost:8080/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:
Server Hostname:        localhost
Server Port:            8080

Document Path:          /
Document Length:        13 bytes

Concurrency Level:      100
Time taken for tests:   0.914 seconds
Complete requests:      100000
Failed requests:        0
Keep-Alive requests:    100000
Total transferred:      15400000 bytes
HTML transferred:       1300000 bytes
Requests per second:    109398.30 [#/sec] (mean)
Time per request:       0.914 [ms] (mean)
Time per request:       0.009 [ms] (mean, across all concurrent requests)
Transfer rate:          16452.48 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:     0    1   1.5      1      52
Waiting:        0    1   1.5      1      52
Total:          0    1   1.5      1      52

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      1
  90%      1
  95%      2
  98%      5
  99%      7
 100%     52 (longest request) 

Thanking you in advance Francis

UPDATE!

the following results in improved performance, but I'm still interested in other ideas that could improve performance

package controllers

import play.api.mvc._
import scala.concurrent.Future
import play.api.libs.concurrent.Execution.Implicits.defaultContext


class Application extends Controller {


  def index = Action.async {
    Future.successful(Ok("Hello, world!"))
  }

}

benchmark results

ab -r -k -n 100000 -c 100 http://localhost:9000/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:
Server Hostname:        localhost
Server Port:            9000

Document Path:          /
Document Length:        13 bytes

Concurrency Level:      100
Time taken for tests:   1.230 seconds
Complete requests:      100000
Failed requests:        0
Keep-Alive requests:    100000
Total transferred:      15400000 bytes
HTML transferred:       1300000 bytes
Requests per second:    81292.68 [#/sec] (mean)
Time per request:       1.230 [ms] (mean)
Time per request:       0.012 [ms] (mean, across all concurrent requests)
Transfer rate:          12225.66 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:     0    1   2.2      1     131
Waiting:        0    1   2.2      1     131
Total:          0    1   2.2      1     131

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      2
  90%      2
  95%      3
  98%      5
  99%      7
 100%    131 (longest request)
like image 465
Francis Avatar asked Oct 18 '22 10:10

Francis


1 Answers

As @marcospereira has said, Play is a relatively high-level framework that focuses on exploiting the much more advanced type-system in Scala to give you a lot of features and safety, which in turn helps you write code that is refactorable and scalable to your needs. Never the less, I've gotten great performance from it in production.

Asides from suggesting that you try running your benchmark on Linux with native socket transport, I'll repeat what @marcospereira said, to run your benchmark a couple of times without stopping your Play server. The standard deviation in your Play benchmark results seems abnormally high (averages of 1 with a SD's of 2.2), which suggests that perhaps JIT hasn't fully finished optimising your code for you yet.

like image 168
lloydmeta Avatar answered Oct 21 '22 04:10

lloydmeta