[Enhancement] Eliminate per-RPC allocation from Logback status, TopicMessageType toLowerCase, and RemotingHelper eager evaluation
- Dominant language
- Java
- Stars
- 22.6k
- Forks
- 12k
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 27
Description
### Before Creating the Enhancement Request
- [x] I have confirmed that this should be classified as an enhancement rather than a bug/feature.
### Summary
Three independent per-RPC/per-metrics micro-allocations can be eliminated to reduce unnecessary heap pressure:
1. **Logback `BasicStatusManager`** — internal status events accumulate during XML configuration loading without being consumed.
2. **`TopicMessageType.getMetricsValue()`** — allocates a new `String` on every call via `value.toLowerCase()`.
3. **`RemotingHelper.getRequestCodeDesc()` / `getResponseCodeDesc()`** — eagerly evaluates `String.valueOf(code)` in `Map.getOrDefault()` even on cache hit.
### Motivation
JFR `settings=profile` on a broker under steady-state send load reveals these three allocation sites as recurring per-RPC waste:
- Logback status events (`InfoStatus`, `BodyEvent`) accumulate in `BasicStatusManager` retained set (~655 KiB) despite never being queried in production. Adding `NopStatusListener` suppresses the callback overhead.
- `TopicMessageType.getMetricsValue()` is called once per send for metrics labeling. The `toLowerCase()` result is deterministic per enum constant — caching it in the constructor avoids ~1 String + 1 byte[] per RPC.
- `RemotingHelper.getRequestCodeDesc()` and `getResponseCodeDesc()` are called per RPC response. Java eagerly evaluates `String.valueOf(code)` as a method argument to `Map.getOrDefault()`, allocating a String even when the key exists in the map. A simple `get()` + null check eliminates this on the hot (cache-hit) path.
Combined, these save ~200–300 bytes per RPC with zero behavioral change.
### Describe the Solution Youd Like
1. **Logback**: Add `` after `` in `rmq.broker.logback.xml`.
2. **TopicMessageType**: Cache `metricsValue` as a `final String` field initialized in the enum constructor with `Locale.ROOT`. The getter returns the cached reference directly.
3. **RemotingHelper**: Replace `REQUEST_CODE_MAP.getOrDefault(code, String.valueOf(code))` with:
```java
String desc = REQUEST_CODE_MAP.get(code);
return desc != null ? desc : String.valueOf(code);
```
Same pattern for `RESPONSE_CODE_MAP`.
### Describe Alternatives Youve Considered
- **Removing NopStatusListener**: Considered using a conditional listener or `loggerContext.getStatusManager().clear()` in code. Rejected because the XML-level listener is simpler and doesnt require broker startup changes.
- **`String.intern()` for metrics values**: Rejected due to global String table contention and lack of locale control.
- **`computeIfAbsent` for RemotingHelper**: Overkill — the map is a static `Map` populated at class load time. A null check is simpler and avoids lambda allocation.
### Additional Context
PR: https://github.com/apache/rocketmq/pull/10491
This PR is stacked on PR #10443 (AttributeKey statics) and will be rebased on `develop` after #10443 merges to show only the 3 files above.
Contributor guide
Research direction
Review PR #10491 and the three named entry points: rmq.broker.logback.xml, TopicMessageType.getMetricsValue(), and RemotingHelper.getRequestCodeDesc()/getResponseCodeDesc(). Confirm that the requested allocation reductions preserve behavior and remain limited to the configuration, enum, and helper updates; no tests are named in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend, performance
- Issue type
- Refactor
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100