Web server ‘hello world’ benchmark : Go vs Node.js vs Nim vs…

Web server ‘hello world’ benchmark : Go vs Node.js vs Nim vs…

Daniel Lemire's blog

There are many popular frameworks for writing little web applications. Go and JavaScript (Node.js) are among the most popular choices. Reportedly, Netflix runs on Node.js; Uber moved from Node.js to Go for better performance. There are also less popular options such as nim.

An in-depth review of their performance characteristics would be challenging.  But I just write a little toy web application, will I see the difference? A minimalist application tells you the best possible speed since any more complex application has to run slower.

Let us try it out. I want the equivalent of ‘hello world’ for web servers. I also do not want to do any fiddling: let us keep things simple.

A minimalist Go server might look as follows:

package main
import (
  "fmt"
  "log"
  "net/http"
)
func main() {
  http.HandleFunc("/simple", func(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "Hello!")
  })
  fmt.Printf("Starting server at port 3000\n")
  if err := http.ListenAndServe(":3000", nil); err != nil {
    log.Fatal(err)
  }
}

A basic JavaScript (Node.js) server might look like this:

const f = require('fastify')()
f.get('/simple', async (request) => {
  return "hello"
})
f.listen({ port: 3000})
  .then(() => console.log('listening on port 3000'))
  .catch(err => console.error(err))

Nim offers a nice way to achieve the same result:

import options, asyncdispatch
import httpbeast
proc onRequest(req: Request): Future[void] =
if req.httpMethod == some(HttpGet):
  case req.path.get()
    of "/simple":
      req.send("Hello World")
    else:
      req.send(Http404)
run(onRequest, initSettings(port=Port(3000)))

I wrote a benchmark, my source code is available. I ran it on a powerful IceLake-based server with 64 cores. I use a simple autocannon command as part of the benchmark:

autocannon -m 'GET' http://localhost:3000/simple

It uses ten concurrent connections by default but you can increase the number of concurrent connections to 1000 (-c 100). My result indicates that Node.js is doing quite well on this toy example.

My web server does very little work, so it is an edge case. I have also not done any configuration: it is ‘out of the box’ performance. Furthermore, the server is probably more powerful than anything web developers will use in practice.

There is considerable noise in this results, and you should not trust my numbers entirely. I recommend you try running the benchmark for yourself.

I reviewed some blog posts, all concluding that Go is faster :

What is somewhat interesting is that, in the best case, they find a factor of two in favour of Go (and Bun). At scale such a factor matters, certainly. It would be interesting to find out why my benchmark does not seem to agree with these findings. Possibly the triviality of my benchmark task plays a role. Presumably, Go scales better with more complexity.

An interesting question is whether one can get better performance by using servers written entirely in a language like C, C++, Rust or Zig.

While preparing this blog post, I had the pleasure of compiling software written in the nim language for the first time. I must say that it left a good impression. The authors state that nim was inspired by Python. I does feel quite like Python. I will revisit nim later.

Generated by RSStT. The copyright belongs to the original author.

Source

Report Page