# OCaml web server run multiple processes

**URL:** <https://discuss.ocaml.org/t/ocaml-web-server-run-multiple-processes/6408>\
**Category:** Learning\
**Tags:** web, performance\
**Created:** [September 13, 2020, 11:31am UTC](https://discuss.ocaml.org/t/ocaml-web-server-run-multiple-processes/6408 "2020-09-13T11:31:05Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![mudrz](https://avatars.discourse-cdn.com/v4/letter/m/8e7dd6/32.png) [@mudrz](https://discuss.ocaml.org/u/mudrz)\
**Post date:** [September 13, 2020, 11:31am UTC](https://discuss.ocaml.org/t/ocaml-web-server-run-multiple-processes/6408/1 "2020-09-13T11:31:05Z")

</div>

I’ve been running some simple benchmarks to compare web servers written in JS, F# and OCaml:  
environments:  
JS

- JS: fastify [https://www.fastify.io](https://www.fastify.io) + pg + knex (not entirely fare with the other ones since they are more bare bone than knex)
- OCaml: opium on master (httpaf) [https://github.com/rgrinberg/opium](https://github.com/rgrinberg/opium) + caqti
- F#: giraffe [https://giraffe.wiki](https://giraffe.wiki) + dapper [https://dapper-tutorial.net](https://dapper-tutorial.net)

I started with @shonfeder’s excellent tutorial: [https://shonfeder.gitlab.io/ocaml\_webapp/](https://shonfeder.gitlab.io/ocaml_webapp/)  
Seriously if there were more tutorials like this the OCaml community would have been times bigger, they are so helpful when starting out and you don’t want to solve the same problem everyone else has already solved.  
And then implemented parts of it in JS and F#

the tests:  
1st just renders html, with no DB calls whatsoever  
2nd:

- queries a DB
- adds an additional item to the result
- orders the list
- returns the result as JSON

I ran each test 3 times and posted the best result

This is not a scientific test using a controlled environment, this is a quick and dirty test, so take it with a bit of salt (but in many ways the results are not so unexpected). The tests are also not comparing the languages themselves but a combination of some of the more popular libraries of them, which is how you would normally use them.

EDIT: adding a link to the code: [https://gitlab.com/mudrz/ocaml-web-benchmarks/-/tree/master](https://gitlab.com/mudrz/ocaml-web-benchmarks/-/tree/master)

The tests were made with `wrk -t8 -c400 -d30s` - 8 threads, 400 connections, 30 seconds;

```auto
  HTML endpoint, no DB access

```

JS - single process

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 44.16ms 4.73ms 59.22ms 88.44%
    Req/Sec 1.10k 89.00 1.50k 82.83%
  262651 requests in 30.05s, 179.60MB read
  Socket errors: connect 0, read 264, write 0, timeout 0
Requests/sec: 8739.98
Transfer/sec: 5.98MB

```

JS - multiple processes

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 43.37ms 56.91ms 316.27ms 83.49%
    Req/Sec 2.43k 459.80 3.81k 73.25%
  580742 requests in 30.05s, 397.10MB read
  Socket errors: connect 0, read 239, write 0, timeout 0
Requests/sec: 19325.95
Transfer/sec: 13.21MB

```

OCaml - single process

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 15.01ms 2.28ms 39.86ms 89.00%
    Req/Sec 3.27k 240.86 4.53k 89.83%
  781313 requests in 30.01s, 489.54MB read
  Socket errors: connect 0, read 308, write 0, timeout 0
Requests/sec: 26031.65
Transfer/sec: 16.31MB

```

F#

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 5.46ms 840.10us 20.34ms 83.20%
    Req/Sec 8.91k 659.89 13.27k 73.25%
  2130565 requests in 30.04s, 1.45GB read
  Socket errors: connect 0, read 272, write 0, timeout 0
Requests/sec: 70923.15
Transfer/sec: 49.31MB

```

Results:

- OCaml: 1.34x more requests/s than JS, with 2.8x less latency
- F#: 3.66x more than JS, 2.7x more requests/s than OCaml, with 2.7x less latency

* * *

```auto
  JSON endpoint, DB access

```

The JSON response for JS and OCaml was:

```auto
{"excerpts":[{"author":"kan","excerpt":"Another excerpt","source":"My source2","page":"another page"},{"author":"kan","excerpt":"My excerpt","source":"my source","page":"23"}]}

```

for F# it was slightly longer since option types are serialized by default with a Some/None variant (it can be changed):

```auto
{"excerpts":[{"author":"kan","excerpt":"Another excerpt","source":"My source2","page":{"case":"Some","fields":["another page"]}},{"author":"kan","excerpt":"My excerpt","source":"my source","page":{"case":"Some","fields":["23"]}},{"author":"a","excerpt":"b","source":"c","page":{"case":"Some","fields":["d"]}}]}

```

The DB was Postgres with 10 max connections

JS - single process

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 57.79ms 5.68ms 88.02ms 85.24%
    Req/Sec 848.20 109.95 1.37k 72.24%
  202885 requests in 30.09s, 62.69MB read
  Socket errors: connect 0, read 237, write 0, timeout 0
Requests/sec: 6742.09
Transfer/sec: 2.08MB

```

JS - multiple processes

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 57.48ms 61.84ms 774.03ms 83.36%
    Req/Sec 1.20k 260.84 2.29k 71.38%
  287101 requests in 30.04s, 88.71MB read
  Socket errors: connect 0, read 286, write 38, timeout 0
Requests/sec: 9558.04
Transfer/sec: 2.95MB

```

OCaml

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 6.69ms 38.78ms 1.07s 98.17%
    Req/Sec 1.78k 842.50 3.62k 56.33%
  424454 requests in 30.02s, 100.39MB read
  Socket errors: connect 0, read 253, write 0, timeout 13
Requests/sec: 14139.42
Transfer/sec: 3.34MB

```

F#

```auto
  Thread Stats Avg Stdev Max +/- Stdev
    Latency 19.27ms 3.92ms 107.53ms 82.60%
    Req/Sec 2.54k 165.82 3.26k 79.21%
  606868 requests in 30.02s, 261.02MB read
  Socket errors: connect 0, read 259, write 0, timeout 0
Requests/sec: 20214.71
Transfer/sec: 8.69MB

```

Results:

- OCaml: 1.48x more requests/s than JS (up from 1.34x before), with 8.6x less latency (before: 2.7x)
- F#: 2.1x more than JS (down from 3.66x before), 1.43x more requests/s than OCaml (down from 2.7x before), with 2.88x MORE latency than OCaml (before: 2.7x LESS than OCaml)

Observations:

- JS is performing unexpectedly good compared to compiled languages
- F# (or [ASP.NET](http://ASP.NET) Core) is really fast out of the box, with no tweaking necessary
- OCaml is running on a single process and has had Max request time of `1.07s` and Stdev 10x that of F#; in some tests it spiked to 2seconds for some requests, is this the GC? how can I troubleshoot that?

* * *

Is there a good tutorial on running OCaml with multiple processes and generally commonly faced use cases for web servers?  
There are countless articles for the other ecosystems, but it is a bit difficult to find ones for OCaml, making it a bit time consuming to try to figure each thing out

---

_[View the full topic](https://discuss.ocaml.org/t/ocaml-web-server-run-multiple-processes/6408)._
