Osgood Performance Gains
Tags: javascript, node
Published: 2019-07-31 16:06:00

We recently performed several optimizations within the request/response path for the new JavaScript platform, [Osgood](https://github.com/IntrinsicLabs/osgood), in an attempt to make it run faster. Osgood is a secure, fast, and simple platform for running JavaScript HTTP servers, and is distributed as a binary that can run on your server just like Node.js.


## Optimizations

Some of these improvements were rather straightforward and are applicable to most codebases:

- Remove [unnecessary](https://github.com/IntrinsicLabs/osgood/commit/2a839bb2e1d580e8858f30e6e73f1bcf55ccd5f6) [work](https://github.com/IntrinsicLabs/osgood/commit/8fd4ab1317cfe66de1453c32c1b5f99d3f2ba022) (in our case, when returning a string response)
- [Lazily construct](https://github.com/IntrinsicLabs/osgood/commit/7788a98f15fd513ab775ac26378292d9b2454a44) complex class instances (such as `Headers`)
- [Pass around references](https://github.com/IntrinsicLabs/osgood/commit/5d6d2471510f0012557282ab6a0301ec83a14256) instead of performing a table lookup

Other optimizations depended on how V8 optimizes and runs JavaScript and wouldn't necessarily be faster in other situations:

- Replace `defineProperty()` calls with [private class fields](https://github.com/IntrinsicLabs/osgood/commit/67037b4a3f048a5d4ec3781ec6575227f0ab0c2b)
    - Though [private symbols](https://github.com/IntrinsicLabs/osgood/commit/5afdc5be1a2cd751cbe8656ac6da7fb847e26d93) turned out to be even faster
- Use `class` when instantiating [similar-shaped objects](https://github.com/IntrinsicLabs/osgood/commit/c5b5053f8a17361d8da3c032ea53a615eaf5f0ab)

Many of these optimizations are ones you wouldn't necessarily want to make within app code. However, with Osgood being a large-audience platform for running application code, it makes sense to optimize as much as possible and benefit a large number of applications.


## Results

Using the `wrk` benchmarking tool we saw a **3.0x** improvement—measured in requests per second (r/s)—when running a simple “Hello, World!” benchmark with _10 concurrent requests_: `osgood@0.1.0` runs at **25,261 r/s** whereas `osgood@0.2.1` runs at **77,450 r/s**! (For reference, `node@12.7.0`, which also runs server-side JavaScript, runs at **31,159 r/s**.)

![Osgood Performance Gains](https://thepracticaldev.s3.amazonaws.com/i/gutm6rontu4i0cmcet83.png)

As you can see, Osgood runs much faster as the concurrency increases. We built Osgood from the beginning with concurrency in mind so these results aren't that surprising. Under the hood, Osgood is making use of Tokio. From the [Tokio homepage](https://tokio.rs/):

>  Applications built with Tokio are concurrent out of the box. Tokio provides a multithreaded, work-stealing, task scheduler tuned for async networking work loads.

Here are some raw numbers from these benchmarks which also show how response time standard deviation is an order of magnitude calmer as well:

```
$ wrk -d 60 -c 10 http://localhost:3000/hello # osgood 0.1.0
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.26ms    9.91ms 123.57ms   92.77%
    Req/Sec    12.69k     2.91k   16.98k    73.83%
Requests/sec:  25261.70

$ wrk -d 60 -c 10 http://localhost:3000/hello # osgood 0.2.1
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   140.86us  219.40us  15.27ms   97.41%
    Req/Sec    38.92k     2.30k   45.89k    71.38%
Requests/sec:  77449.91

$ wrk -d 60 -c 10 http://localhost:3000/hello # node v12.7.0
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   321.69us   96.95us  11.08ms   98.41%
    Req/Sec    15.66k     1.18k   17.50k    76.54%
Requests/sec:  31159.16

$ wrk --version
wrk 4.0.0 [epoll]
```

The code used for these benchmarks is [available here](https://github.com/IntrinsicLabs/osgood/tree/master/benchmarks).

## What's Next

We're pretty happy with the performance gains we've been able to make. That said we have more plans to make it even faster. One such feature we're planning on implementing is to optionally [auto-scale workers](https://github.com/IntrinsicLabs/osgood/pull/12) (a feature which gave a **2.5x** improvement over the `osgood@v0.1.0` release).

While the _average_ latency of `osgood@0.2.1` is less than half of Node.js, the _max_ is still higher. This means there should still be some room to optimize garbage collection and get more consistent results.

As always, [patches are welcome](https://github.com/IntrinsicLabs/osgood), and if you see an area to help performance we'd love to get a PR from you!

Wanna get your hands on this faster version of Osgood? Visit the [releases](https://github.com/IntrinsicLabs/osgood/releases) page and download the latest version!