Skip to content

Conversation

@contrueCT
Copy link
Contributor

@contrueCT contrueCT commented Dec 20, 2025

Ⅰ. Describe what this PR did

Add metrics for NamingServer:

  • seata_namingserver_cluster_node_count (Gauge)
  • seata_namingserver_watcher_count (Gauge)
  • seata_namingserver_cluster_change_push_total (Counter)
  • JVM and HTTP-related metrics implemented via Micrometer and Spring Boot.

Ⅱ. Does this pull request fix one issue?

fixes #7852

Ⅲ. Why don't you add test cases (unit test/integration test)?

Ⅳ. Describe how to verify it

Ⅴ. Special notes for reviews

@codecov
Copy link

codecov bot commented Dec 20, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.10%. Comparing base (4593c46) to head (d93af2f).

Additional details and impacted files
@@             Coverage Diff              @@
##                2.x    #7882      +/-   ##
============================================
- Coverage     71.11%   71.10%   -0.02%     
  Complexity      797      797              
============================================
  Files          1300     1300              
  Lines         49601    49601              
  Branches       5875     5875              
============================================
- Hits          35274    35269       -5     
- Misses        11406    11411       +5     
  Partials       2921     2921              

see 8 files with indirect coverage changes

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@funky-eyes funky-eyes changed the title feat: add metrics support for NamingServer feature: add metrics support for NamingServer Dec 22, 2025
Copy link
Contributor

@funky-eyes funky-eyes left a comment

Choose a reason for hiding this comment

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

Additionally, I suggest adding monitoring metrics for the response time (avg, p50, p99, p999) and QPS of each interface. You can implement this in the filter.

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we should abstract an interface for MetricsManager and provide a no-op (empty) implementation. When the Prometheus metrics feature is disabled, we can use this empty implementation, thereby avoiding the need for null checks in other classes that depend on MetricsManager.

