apache / apache/rocketmq

[Enhancement] Eliminate per-RPC allocation from Logback status, TopicMessageType toLowerCase, and RemotingHelper eager evaluation

Open
#10,490 3 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.