Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Actor HTTP TLS comparison

Current matched measurements for std.http.server and std.actor.http.server. The actor qualification record retains the original comparison and the platform limits.

Measured on 2026-11-01 at source revision c397a845, after the private TLS configuration reconstruction (issue #641) and completion-credit changes (issue #644). The raw results and replay sources retain all samples, source fixtures, the driver, a reproduction script, an independent validation script, compiler/native hashes and machine load snapshots. Compiler SHA-256: 13c6ed9514305a6d67592417265034555283bb7e8635188dcddc77091c907aa6. The compiler was built with cargo build --locked --bin plenty; native fixtures used --release --compile with PLENTY_CACHE=off.

The Ryzen 7 7840HS host ran Linux 7.2.11 x86-64 GNU/Linux. One worker and the single actor stage used CPU 0; four workers used physical cores 0, 2, 4 and 6. Clients used physical cores 8, 10, 12 and 14. Three rounds alternated worker/actor/four-worker order, reversing it in the middle round. Every workload started a fresh server, with 5,000 requests at the stated concurrency. All 270,000 measured requests completed with zero failures or missing responses. Idle measurements used 984 connections in each configuration. No task-local builds or search indexing ran during measurement; unrelated shared-host activity was uncontrolled. The host’s one-minute load average was 2.88 before and 2.72 after the complete run.

HTTPS throughput and latency

Median requests/second across three samples:

WorkloadOne worker / one coreActor / one coreFour workers / four cores
Small, 1 keep-alive client18,87625,95620,925
Small, 16 keep-alive clients21,87434,37989,255
Small, 64 keep-alive clients19,95528,64164,121
New connection, 16 clients3,7883,7944,465
16 KiB response, 16 clients14,27913,33251,283
1 KiB POST echo, 16 clients21,05130,17184,747

The actor leads the equal-core small-response and echo cases in these samples; one worker leads the 16 KiB case, and four worker cores have substantially higher concurrent throughput. New-connection throughput is nearly equal between the single-core configurations. This is a current comparison of the implementations, not an isolated before/after measurement of either fix.

Median sample p99 latency in milliseconds (new-connection latency includes TLS and the HTTP response):

WorkloadOne workerActorFour workers
Small, 1 keep-alive client0.0920.0640.085
Small, 16 keep-alive clients1.5760.5790.443
Small, 64 keep-alive clients28.13722.58319.484
New connection, 16 clients5.3135.3944.324
16 KiB response, 16 clients1.8171.4410.575
1 KiB POST echo, 16 clients0.9810.6290.367

The 64-client p99 values are high for all configurations. The three p99 samples range from 24.349–32.037 ms for one worker, 22.431–22.710 ms for the actor, and 16.729–24.064 ms for four workers. Short loopback runs on a shared host do not establish a service latency objective or sustained deployment capacity. ApacheBench drives keep-alive workloads; four parallel curl processes drive new connections, without certificate verification, as in the historical comparison.

TLS handshake and idle memory

A separate Python probe made 1,000 new connections at concurrency 16 per sample, three samples per configuration: 9,000 successful verified TLS handshakes and validated HTTP responses. It used one shared client SSL context loaded with the fixture CA. Every session negotiated TLS 1.3 with TLS_AES_256_GCM_SHA384 and reported no session reuse. Timing begins after TCP connect and ends when the client’s TLS handshake returns, before the HTTP request. It includes client verification, scheduling and library overhead; it does not isolate server CPU cost or prove that the server has consumed the client’s Finished message.

MeasurementOne workerActorFour workers
Median sample handshake p50, ms1.7823.6301.383
Median sample handshake p99, ms3.4895.4435.192
Median incremental idle RSS, KiB/connection41.1257.8041.42

The actor fixture uses 16.68 KiB more incremental idle RSS than one worker, including its private per-session configuration, for this ECDSA P-256 certificate fixture. This comparison does not isolate configuration memory from other actor overhead. Idle RSS is a process resident-memory difference with connection capacity raised to 1,000, not an actor heap high-water mark or a general heap-sizing recommendation. The historical 45.86 KiB actor TLS figure predates the ownership change. Different certificate chains, root sets, record sizes and application state need their own measurement.

TLS failures and recovery

A separate descriptive probe combined 32 stalled TLS request heads, four healthy clients and 100 intentional handler traps per batch. Across four actor batches, all 4,000 healthy requests and 400 post-batch recovery requests succeeded; all 400 trap requests ended without a successful response. Healthy-request p99, including TLS setup, ranged from 1.699 to 2.957 ms. After each batch RSS was 5,128 KiB and the descriptor count was six; before fault injection RSS was 5,124 KiB. Shutdown succeeded with exactly 4,501 completed requests (including 100 baseline requests and /stop), 400 trapped actors, zero rejected admissions and zero lost messages. Abrupt client TLS closes also increment actor failure counts; they do not mean those complete HTTP responses failed.

Both worker configurations completed their 100-request baselines, then exited with status 1 on the first handler trap; neither served recovery requests. This demonstrates the actor containment contract for these injected traps. It is one fault run per configuration, with a fixed root TLS configuration, not a configuration-rotation soak, an allocation-failure test, or a new platform qualification. The actor server’s production-readiness limits remain unchanged.

Replay from the recorded source revision with ApacheBench, curl, taskset and a compiler built there. Extract the scripts from this artifact before switching to that checkout, then pass its path and compiler to the replay script:

python3 - <<'PYREPLAY'
import json
from pathlib import Path
record = json.loads(Path("book/src/assets/actor-https-comparison.json").read_text())
Path("/tmp/actor-https-replay.py").write_text(record["reproduction_script"])
Path("/tmp/actor-https-validate.py").write_text(record["validation_script"])
PYREPLAY
TLS_CHECKOUT=/path/to/checkout-of-c397a845
python3 /tmp/actor-https-replay.py "$TLS_CHECKOUT" \
    "$TLS_CHECKOUT/target/debug/plenty" /tmp/actor-https-replayed
python3 /tmp/actor-https-validate.py /tmp/actor-https-replayed/results.json

Adapt CPU affinities to the host. Keep newly recorded results separate from the published artifact; numerical RSS stability and negotiated-cipher assertions in the validation script describe this fixture and platform, and may need adjustment elsewhere.