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

Performance and feature comparison

Every number and every cell on this page is measured, not quoted from documentation: the same benchmark harness drives the same live exchange against each product running unmodified in its own container, and the feature matrix comes from the live interop verification runs. Tested versions are listed; newer releases may differ.

Benchmark

Scenario: the exchange profile every tested product supports — payload signed (RSA / SHA-256) and encrypted (AES-256-CBC), synchronous signed MDN, MIC reconciliation. One uniform sender (the as2d client) drives each receiver; latency is the full exchange as a partner experiences it: packaging, POST, the receiver’s decrypt/verify/store, MDN generation, and receipt verification.

Method: 100 messages per payload size after warmup, 4 concurrent senders, containerized receivers with their default configurations, all on the same host (a 12th-gen Intel i7-12700H laptop, NVMe SSD, Linux). Receivers were benchmarked one at a time. Results from 2026-08-26; raw data and the harness ship in the as2d source tree, so the run is reproducible.

Receiver1 KiB msgs/s1 KiB p50 ms1 KiB p95 ms64 KiB msgs/s64 KiB p50 ms64 KiB p95 ms1 MiB msgs/s1 MiB p50 ms1 MiB p95 ms
as2d30612.716.627914.018.412531.635.0
phase223514.630.416623.529.727.8143153
openas230812.818.933811.414.773.753.064.7
mendelson37.310118133.21181905.557111109
pyas299.236.171.667.456.988.516.4239319
waarp-as26705.778.305207.779.8214826.631.1
ruby-as215824.539.815425.933.685.446.058.5
node-libas271.955.663.253.673.185.4

Reading notes:

  • What “durable” costs. as2d’s numbers include per-message durable state writes — replay-protection and journal entries are fsynced to disk before the receipt is acknowledged, because an acknowledged message must survive a crash. Products differ in what they persist before acknowledging, and this benchmark does not normalize that.
  • as2d is nearly size-insensitive: median latency rises only 13 ms → 32 ms from 1 KiB to 1 MiB. It is the fastest receiver measured at every payload size except the Go implementation — while being the only product in the table whose numbers include fsyncing the payload, replay-protection state, and the journal before acknowledging (at 1 MiB it is still 4× phase2 and 22× mendelson CE).
  • The crypto runtime matters as much as the product. as2d’s own container numbers doubled just by moving its base image from OpenSSL 3.0 to 3.5 (3.0’s per-operation algorithm-fetch locking is a known cost under concurrent CMS load that microbenchmarks like openssl speed do not show). If you run any AS2 product on an OpenSSL-3.0-era distribution, you are likely paying this too.
  • Waarp AS2 (Go) is the fastest receiver at small payloads; at 1 MiB it and as2d are effectively tied at the top.
  • node-libas2 failed every 1 MiB exchange under load (it returned MDNs with no disposition field), hence the dashes — consistent with the library’s frozen 2020-era dependency set.
  • Java products show their strength at small payloads once the JIT is warm (OpenAS2, phase2) but fall off steeply at 1 MiB.

Scaling under load

The same exchange at 16 concurrent senders: as2d’s durable writes batch across in-flight messages (group commit), so throughput scales near-linearly — 981 msg/s at 1 KiB, 800 msg/s at 64 KiB, and at 1 MiB it matches the fastest non-durable implementation measured (335 vs 342 msg/s) while fsyncing every payload before acknowledging it.

Feature matrix

As measured in the live interop rig (both directions, receipt reconciliation) — ✔ works as specified, ◐ works with caveats (see the per-product notes), ✘ not supported by that product.

Capabilityas2dphase2 (as2-lib)OpenAS2 4.10mendelson CE 1.1b69pyas2lib 1.4.4Waarp AS2Ruby as2 0.12node-libas2 0.8.2
Signing SHA-2 family
RSASSA-PSS signatures
AES-CBC / 3DES encryption
AES-GCM (RFC 5084 conformant)✘ rejects✘ rejects
AES-GCM (BC-compatible form)✔ receive + per-partner send✔ (its native form)✘ rejects
ZLIB compression (RFC 5402)
Sync signed MDN generation◐ broken upstream (sends unsigned)
Async MDN delivery
Honors requested receipt digest✘ always SHA-256✘ uses signature digest
Binary (raw) S/MIME bodies✘ base64 required
Enforces inbound security floor✔ (insufficient-message-security)✔ (requires signed+encrypted, always)

✘ is only used where the limitation was directly measured or is the product’s own documented constraint; — means the capability was not exercised against that product in the rig and is left unclaimed rather than assumed either way.

A note on fairness. These are open-source products measured under their own default configurations in containers; each of them may be tunable beyond what defaults deliver, and all of them interoperate correctly with as2d in the profiles above — that is the point of the interop rig. The benchmark answers one question honestly: what does the same exchange cost against each receiver, out of the box, on the same hardware.