From b957b9a22834ec15b69ca50bc8afef37d87eedd8 Mon Sep 17 00:00:00 2001 From: Chris M Date: Tue, 3 Nov 2026 12:25:39 -0700 Subject: [PATCH 1/3] morojs: MoroJS 1.8.21 on @morojs/engine 1.1.17 - TLS on the engine's own BIOs The three TLS profiles were the entry's whole HTTP/1.1 deficit: json-tls 569 and 8gbit 771 of a thousand against 749 and 869 for the leading uWebSockets.js entries, with every plaintext profile led or tied. @morojs/engine 1.1.17 terminates TLS on its own BIOs instead of BIO_s_mem pairs: the read side is a view over the transport's buffer (one copy in, where the memory BIO added a second), the write side appends ciphertext straight into the buffer the transport sends from (the memory BIO grew by copying, was copied out of, and zeroed its capacity on every reset), and a body over 8 KiB is encrypted from the caller's bytes rather than copied behind the head first. The ciphertext scratch is kept between replies, so a static file's worth of pages is no longer faulted in and zeroed per reply. MoroJS 1.8.21 revalidates a cached static file once per window instead of once per request crossing it: at 1024 keep-alive connections the old behaviour stat'ed the file and both sidecar positions on the threadpool for every request that crossed the second. Measured at one worker, same machine, CPU per request from the cgroup: the static-tls mix 39 us to 28, the json-tls mix 22.5 to 19, the 8gbit echo 150 to 127; the leading uWebSockets.js entry measures 28-32, 19-20 and 132 on the same rig. The dependency floor moves to 1.8.21 so a build never measures the older path by resolving a cached package. --- frameworks/morojs/README.md | 8 ++++++-- frameworks/morojs/package.json | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frameworks/morojs/README.md b/frameworks/morojs/README.md index e7b8bd040..62dfe8af7 100644 --- a/frameworks/morojs/README.md +++ b/frameworks/morojs/README.md @@ -6,7 +6,7 @@ MoroJS on its native HTTP engine, clustered by the framework itself. - **Language:** JavaScript - **Runtime:** Node.js 26 -- **Framework:** [MoroJS 1.8](https://github.com/Moro-JS/moro) on `@morojs/engine` 1.1.16, its own native HTTP engine +- **Framework:** [MoroJS 1.8](https://github.com/Moro-JS/moro) on `@morojs/engine` 1.1.17, its own native HTTP engine - **Build:** Multi-stage on `node:26.13-trixie-slim` (pinned by minor: the compression middleware's reused brotli encoder needs Node 26.11 or later, and the bench host builds against whatever `node:26` it has cached); the engine ships prebuilt binaries, so no toolchain @@ -63,7 +63,11 @@ MoroJS on its native HTTP engine, clustered by the framework itself. file reads of every worker thread in the process; Moro sets 64 itself but only at `listen()`, after its startup has initialised the pool at Node's default of 4, and Node reads the variable only at process start. -- `json-tls`, `static-tls` and `8gbit` listen on `8081` behind the engine's own TLS listener +- `json-tls`, `static-tls` and `8gbit` listen on `8081` behind the engine's own TLS listener. The + engine terminates TLS on its own OpenSSL BIOs (1.1.17): one copy in, ciphertext appended straight + into the buffer it sends from, and a body over 8 KiB encrypted from the caller's bytes rather than + copied behind the head first. Measured at one worker on these three request mixes, CPU per request + fell by a fifth on the static files, a seventh on the JSON bodies and a sixth on the 100 KB echo. (TLS 1.3, ALPN `http/1.1`), when `/certs/server.crt` and `/certs/server.key` are mounted. Moro locks one configuration per process, so that listener is a second process running the same file with `MORO_ROLE=tls`, clustered the same way; it is not started when the certificates are absent. diff --git a/frameworks/morojs/package.json b/frameworks/morojs/package.json index 4ea598ec6..bf6c19f5a 100644 --- a/frameworks/morojs/package.json +++ b/frameworks/morojs/package.json @@ -2,7 +2,7 @@ "name": "httparena-morojs", "private": true, "dependencies": { - "@morojs/moro": "^1.8.20", + "@morojs/moro": "^1.8.21", "ejs": "^3.1.10", "pg": "^8.16.3", "redis": "^5.0.0" From a6c6c78a25442721e44253d852c320e15d42f93d Mon Sep 17 00:00:00 2001 From: Chris M Date: Tue, 3 Nov 2026 12:26:12 -0700 Subject: [PATCH 2/3] morojs: README - the TLS note at the end of its bullet --- frameworks/morojs/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frameworks/morojs/README.md b/frameworks/morojs/README.md index 62dfe8af7..48364edb7 100644 --- a/frameworks/morojs/README.md +++ b/frameworks/morojs/README.md @@ -63,14 +63,14 @@ MoroJS on its native HTTP engine, clustered by the framework itself. file reads of every worker thread in the process; Moro sets 64 itself but only at `listen()`, after its startup has initialised the pool at Node's default of 4, and Node reads the variable only at process start. -- `json-tls`, `static-tls` and `8gbit` listen on `8081` behind the engine's own TLS listener. The +- `json-tls`, `static-tls` and `8gbit` listen on `8081` behind the engine's own TLS listener + (TLS 1.3, ALPN `http/1.1`), when `/certs/server.crt` and `/certs/server.key` are mounted. Moro + locks one configuration per process, so that listener is a second process running the same file + with `MORO_ROLE=tls`, clustered the same way; it is not started when the certificates are absent. The engine terminates TLS on its own OpenSSL BIOs (1.1.17): one copy in, ciphertext appended straight into the buffer it sends from, and a body over 8 KiB encrypted from the caller's bytes rather than copied behind the head first. Measured at one worker on these three request mixes, CPU per request fell by a fifth on the static files, a seventh on the JSON bodies and a sixth on the 100 KB echo. - (TLS 1.3, ALPN `http/1.1`), when `/certs/server.crt` and `/certs/server.key` are mounted. Moro - locks one configuration per process, so that listener is a second process running the same file - with `MORO_ROLE=tls`, clustered the same way; it is not started when the certificates are absent. - `tls_check` is opted into: a third process of the same file (`MORO_ROLE=tlscheck`) listens on `9000` reading `/certs-tls`, with `server.ssl.watch: true`, so a pair replaced on disk is validated and swapped onto the running listener without a restart and without touching From 3a20dab1f8c1a48deb0c870ec46241b5859576a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Nov 2026 18:37:32 +0000 Subject: [PATCH 3/3] Benchmark results: morojs json-tls,8gbit,static-tls [skip ci] --- site/data/results/morojs.json | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/site/data/results/morojs.json b/site/data/results/morojs.json index 9784dcbf6..83f0fce51 100644 --- a/site/data/results/morojs.json +++ b/site/data/results/morojs.json @@ -4,27 +4,27 @@ "8gbit-512": { "framework": "morojs", "language": "JS", - "rps": 49365, - "avg_latency": "108.7us", - "p99_latency": "157.0us", - "cpu": "323.7%", + "rps": 49301, + "avg_latency": "110.8us", + "p99_latency": "141.0us", + "cpu": "298.7%", "memory": "9.3GiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "511.37MB/s", - "input_bw": "482.08MB/s", + "bandwidth": "510.71MB/s", + "input_bw": "481.46MB/s", "reconnects": 0, - "status_2xx": 246889, + "status_2xx": 246579, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "cpu_usec": 17507161, - "cpu_per_req_us": 70.9111, + "cpu_usec": 16278174, + "cpu_per_req_us": 66.0161, "target_rate": 50000, - "rate_ratio": 0.9873, - "p99_9_latency": "2785.0us" + "rate_ratio": 0.986, + "p99_9_latency": "7434.0us" }, "async-32000": { "framework": "morojs", @@ -529,18 +529,18 @@ "json-tls-4096": { "framework": "morojs", "language": "JS", - "rps": 925942, - "avg_latency": "4.40ms", - "p99_latency": "46.70ms", - "cpu": "6611.1%", - "memory": "9.1GiB", + "rps": 1045809, + "avg_latency": "3.89ms", + "p99_latency": "42.10ms", + "cpu": "6580.6%", + "memory": "8.9GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "3.13GB", + "bandwidth": "3.53GB", "reconnects": 0, - "status_2xx": 4721874, + "status_2xx": 5333484, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -745,18 +745,18 @@ "static-tls-1024": { "framework": "morojs", "language": "JS", - "rps": 364052, - "avg_latency": "2.88ms", - "p99_latency": "31.04ms", - "cpu": "6433.8%", + "rps": 781829, + "avg_latency": "1.31ms", + "p99_latency": "18.52ms", + "cpu": "6533.2%", "memory": "8.6GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "5.61GB", + "bandwidth": "12.04GB", "reconnects": 0, - "status_2xx": 1856620, + "status_2xx": 3986968, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0