Being an avid learner and a tech perfectionist for more than a decade I like to run various performance tests. And although I agree that all tests are subjective and skewed, sometimes there are grains of truth. I’m involved in several big PHP projects(see Homediary.com) on my day-to-day job where we use Phalcon - a clean, super fast framework and I also learn Elixir and Go. PHP got a serious performance boost with the recent release of PHP 7. Hearing only awesome stories about Phoenix/Elixir performance and with Go on the rise I decided to look for any existing projects measuring the performance of the above mentioned web frameworks.
Luckily, there was PETE, which stands for PErformance TEst of different web frameworks: phoenix (elixir), slim (PHP), phalcon (PHP). It is a simple single page web app showing a list of images. Nevertheless it consists of a controller, a view and a template: the View/Controller part of the MVC stack. That’s exactly what can be evaluated from the performance point of view. The project didn’t have a Go version of the app so I had to code one. I have submitted a pull request to have it included in the original repo.
I did my own test on three m4.xlarge AWS EC2 instances: one instance was used for
wrk, another instance was used for nginx/Php-fpm/phalcon setup and the last instance was used for Elixir/Erlang stack. I reused the PHP instance to test Go version of the app by stopping nginx and php-fpm and launching the Go app.
I repeated every
wrk launch several times to ensure consistency in numbers. The results are quite surprising. I expected to see a tight fight between Phoenix/Elixir and Go/stdlib but instead the Go version has been surpassed by Phalcon/PHP! In fact, the Go version of the gallery app is the slowest among the three.
Phalcon 3.0.2 with PHP 7
wrk -t4 -c100 -d60s --timeout 2000 http://220.127.116.11/gallery Running 1m test @ http://18.104.22.168/gallery 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 14.00ms 5.40ms 227.06ms 90.31% Req/Sec 1.82k 58.01 2.06k 74.92% 435522 requests in 1.00m, 772.52MB read Requests/sec: 7255.99 Transfer/sec: 12.87MB
Phoenix 1.2.0 with Erlang/OTP 19
wrk -t4 -c100 -d60s --timeout 2000 http://22.214.171.124/gallery Running 1m test @ http://126.96.36.199/gallery 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 5.80ms 4.30ms 228.66ms 74.56% Req/Sec 4.56k 546.57 9.26k 74.86% 1091298 requests in 1.00m, 2.05GB read Requests/sec: 18158.02 Transfer/sec: 34.95MB
wrk -t4 -c100 -d60s --timeout 2000 http://188.8.131.52/gallery Running 1m test @ http://184.108.40.206/gallery 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 19.65ms 19.01ms 223.41ms 85.76% Req/Sec 1.57k 144.09 2.13k 68.25% 375624 requests in 1.00m, 651.61MB read Requests/sec: 6256.53 Transfer/sec: 10.85MB
It is easy to see that Phalcon serves 7255 requests/sec but that pales in comparison with Phoenix’s 18158 requests/sec (served with only 5.8ms avg latency!!). The Go version Go is the slowest with only 6256 requests/sec despite Go being a compiled language.
Performance of the Go version can be improved by almost 5x by moving template parsing outside of the handler function so that templates are only parsed once during app initialization. I’m not 100% sure but I think that’s how other frameworks deal with templates too, so that should be fair comparison. The updated results for Go look like this:
wrk -t4 -c100 -d60s --timeout 2000 http://220.127.116.11/gallery Running 1m test @ http://18.104.22.168/gallery 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.49ms 3.66ms 218.68ms 84.18% Req/Sec 5.93k 407.07 23.34k 95.59% 1416365 requests in 1.00m, 2.40GB read Requests/sec: 23567.17 Transfer/sec: 40.88MB
This makes Go/stdlib the winner, Elixir/Phoenix the runner up (23% fewer requests than Go) and PHP/Phalcon taking the last place.
My smart readers told me net/http can’t do connection pooling and is not a very fast HTTP server in general and advised to use valyala/fasthttp. Well, the Go version of the app with fasthttp has just blown my socks off with a whopping 28816 requests/sec, a 22% increase!
wrk -t4 -c100 -d60s --timeout 2000 http://22.214.171.124/gallery Running 1m test @ http://126.96.36.199/gallery 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 3.74ms 3.43ms 211.54ms 90.18% Req/Sec 7.24k 237.32 7.90k 68.79% 1729095 requests in 1.00m, 2.96GB read Requests/sec: 28816.34 Transfer/sec: 50.46MB