Skip to content

[ISSUE #10522] Reduce Remoting header encoding allocation via FastCodesHeader/RocketMQSerializable optimizations#10524

Open
wang-jiahua wants to merge 1 commit into
apache:developfrom
wang-jiahua:perf/fastcodes-header-interface
Open

[ISSUE #10522] Reduce Remoting header encoding allocation via FastCodesHeader/RocketMQSerializable optimizations#10524
wang-jiahua wants to merge 1 commit into
apache:developfrom
wang-jiahua:perf/fastcodes-header-interface

Conversation

@wang-jiahua

@wang-jiahua wang-jiahua commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Which Issue(s) This PR Fixes

Fixes #10522

Brief Description

Enhance FastCodesHeader interface and RocketMQSerializable utility to reduce allocation and CPU overhead in the Remoting header encoding/decoding hot path.

FastCodesHeader.java

  • Optimize writeIfNotNull to route Long/Integer values through writeDecimalLong/writeDecimalInt instead of value.toString() + writeStr, eliminating transient String allocation.
  • Add writeLong(ByteBuf, String, long) and writeInt(ByteBuf, String, int) helper methods for direct primitive encoding.

RocketMQSerializable.java

  • Add writeDecimalLong(ByteBuf, long) and writeDecimalInt(ByteBuf, int) — write decimal numbers directly to ByteBuf without String.valueOf() allocation.
  • Add SINGLE_BYTE_STRINGS cache (128 entries) — readStr returns cached String for single-byte ASCII values instead of creating new String via readCharSequence.
  • Right-size mapDeserialize initial HashMap capacity from 128 to 24 — typical headers have 5-15 entries, 128 causes unnecessary memory waste.

All changes are additive — no existing method signatures are modified.

How Did You Test This Change?

1. Unit tests

mvn test -pl remoting -Dtest=RocketMQSerializableTest,FastCodesHeaderTest
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0

2. A/B benchmark (256 threads, 1KB sync send, Dragonwell JDK 21, 6g heap)

Metric Baseline (develop) Optimized (R1) Change
TPS ~196k ~236k +20.6%
p99 RT 3ms 2ms -33%
Average RT 1.307ms 1.085ms -17.0%
Max RT 594ms 351ms -40.9%
Young GCs (total) 336 304 -9.5%

3. Commercial compatibility

  • Pure additive changes — no existing API signatures modified.
  • No commercial classes implement FastCodesHeader.
  • Commercial YitianRemotingCommand calls RocketMQSerializable.rocketMQProtocolDecode/Encode which are unchanged.

Copilot AI review requested due to automatic review settings June 17, 2026 10:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR optimizes remoting header serialization/deserialization by adding fast-path encoding for numeric values and single-byte strings, and tweaks map allocation to reduce overhead.

Changes:

  • Add decimal (ASCII) serialization helpers for int/long values written into a ByteBuf.
  • Add a cached fast-path for reading 1-byte UTF-8 strings (ASCII) to avoid allocations/decoding overhead.
  • Update header encoding to use the new decimal writers for Long/Integer values and adjust HashMap initial capacity.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java Adds decimal numeric writers, single-byte string cache/fast-path, and updates deserialization map pre-sizing.
remoting/src/main/java/org/apache/rocketmq/remoting/protocol/FastCodesHeader.java Uses new decimal writers for Long/Integer fields and introduces typed writeLong/writeInt helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…astCodesHeader/RocketMQSerializable optimizations

- Add writeDecimalLong/writeDecimalInt to RocketMQSerializable for direct primitive decimal encoding

- Add writeLong/writeInt helpers to FastCodesHeader

- Optimize writeIfNotNull to route Long/Integer through primitive writers

- Cache single-byte ASCII strings in RocketMQSerializable.readStr

- Right-size HashMap initial capacity in mapDeserialize (128 -> 24)
@wang-jiahua wang-jiahua force-pushed the perf/fastcodes-header-interface branch from e7659fa to 9a009d9 Compare June 17, 2026 10:17

@RockteMQ-AI RockteMQ-AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by github-manager-bot

Summary

This PR optimizes the Remoting header encoding/decoding hot path by eliminating transient String allocations for numeric values and adding a single-byte ASCII string cache. The changes are purely additive with impressive benchmark results (+20.6% TPS, -33% p99 RT).

Findings

  • [Positive] FastCodesHeader.java:41-47 — Routing Long/Integer through writeDecimalLong/writeDecimalInt instead of value.toString() + writeStr is a clean and effective allocation elimination. The instanceof branching cost is negligible compared to the allocation savings on the hot path.

  • [Positive] RocketMQSerializable.java writeDecimalLong/writeDecimalInt — The Long.MIN_VALUE / Integer.MIN_VALUE edge cases are correctly handled by dividing by 10 first and appending the last digit, avoiding the overflow that -value would cause. Well done.

  • [Positive] SINGLE_BYTE_STRINGS cache — 128-entry ASCII cache is a good trade-off: ~5-6KB static memory vs. avoiding new String() for the most common single-byte header values. The readStr fast path (len == 1 && b >= 0) is correct for UTF-8 single-byte range.

  • [Positive] mapDeserialize capacity 128 → 24 — Good observation. Typical headers have 5-15 entries; 128 was wasteful. With load factor 0.75, capacity 24 supports 18 entries before resize, which covers the common case.

  • [Info] FastCodesHeader.java:41 — Consider reordering the instanceof checks to test String first (most common header value type), then Long, then Integer. This avoids two unnecessary type checks for the majority of calls. Minor optimization, non-blocking.

if (value instanceof String) {
    RocketMQSerializable.writeStr(out, false, (String) value);
} else if (value instanceof Long) {
    RocketMQSerializable.writeDecimalLong(out, (Long) value);
} else if (value instanceof Integer) {
    RocketMQSerializable.writeDecimalInt(out, (Integer) value);
} else {
    RocketMQSerializable.writeStr(out, false, value.toString());
}
  • [Info] writePositiveDigits uses a two-pass approach (count digits, then write). An alternative is a pre-allocated digit lookup table indexed by value, but the current approach is clean and the performance difference is negligible for numbers up to 19 digits.

Compatibility

  • All changes are additive — no existing method signatures modified.
  • New default methods in FastCodesHeader interface do not break existing implementations.
  • SINGLE_BYTE_STRINGS is a private static field with no external visibility.
  • Wire format is unchanged: writeDecimalLong/writeDecimalInt produce the same byte output as writeStr(out, false, String.valueOf(value)).

Tests

  • Unit tests cover RocketMQSerializable and FastCodesHeader directly.
  • Benchmark data is well-documented with clear before/after comparison.
  • Consider adding an edge-case test for writeDecimalLong(Long.MIN_VALUE) and writeDecimalInt(Integer.MIN_VALUE) to prevent regression of the overflow handling.

Automated review by github-manager-bot

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 7.35294% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.07%. Comparing base (59a70d9) to head (9a009d9).
⚠️ Report is 3 commits behind head on develop.

Files with missing lines Patch % Lines
...cketmq/remoting/protocol/RocketMQSerializable.java 8.77% 51 Missing and 1 partial ⚠️
...he/rocketmq/remoting/protocol/FastCodesHeader.java 0.00% 11 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop   #10524      +/-   ##
=============================================
- Coverage      48.19%   48.07%   -0.12%     
+ Complexity     13394    13376      -18     
=============================================
  Files           1377     1377              
  Lines         100730   100801      +71     
  Branches       13012    13029      +17     
=============================================
- Hits           48542    48459      -83     
- Misses         46254    46400     +146     
- Partials        5934     5942       +8     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Reduce Remoting header encoding allocation via FastCodesHeader/RocketMQSerializable optimizations

4 participants