[ISSUE #10441] Reduce per-RPC allocation in metrics by caching static AttributeKey instances#10443
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR focuses on reducing allocation/CPU overhead on metrics and remoting hot paths by introducing AttributeKey singletons and adding small caches for frequently repeated attribute/metric lookups.
Changes:
- Added fast-path caching for remoting request/response code distribution counting.
- Introduced typed OpenTelemetry
AttributeKeyconstants and attribute caching/build helpers in remoting and broker metrics. - Reduced repeated string allocations (e.g., cached lowercase metrics value, avoided
Map.getOrDefaultboxing paths).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| remoting/src/main/java/org/apache/rocketmq/remoting/netty/RemotingCodeDistributionHandler.java | Adds “last code” fast path to reduce map lookups for hot request/response codes. |
| remoting/src/main/java/org/apache/rocketmq/remoting/metrics/RemotingMetricsManager.java | Adds attribute caching and typed label keys to reduce OpenTelemetry attribute overhead. |
| remoting/src/main/java/org/apache/rocketmq/remoting/metrics/RemotingMetricsConstant.java | Introduces typed AttributeKey singletons for labels. |
| remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java | Minor optimization to avoid getOrDefault overhead for code descriptions. |
| common/src/main/java/org/apache/rocketmq/common/attribute/TopicMessageType.java | Caches lowercase metrics value to avoid repeated conversions. |
| broker/src/main/resources/rmq.broker.logback.xml | Suppresses Logback status output via NopStatusListener. |
| broker/src/main/java/org/apache/rocketmq/broker/metrics/PopMetricsManager.java | Switches to typed label keys for attributes. |
| broker/src/main/java/org/apache/rocketmq/broker/metrics/BrokerMetricsManager.java | Adds topic attributes cache and switches to typed label keys. |
| broker/src/main/java/org/apache/rocketmq/broker/metrics/BrokerMetricsConstant.java | Introduces typed AttributeKey singletons for broker metrics labels. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
607c58a to
52c49e8
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #10443 +/- ##
=============================================
- Coverage 48.13% 48.11% -0.03%
+ Complexity 13379 13375 -4
=============================================
Files 1377 1377
Lines 100730 100749 +19
Branches 13012 13012
=============================================
- Hits 48491 48480 -11
- Misses 46300 46319 +19
- Partials 5939 5950 +11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
oss-sentinel-ai
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
This PR caches OpenTelemetry AttributeKey instances as static finals to avoid per-RPC allocation, optimizes TopicMessageType lookup, adds a volatile inline cache for RemotingCodeDistributionHandler, and adds Logback NopStatusListener to suppress startup log noise.
Findings
- [Good] BrokerMetricsConstant.java:69-86 — Pre-built typed
AttributeKeysingletons eliminate per-call allocation on the metrics hot path. - [Good] BrokerMetricsManager.java:105-120 — Import changes correctly reference the new cached keys.
- [Good] RemotingCodeDistributionHandler.java:35-68 — Volatile inline cache pattern correctly avoids
ConcurrentHashMap.computeIfAbsent()on repeated request codes. - [Good] TopicMessageType.java — Enum-based lookup is more efficient than string comparison.
- [Good] rmq.broker.logback.xml —
NopStatusListenersuppresses Logback startup noise in production.
Suggestions
- The volatile inline cache pattern in
RemotingCodeDistributionHandleris effective for sequential workloads. Consider documenting that this optimization assumes temporal locality in request codes. - Consider adding a microbenchmark to quantify the allocation reduction.
Verdict
✅ Approved — Solid performance optimization with clean implementation.
Automated review by github-manager-bot
994bf3d to
8eeec77
Compare
8eeec77 to
f8e69a4
Compare
… metrics hot path Builds on top of PR apache#10443 (which introduces the typed AttributeKey constants). After AttributeKey instances are de-duplicated, the next allocation hot spot in the metrics path is the Attributes object itself. For repeated parameter combinations the broker keeps rebuilding identical immutable Attributes (each ~200-300 byte). This commit introduces a two-level cache (volatile inline cache + ConcurrentHashMap fallback) at three points: - BrokerMetricsManager.getOrBuildTopicAttributes(topic, msgType, isSystem): 4-field volatile inline cache + CHM keyed by 'topic|msgType|isSystem'. - RemotingMetricsManager.getOrBuildAttributes(reqCode, respCode, isLongPolling, result): long-packed cache key (35 bits across 4 args, no String allocation), volatile inline cache + CHM. Falls back to direct build for unknown result values. - RemotingCodeDistributionHandler: replace two independent volatile fields (lastCode, lastAdder) with an immutable CachedCounter holder published through a single volatile reference. A single volatile read per inc() returns a self-consistent (code, adder) snapshot, eliminating a torn-read between the two fields under @sharable concurrent access from multiple Netty EventLoop threads.
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Pre-builds AttributeKey singletons as static constants in BrokerMetricsConstant and updates all call sites to use them, eliminating per-RPC allocation of InternalAttributeKeyImpl objects.
Findings
- [Critical]
BrokerMetricsConstant.java:69-83— All 15AttributeKeysingletons are correctly typed (stringKeyfor String labels,booleanKeyfor boolean labels). Each call toAttributeKey.stringKey("name")creates a new object; caching eliminates this per-RPC allocation. - [Critical]
BrokerMetricsManager.java,PopMetricsManager.java,RemotingMetricsManager.java— All call sites consistently updated to use the cached keys. No remainingAttributeKey.stringKey()calls on hot paths. - [Info]
RemotingMetricsManager.java:125-135— ThenewAttributes()helper now uses cached keys. This is called on every RPC completion, so the savings are proportional to RPC throughput.
Suggestions
No concerns. This is a straightforward, low-risk optimization with clear benefits on high-throughput brokers.
Verdict: LGTM. Clean optimization with consistent application across all metrics call sites.
Automated review by github-manager-bot
…static AttributeKey instances
f8e69a4 to
393393a
Compare
… metrics hot path Builds on top of PR apache#10443 (which introduces the typed AttributeKey constants). After AttributeKey instances are de-duplicated, the next allocation hot spot in the metrics path is the Attributes object itself. For repeated parameter combinations the broker keeps rebuilding identical immutable Attributes (each ~200-300 byte). This commit introduces a two-level cache (volatile inline cache + ConcurrentHashMap fallback) at three points: - BrokerMetricsManager.getOrBuildTopicAttributes(topic, msgType, isSystem): 4-field volatile inline cache + CHM keyed by 'topic|msgType|isSystem'. - RemotingMetricsManager.getOrBuildAttributes(reqCode, respCode, isLongPolling, result): long-packed cache key (35 bits across 4 args, no String allocation), volatile inline cache + CHM. Falls back to direct build for unknown result values. - RemotingCodeDistributionHandler: replace two independent volatile fields (lastCode, lastAdder) with an immutable CachedCounter holder published through a single volatile reference. A single volatile read per inc() returns a self-consistent (code, adder) snapshot, eliminating a torn-read between the two fields under @sharable concurrent access from multiple Netty EventLoop threads.
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Introduces pre-built static final AttributeKey<T> singletons in BrokerMetricsConstant and RemotingMetricsConstant, then replaces all AttributesBuilder.put(String, T) calls with typed put(AttributeKey<T>, T) overloads in BrokerMetricsManager, PopMetricsManager, and RemotingMetricsManager to eliminate per-RPC InternalAttributeKeyImpl allocations.
Findings
- [Info] JFR data cited in the issue (38,182 instances for 6 distinct keys) makes a strong case. The singleton pattern is the correct fix.
- [Info] All call sites consistently use the typed
put(AttributeKey<T>, T)overload — no mixed usage detected. - [Info] The
LABEL_INVOCATION_STATUS_KEYusesAttributeKey.stringKey()which is correct sinceInvocationStatusis stored as its.name()String. - [Warning]
PopMetricsManagerusesLABEL_CONSUMER_GROUP_KEYfor the group label — ensure this is the same semantic as the one inBrokerMetricsConstant(it is, but worth a comment for future maintainers).
Suggestions
- Minor: consider grouping the
LABEL_*_KEYconstants with a comment block explaining they are hot-path singletons, so future contributors don't accidentally remove "unused" constants.
No blocking issues. Solid, well-targeted optimization.
Automated review by github-manager-bot
Which Issue(s) This PR Fixes
Fixes #10441
Brief Description
Reduce per-RPC allocation by replacing reflective
AttributeKey.stringKey(name)/AttributeKey.booleanKey(name)calls with pre-built staticAttributeKey<T>singletons.JFR heap dump showed 38,182
InternalAttributeKeyImplinstances for only 6 distinct key names. EveryAttributesBuilder.put(String, T)call internally creates a freshAttributeKey— a stateless immutable object that should be a singleton.Define
static final AttributeKey<T> LABEL_*_KEYconstants inBrokerMetricsConstantandRemotingMetricsConstant, then migrate allput(String, T)callsites toput(AttributeKey<T>, T).Three misc optimizations previously bundled here (NopStatusListener, TopicMessageType.metricsValue cache, RemotingHelper eager eval fix) have been split into PR #10491.
How Did You Test This Change?
NormalMsgTwoSameGroupConsumerIT), unrelated to this PR.