if (mappingObj instanceof Map) {
Map<String, String> vGroups = (Map<String, String>) mappingObj;
vGroups.forEach((k, v) -> {
// In non-raft mode, a unit is one-to-one with a node, and the unitName is stored on the node.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why remove these commented-out content?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, it just a mistake, i will restore it.

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems we're missing some common tags, such as the host of the current Naming Server. For example, this would make it easier to query metrics from specific Naming Server instances.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds comprehensive Prometheus metrics support to the NamingServer module. The implementation enables monitoring of critical server operations through Micrometer and Spring Boot Actuator.

Key Changes:

  • Introduces three core metrics: cluster node count (Gauge), watcher count (Gauge), and cluster change push notifications (Counter)
  • Adds configurable metrics support with a no-op implementation for when metrics are disabled
  • Integrates metrics collection into existing server operations for real-time monitoring

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
namingserver/pom.xml Adds Spring Boot Actuator and Micrometer Prometheus registry dependencies
namingserver/src/main/resources/application.yml Configures metrics endpoint exposure and percentile distribution settings
namingserver/src/test/resources/application.yml Configures test environment metrics settings
namingserver/src/main/java/org/apache/seata/namingserver/metrics/NamingServerMetricsManager.java Defines the metrics manager interface with metric names and tag constants
namingserver/src/main/java/org/apache/seata/namingserver/metrics/PrometheusNamingMetricsManager.java Implements Prometheus metrics collection using MultiGauge and Counter
namingserver/src/main/java/org/apache/seata/namingserver/metrics/NoOpNamingMetricsManager.java Provides no-op implementation when metrics are disabled
namingserver/src/main/java/org/apache/seata/namingserver/metrics/NamingServerTagsContributor.java Adds custom tags to HTTP request metrics for business dimensions
namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java Integrates cluster node count metrics refresh on instance registration/unregistration
namingserver/src/main/java/org/apache/seata/namingserver/manager/ClusterWatcherManager.java Integrates watcher count metrics and cluster change push counter
namingserver/src/test/java/org/apache/seata/namingserver/NamingServerMetricsManagerTest.java Adds comprehensive unit tests for metrics manager functionality
namingserver/src/test/java/org/apache/seata/namingserver/ClusterWatcherManagerTest.java Updates tests to inject NoOpNamingMetricsManager
changes/en-us/2.x.md Documents the feature addition in English changelog
changes/zh-cn/2.x.md Documents the feature addition in Chinese changelog
Comments suppressed due to low confidence (1)

namingserver/src/main/java/org/apache/seata/namingserver/manager/ClusterWatcherManager.java:78

  • The scheduled task re-registers watchers within its execution which calls registryWatcher, and registryWatcher immediately triggers refreshWatcherCountMetrics. This creates a potential for frequent metrics refreshes every second as the scheduled task runs. This could cause unnecessary overhead when combined with the refresh on line 102.
        scheduledThreadPoolExecutor.scheduleAtFixedRate(
                () -> {
                    for (String group : WATCHERS.keySet()) {
                        Optional.ofNullable(WATCHERS.remove(group))
                                .ifPresent(watchers -> watchers.parallelStream().forEach(watcher -> {
                                    if (System.currentTimeMillis() >= watcher.getTimeout()) {
                                        notify(watcher, HttpStatus.NOT_MODIFIED.value());
                                    }
                                    if (!watcher.isDone()) {
                                        // Re-register
                                        registryWatcher(watcher);

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

Comment on lines +44 to +60
// Add namespace tag
String namespace = context.getCarrier().getParameter(TAG_NAMESPACE);
keyValues = keyValues.and(KeyValue.of(TAG_NAMESPACE, namespace != null ? namespace : UNKNOWN));

// Add cluster tag
String cluster = context.getCarrier().getParameter(TAG_CLUSTER);
if (cluster == null) {
cluster = context.getCarrier().getParameter("clusterName");
}
keyValues = keyValues.and(KeyValue.of(TAG_CLUSTER, cluster != null ? cluster : UNKNOWN));

// Add vgroup tag
String vgroup = context.getCarrier().getParameter(TAG_VGROUP);
if (vgroup == null) {
vgroup = context.getCarrier().getParameter("group");
}
keyValues = keyValues.and(KeyValue.of(TAG_VGROUP, vgroup != null ? vgroup : UNKNOWN));
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

Adding tags with value "unknown" for every HTTP request will create high cardinality metrics. When these parameters are not present in requests, it would be better to either not add the tag at all, or use a constant shared "unknown" value. This could lead to performance issues and excessive memory usage in the metrics registry as each unique combination of tag values creates a separate time series. Consider only adding tags when they have meaningful values.

Copilot uses AI. Check for mistakes.
Comment on lines +132 to +133
// Immediately refresh watcher count metrics
metricsManager.refreshWatcherCountMetrics();
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The metrics are being refreshed on every watcher registration, which could happen very frequently in a high-traffic scenario. Calling refreshWatcherCountMetrics on every single registration could create unnecessary overhead. Consider batching these updates or using a scheduled refresh instead of immediate refresh on every operation.

Copilot uses AI. Check for mistakes.
Comment on lines +359 to +360
// Immediately refresh cluster node count metrics
metricsManager.refreshClusterNodeCountMetrics();
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The metrics are being refreshed on every instance registration and unregistration. In high-traffic scenarios with frequent registrations/unregistrations, this could create significant overhead. Consider batching these updates or using a scheduled refresh strategy instead of immediately refreshing on every operation.

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +64
public class NamingServerTagsContributor extends DefaultServerRequestObservationConvention {

private static final String TAG_NAMESPACE = "namespace";
private static final String TAG_CLUSTER = "cluster";
private static final String TAG_VGROUP = "vgroup";
private static final String UNKNOWN = "unknown";

@Override
public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
KeyValues keyValues = super.getLowCardinalityKeyValues(context);

// Add namespace tag
String namespace = context.getCarrier().getParameter(TAG_NAMESPACE);
keyValues = keyValues.and(KeyValue.of(TAG_NAMESPACE, namespace != null ? namespace : UNKNOWN));

// Add cluster tag
String cluster = context.getCarrier().getParameter(TAG_CLUSTER);
if (cluster == null) {
cluster = context.getCarrier().getParameter("clusterName");
}
keyValues = keyValues.and(KeyValue.of(TAG_CLUSTER, cluster != null ? cluster : UNKNOWN));

// Add vgroup tag
String vgroup = context.getCarrier().getParameter(TAG_VGROUP);
if (vgroup == null) {
vgroup = context.getCarrier().getParameter("group");
}
keyValues = keyValues.and(KeyValue.of(TAG_VGROUP, vgroup != null ? vgroup : UNKNOWN));

return keyValues;
}
} No newline at end of file
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The NamingServerTagsContributor class lacks test coverage. This component extends DefaultServerRequestObservationConvention and adds custom tag logic that should be tested to ensure tags are correctly extracted from request parameters and handled when missing.

Copilot uses AI. Check for mistakes.
include: "prometheus,health,info,metrics"
metrics:
tags:
application: { spring.application.name }
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The syntax used here is incorrect for YAML. The correct syntax to reference another property value in Spring Boot YAML should use ${} without curly braces around the reference, like this: application: ${spring.application.name}

Suggested change
application: { spring.application.name }
application: ${spring.application.name}

Copilot uses AI. Check for mistakes.
include: "prometheus,health,info,metrics"
metrics:
tags:
application: { spring.application.name }
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The syntax used here is incorrect for YAML. The correct syntax to reference another property value in Spring Boot YAML should use ${} without curly braces around the reference, like this: application: ${spring.application.name}

Suggested change
application: { spring.application.name }
application: ${spring.application.name}

Copilot uses AI. Check for mistakes.
Comment on lines +394 to +395
// Immediately refresh cluster node count metrics
metricsManager.refreshClusterNodeCountMetrics();
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The metrics are being refreshed on every instance registration and unregistration. In high-traffic scenarios with frequent registrations/unregistrations, this could create significant overhead. Consider batching these updates or using a scheduled refresh strategy instead of immediately refreshing on every operation.

Copilot uses AI. Check for mistakes.
protected final ScheduledExecutorService heartBeatCheckService =
new ScheduledThreadPoolExecutor(1, new CustomizableThreadFactory("heartBeatCheckExcuter"));
protected final ScheduledExecutorService heartBeatCheckService = new ScheduledThreadPoolExecutor(1,
new CustomizableThreadFactory("heartBeatCheckExcuter"));
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

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

The thread factory name contains a typo: "heartBeatCheckExcuter" should be spelled "heartBeatCheckExecutor".

Suggested change
new CustomizableThreadFactory("heartBeatCheckExcuter"));
new CustomizableThreadFactory("heartBeatCheckExecutor"));

Copilot uses AI. Check for mistakes.
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.

Add metrics for NamingServer

2 participants