SpinSpire logo

Choosing between PHP, Lua, Go

I have recently spent quite a bit of time trying to come up with a better way to implement RESTful service that serve data in JSON. This is because most of our work these days involves writing client-side JavaScript apps that present a rich UI in the browser and then do all server-side interactions via AJAX. In pursuit of the best way to implement RESTful service on the backend, I have tried my hands at Go programming language, D programming language, Lua and of course Java and PHP. I was assuming that the Go or Lua would be much faster than PHP. Well, it turns out that at least without special optimizations, that is not the case.

I wrote the following programs to compare their performance:

<?php

header('Content-Type: application/json');

$db = new PDO('mysql:host=localhost;dbname=db;charset=utf8', 'user', 'pass');
$stmt = $db->query("SELECT * FROM node");
$result = array();
$result['list'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($result);

 

<?php

define('DRUPAL_ROOT', getcwd());

require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
// drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

header('Content-Type: application/json');

$stmt = db_query("SELECT * FROM node");
$result = array();
$result['list'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($result);

 

json = require "cjson"

function json_result(key, data)
  local result = {}
  result[key] = data
  ngx.say(json.encode(result))
end

function json_error(...)
  local result = {}
  result["message"] = string.format(...)
  ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
  ngx.say(json.encode(result))
end

mysql = require "resty.mysql"

local db, err = mysql:new()
if not db then
  json_error("failed to instantiate mysql: %s", err)
  return
end

db:set_timeout(1000) -- 1 sec

local ok, err, errno, sqlstate = db:connect{
  host = "127.0.0.1",
  port = 3306,
  database = "db",
  user = "user",
  password = "pass",
  max_packet_size = 1024 * 1024
}

if not ok then
    json_error("failed to connect: %s: %d %d", err, errno, sqlstate)
    return
end

result, err, errno, sqlstate = db:query("SELECT * FROM node")

if not result then
  json_error("failed to query: %s: %d %d", err, errno, sqlstate)
end

json_result("list", result)

 

The above programs simply query a table and return all rows and columns from that table as a JSON array.

And then I hit the above programs with a bit of load using 'ab' HTTP load testing command. Following are the results ...

Performance Comparison
Language/API Average time/request
PHP PDO API 0.519 ms
PHP Drupal API 4.281 ms
LuaJIT OpenResty API
with code cache ON
0.877 ms
LuaJIT OpenResty API
with code cache OFF
2.191 ms
Go lang with GORM and Go-JSON-REST 0.880 ms

So it turns out that pure PHP PDO API version is the fastest. LuaJIT with code cache ON is a close second. LuaJIT with code cache OFF is slower. And  PHP with Drupal API version is slowest because it incurs the overhead of bootstrapping Drupal. And the Go version is about same as LuaJIT (didn't include the source code for that one). I didn't bother writing one for Java, as I know that it will perform pretty well, but consume a boatload of resources.

As you can see, that PHP is still the fastest, even without APC. But in reality, the raw performance of the program itself won't matter, because running from across the internet, the network latency will add about another 100ms. So I'm not sure why I'd switch away from PHP just yet. PHP is not my favorite language. But at this time, I can't justify changing my whole programming stack without real benefits of switching.


tags: drupal php go lua