This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 11a3b2e2579 [improvement](fe) Add cloud tablet rebalancer metrics 
(#66576) (#67296)
11a3b2e2579 is described below

commit 11a3b2e2579b3de8b369f52c2a78fc59f7fb2a2f
Author: deardeng <[email protected]>
AuthorDate: Mon Aug 31 15:27:46 2026 +0800

    [improvement](fe) Add cloud tablet rebalancer metrics (#66576) (#67296)
    
    pick from https://github.com/apache/doris/pull/66576
    
    Record cloud tablet rebalancer round duration, allocation, and scan
    metrics.
    
    (cherry picked from commit 472f5c9f317702527a5a85f356126fa6089b39d3)
    
    ### What problem does this PR solve?
    
    Issue Number: close #xxx
    
    Related PR: #xxx
    
    Problem Summary:
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 .../doris/cloud/catalog/CloudTabletRebalancer.java | 78 +++++++++++++---------
 .../catalog/CloudTabletRebalancerMetrics.java      | 78 ++++++++++++++++++++++
 .../java/org/apache/doris/metric/CloudMetrics.java | 37 ++++++++++
 .../java/org/apache/doris/metric/MetricRepo.java   | 15 +++++
 4 files changed, 177 insertions(+), 31 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
index 82d29f3d701..d1758eae96e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
@@ -82,6 +82,9 @@ import java.util.stream.Collectors;
 public class CloudTabletRebalancer extends MasterDaemon {
     private static final Logger LOG = 
LogManager.getLogger(CloudTabletRebalancer.class);
 
+    private final CloudTabletRebalancerMetrics rebalancerMetrics;
+    private long currentRoundTabletScanCount;
+
     private volatile ConcurrentHashMap<Long, Set<Long>> beToTabletsGlobal =
             new ConcurrentHashMap<Long, Set<Long>>();
 
@@ -243,8 +246,14 @@ public class CloudTabletRebalancer extends MasterDaemon {
     }
 
     public CloudTabletRebalancer(CloudSystemInfoService 
cloudSystemInfoService) {
+        this(cloudSystemInfoService, CloudTabletRebalancerMetrics.create());
+    }
+
+    CloudTabletRebalancer(CloudSystemInfoService cloudSystemInfoService,
+                          CloudTabletRebalancerMetrics rebalancerMetrics) {
         super("cloud tablet rebalancer", 
Config.cloud_tablet_rebalancer_interval_second * 1000);
         this.cloudSystemInfoService = cloudSystemInfoService;
+        this.rebalancerMetrics = rebalancerMetrics;
     }
 
     private void initializeWarmupExecutorsIfNeeded() {
@@ -503,43 +512,49 @@ public class CloudTabletRebalancer extends MasterDaemon {
         }
 
         LOG.info("cloud tablet rebalance begin");
-        long start = System.currentTimeMillis();
-        activeTabletIds = getActiveTabletIds();
-        globalBalanceTypeEnum = 
BalanceTypeEnum.getCloudWarmUpForRebalanceTypeEnum();
+        CloudTabletRebalancerMetrics.Round metricRound = 
rebalancerMetrics.startRound();
+        currentRoundTabletScanCount = 0L;
+        try {
+            long start = System.currentTimeMillis();
+            activeTabletIds = getActiveTabletIds();
+            globalBalanceTypeEnum = 
BalanceTypeEnum.getCloudWarmUpForRebalanceTypeEnum();
 
-        buildClusterToBackendMap();
-        if (!completeRouteInfo()) {
-            return;
-        }
+            buildClusterToBackendMap();
+            if (!completeRouteInfo()) {
+                return;
+            }
 
-        statRouteInfo();
-        migrateTabletsForSmoothUpgrade();
-        statRouteInfo();
+            statRouteInfo();
+            migrateTabletsForSmoothUpgrade();
+            statRouteInfo();
 
-        indexBalanced = true;
-        tableBalanced = true;
+            indexBalanced = true;
+            tableBalanced = true;
 
-        performBalancing();
+            performBalancing();
 
-        checkDecommissionState(clusterToBes);
-        inited = true;
-        long sleepSeconds = Config.cloud_tablet_rebalancer_interval_second;
-        if (sleepSeconds < 0L) {
-            LOG.warn("cloud tablet rebalance interval second is negative, 
change it to default 1s");
-            sleepSeconds = 1L;
-        }
-        long balanceEnd = System.currentTimeMillis();
-        if 
(DebugPointUtil.isEnable("CloudTabletRebalancer.balanceEnd.tooLong")) {
-            LOG.info("debug pointCloudTabletRebalancer.balanceEnd.tooLong");
-            // slower the balance end time to trigger next balance immediately
-            balanceEnd += (Config.cloud_tablet_rebalancer_interval_second + 
10L) * 1000L;
-        }
-        if (balanceEnd - start > 
Config.cloud_tablet_rebalancer_interval_second * 1000L) {
-            sleepSeconds = 1L;
+            checkDecommissionState(clusterToBes);
+            inited = true;
+            long sleepSeconds = Config.cloud_tablet_rebalancer_interval_second;
+            if (sleepSeconds < 0L) {
+                LOG.warn("cloud tablet rebalance interval second is negative, 
change it to default 1s");
+                sleepSeconds = 1L;
+            }
+            long balanceEnd = System.currentTimeMillis();
+            if 
(DebugPointUtil.isEnable("CloudTabletRebalancer.balanceEnd.tooLong")) {
+                LOG.info("debug 
pointCloudTabletRebalancer.balanceEnd.tooLong");
+                // slower the balance end time to trigger next balance 
immediately
+                balanceEnd += (Config.cloud_tablet_rebalancer_interval_second 
+ 10L) * 1000L;
+            }
+            if (balanceEnd - start > 
Config.cloud_tablet_rebalancer_interval_second * 1000L) {
+                sleepSeconds = 1L;
+            }
+            setInterval(sleepSeconds * 1000L);
+            LOG.info("finished to rebalancer. cost: {} ms, rebalancer sche 
interval {} s",
+                    (System.currentTimeMillis() - start), sleepSeconds);
+        } finally {
+            rebalancerMetrics.finishRound(metricRound, 
currentRoundTabletScanCount);
         }
-        setInterval(sleepSeconds * 1000L);
-        LOG.info("finished to rebalancer. cost: {} ms, rebalancer sche 
interval {} s",
-                (System.currentTimeMillis() - start), sleepSeconds);
     }
 
     private void buildClusterToBackendMap() {
@@ -1241,6 +1256,7 @@ public class CloudTabletRebalancer extends MasterDaemon {
                         for (MaterializedIndex index : 
partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
                             for (Map.Entry<String, List<Long>> entry : 
clusterToBes.entrySet()) {
                                 String cluster = entry.getKey();
+                                currentRoundTabletScanCount += 
index.getTablets().size();
                                 operator.op(db, table, partition, index, 
cluster);
                             }
                         } // end for indices
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerMetrics.java
 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerMetrics.java
new file mode 100644
index 00000000000..96d5b31ad1a
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerMetrics.java
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.cloud.catalog;
+
+import org.apache.doris.metric.MetricRepo;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.function.LongSupplier;
+
+final class CloudTabletRebalancerMetrics {
+    private static final long ALLOCATED_BYTES_UNAVAILABLE = -1L;
+
+    private final LongSupplier nanoTimeSupplier;
+    private final LongSupplier allocatedBytesSupplier;
+
+    CloudTabletRebalancerMetrics(LongSupplier nanoTimeSupplier, LongSupplier 
allocatedBytesSupplier) {
+        this.nanoTimeSupplier = nanoTimeSupplier;
+        this.allocatedBytesSupplier = allocatedBytesSupplier;
+    }
+
+    static CloudTabletRebalancerMetrics create() {
+        com.sun.management.ThreadMXBean threadMxBean =
+                
ManagementFactory.getPlatformMXBean(com.sun.management.ThreadMXBean.class);
+        return new CloudTabletRebalancerMetrics(System::nanoTime, 
createAllocatedBytesSupplier(threadMxBean));
+    }
+
+    Round startRound() {
+        return new Round(nanoTimeSupplier.getAsLong(), 
allocatedBytesSupplier.getAsLong());
+    }
+
+    void finishRound(Round round, long tabletScanCount) {
+        long durationMs = 
TimeUnit.NANOSECONDS.toMillis(nanoTimeSupplier.getAsLong() - round.startNanos);
+        long currentAllocatedBytes = allocatedBytesSupplier.getAsLong();
+        long allocatedBytes = round.startAllocatedBytes < 0L || 
currentAllocatedBytes < 0L
+                ? ALLOCATED_BYTES_UNAVAILABLE : currentAllocatedBytes - 
round.startAllocatedBytes;
+        MetricRepo.updateCloudTabletRebalancerMetrics(durationMs, 
allocatedBytes, tabletScanCount);
+    }
+
+    static LongSupplier 
createAllocatedBytesSupplier(com.sun.management.ThreadMXBean threadMxBean) {
+        if (threadMxBean == null || 
!threadMxBean.isThreadAllocatedMemorySupported()) {
+            return () -> ALLOCATED_BYTES_UNAVAILABLE;
+        }
+        if (!threadMxBean.isThreadAllocatedMemoryEnabled()) {
+            try {
+                threadMxBean.setThreadAllocatedMemoryEnabled(true);
+            } catch (SecurityException | UnsupportedOperationException e) {
+                return () -> ALLOCATED_BYTES_UNAVAILABLE;
+            }
+        }
+        return () -> 
threadMxBean.getThreadAllocatedBytes(Thread.currentThread().getId());
+    }
+
+    static final class Round {
+        private final long startNanos;
+        private final long startAllocatedBytes;
+
+        private Round(long startNanos, long startAllocatedBytes) {
+            this.startNanos = startNanos;
+            this.startAllocatedBytes = startAllocatedBytes;
+        }
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java 
b/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
index e74ed0b1bc3..af8c17bef6e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
@@ -71,6 +71,13 @@ public class CloudMetrics {
     protected static AutoMappedMetric<LongCounterMetric> 
CLUSTER_CLOUD_WARM_UP_CACHE_BALANCE_NUM;
     protected static AutoMappedMetric<LongCounterMetric> 
VIRTUAL_COMPUTE_GROUP_SWITCH_COUNTER;
 
+    protected static LongCounterMetric CLOUD_TABLET_REBALANCER_ROUND_TOTAL;
+    protected static LongCounterMetric 
CLOUD_TABLET_REBALANCER_ALLOCATED_BYTES_TOTAL;
+    protected static GaugeMetricImpl<Long> 
CLOUD_TABLET_REBALANCER_LAST_ROUND_ALLOCATED_BYTES;
+    protected static LongCounterMetric 
CLOUD_TABLET_REBALANCER_DURATION_MS_TOTAL;
+    protected static GaugeMetricImpl<Long> 
CLOUD_TABLET_REBALANCER_LAST_ROUND_DURATION_MS;
+    protected static LongCounterMetric 
CLOUD_TABLET_REBALANCER_TABLET_SCAN_TOTAL;
+
     protected static void init() {
         if (Config.isNotCloudMode()) {
             return;
@@ -201,5 +208,35 @@ public class CloudMetrics {
         VIRTUAL_COMPUTE_GROUP_SWITCH_COUNTER = new AutoMappedMetric<>(name -> 
new LongCounterMetric(
             "virtual_compute_group_switch_total", MetricUnit.NOUNIT,
             "virtual compute group active standby switch count"));
+
+        initCloudTabletRebalancerMetrics();
+    }
+
+    static void initCloudTabletRebalancerMetrics() {
+        CLOUD_TABLET_REBALANCER_ROUND_TOTAL = new LongCounterMetric(
+                "cloud_tablet_rebalancer_round_total", MetricUnit.OPERATIONS,
+                "total cloud tablet rebalancer rounds");
+        CLOUD_TABLET_REBALANCER_ALLOCATED_BYTES_TOTAL = new LongCounterMetric(
+                "cloud_tablet_rebalancer_allocated_bytes_total", 
MetricUnit.BYTES,
+                "total bytes allocated by cloud tablet rebalancer rounds");
+        CLOUD_TABLET_REBALANCER_LAST_ROUND_ALLOCATED_BYTES = new 
GaugeMetricImpl<>(
+                "cloud_tablet_rebalancer_last_round_allocated_bytes", 
MetricUnit.BYTES,
+                "bytes allocated by the last cloud tablet rebalancer round, or 
-1 when unavailable", -1L);
+        CLOUD_TABLET_REBALANCER_DURATION_MS_TOTAL = new LongCounterMetric(
+                "cloud_tablet_rebalancer_duration_ms_total", 
MetricUnit.MILLISECONDS,
+                "total cloud tablet rebalancer round duration in 
milliseconds");
+        CLOUD_TABLET_REBALANCER_LAST_ROUND_DURATION_MS = new GaugeMetricImpl<>(
+                "cloud_tablet_rebalancer_last_round_duration_ms", 
MetricUnit.MILLISECONDS,
+                "duration of the last cloud tablet rebalancer round in 
milliseconds", 0L);
+        CLOUD_TABLET_REBALANCER_TABLET_SCAN_TOTAL = new LongCounterMetric(
+                "cloud_tablet_rebalancer_tablet_scan_total", 
MetricUnit.OPERATIONS,
+                "total tablet route entries scanned by cloud tablet rebalancer 
rounds");
+
+        
MetricRepo.DORIS_METRIC_REGISTER.addMetrics(CLOUD_TABLET_REBALANCER_ROUND_TOTAL);
+        
MetricRepo.DORIS_METRIC_REGISTER.addMetrics(CLOUD_TABLET_REBALANCER_ALLOCATED_BYTES_TOTAL);
+        
MetricRepo.DORIS_METRIC_REGISTER.addMetrics(CLOUD_TABLET_REBALANCER_LAST_ROUND_ALLOCATED_BYTES);
+        
MetricRepo.DORIS_METRIC_REGISTER.addMetrics(CLOUD_TABLET_REBALANCER_DURATION_MS_TOTAL);
+        
MetricRepo.DORIS_METRIC_REGISTER.addMetrics(CLOUD_TABLET_REBALANCER_LAST_ROUND_DURATION_MS);
+        
MetricRepo.DORIS_METRIC_REGISTER.addMetrics(CLOUD_TABLET_REBALANCER_TABLET_SCAN_TOTAL);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java 
b/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
index 1e7a979b01f..97ac8d24460 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
@@ -2370,4 +2370,19 @@ public final class MetricRepo {
         counter.setLabels(labels);
         MetricRepo.DORIS_METRIC_REGISTER.addMetrics(counter);
     }
+
+    public static void updateCloudTabletRebalancerMetrics(long durationMs, 
long allocatedBytes,
+                                                           long 
tabletScanCount) {
+        if (!MetricRepo.isInit || Config.isNotCloudMode()) {
+            return;
+        }
+        CloudMetrics.CLOUD_TABLET_REBALANCER_ROUND_TOTAL.increase(1L);
+        
CloudMetrics.CLOUD_TABLET_REBALANCER_DURATION_MS_TOTAL.increase(durationMs);
+        
CloudMetrics.CLOUD_TABLET_REBALANCER_LAST_ROUND_DURATION_MS.setValue(durationMs);
+        
CloudMetrics.CLOUD_TABLET_REBALANCER_TABLET_SCAN_TOTAL.increase(tabletScanCount);
+        
CloudMetrics.CLOUD_TABLET_REBALANCER_LAST_ROUND_ALLOCATED_BYTES.setValue(allocatedBytes);
+        if (allocatedBytes >= 0L) {
+            
CloudMetrics.CLOUD_TABLET_REBALANCER_ALLOCATED_BYTES_TOTAL.increase(allocatedBytes);
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to