richardcocks opened a new pull request, #4076:
URL: https://github.com/apache/iggy/pull/4076

   Closes #4066
   
   ## Rationale
   
   Profiling the small-message hot path showed a large amount of time spent in 
generating message IDs. This was most noticeable in the Node SDK where it was 
impacting throughput severely.
   
   ## What changed?
   
   The SDKs were minting Ids by constructing UUIDv4 values and then 
transforming them to extract the 16 bytes the message IDs needed.  The message 
IDs are opaque bytes which do not need to match a UUID format, nor are they 
cryptographically sensitive.
   
   This updates the SDKs to generate bytes directly from faster random sources 
where available. 
   
   For Node, to achieve a fast throughput required a new random pool, which was 
fastest to fill from the CSPRNG, because the non-CSPRNG doesn't have any way to 
get a byte array from it. Other SDKs have PRNGs which are fast without the 
complexity of managing a pool.
   
   The Node path now throws on a numeric id ≥ 2¹²⁸ (via a new bound check in 
serializeMessageId), where the old hex round-trip silently truncated to a 
garbage value. This is in line with other SDKs. 
   
   ### Producer throughput — small (~6 B) messages
   
   `id=0` mint path, measured with my harness (`MODE=producer
   MSG_ID=uuid REPEAT=10 BITS=42`, TCP_NODELAY on, server + producer 
co-located).
   Mean messages/sec over 10 runs (stddev %).
   
   | SDK     | master (before)  | branch (after)   |            change |
   | :------ | ---------------: | ---------------: | ----------------: |
   | Node    |   196,809 (1.6%) |   528,076 (2.4%) | **+168% (2.68×)** |
   | Java    | 1,027,080 (6.5%) | 1,375,820 (9.1%) |        **+34.0%** |
   | C#\*    | 1,870,353 (5.5%) | 2,201,070 (9.8%) |        **+17.7%** |
   | Go      | 1,630,751 (8.2%) | 1,915,466 (9.4%) |        **+17.5%** |
   | Rust\*\*| 1,785,892 (6.7%) | 1,824,243 (8.3%) |      +2.1% (within noise)  
|
   
   \* C# Compiled with .NET 11 AOT, which emits warnings against the SDK's HTTP 
transport, which is unused. Both master and branch are compiled in the same way.
   
   \*\* Rust is a control: its mint path is unchanged, so the tie (within noise)
   confirms the harness attributes the other deltas to the code, not the 
machine.
   
   ### Producer throughput — ~1 KB messages
   
   Same test at a realistic payload (`pack=167` → 1,002-byte messages). Mean
   messages/sec over 10 runs (stddev %); the mint runs once per message, so its
   benefit shrinks as payloads grow.
   
   | SDK  | master (before) | branch (after)  |          change |
   | :--- | --------------: | --------------: | --------------: |
   | Node |   75,565 (3.4%) |  107,641 (2.2%) |    **+42.4%**   |
   | Java |  172,647 (5.1%) |  203,600 (4.1%) |    **+17.9%**   |
   | Go   |  368,275 (5.1%) |  384,620 (6.5%) |  +4.4% (noise)  |
   | C#   |  394,541 (4.5%) |  407,785 (4.0%) |  +3.4% (noise)  |
   | Rust\*  |  323,347 (7.4%) |  324,836 (10.1%)|   +0.5% (tie)   |
   
   The C# and Go results collapse to technically within noise, but given the 
single-message improvements is likely to be a real effect that I can't prove 
statistically without ~50 repeated runs for each branch.
   
   The Java and Node results are well above the noise floor.
   
   \* Rust is a control, unchanged between master and branch.
   
   Please do not try to compare languages, absolute throughput is not 
comparable across SDKs, each producer is different and are not comparable, the 
benchmarks are tuned for comparing differences across builds of the same SDK, 
not between languages or SDKs.
   
   ## AI Usage
   
   Claude Opus 4.8 was used extensively both for writing code, analysis of 
ideas, in benchmarking and in verification of results.
   Every line has been hand-reviewed and I fully understand the changes, the 
choices made and the rationale for those choices.
   
   Verification was mostly through end-to-end benchmarking tests which also 
verify correctness. Additional correctness tests and micro-benchmarks were 
scaffolded during development to check assumptions, some of which were out of 
scope of this PR and have been excluded. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to