You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/01/10 09:04:26 UTC

[skywalking] 01/01: Support new percentile func with new alarm and exporter for this new func.

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

wusheng pushed a commit to branch percentile
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit 39c9222ded0705a529636b7a9caedd939886a7af
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Fri Jan 10 17:04:04 2020 +0800

    Support new percentile func with new alarm and exporter for this new func.
---
 dist-material/alarm-settings.yml                   |   4 +-
 .../exporter/provider/grpc/GRPCExporter.java       |   6 ++
 .../exporter/src/main/proto/metric-exporter.proto  |   2 +
 .../core/alarm/provider/MetricsValueType.java      |   2 +-
 .../server/core/alarm/provider/RunningRule.java    |  35 ++++++-
 .../oap/server/core/alarm/provider/Threshold.java  |  19 +++-
 .../server/core/alarm/provider/ThresholdTest.java  |   2 +-
 .../src/main/resources/official_analysis.oal       |  43 ++-------
 .../analysis/metrics/MultiIntValuesHolder.java}    |  11 ++-
 .../core/analysis/metrics/PercentileMetrics.java   | 103 +++++++++++++++++++++
 .../oap/server/core/query/MetricQueryService.java  |   6 +-
 .../core/storage/annotation/ValueColumnIds.java    |  16 +++-
 .../src/main/resources/query-protocol              |   2 +-
 13 files changed, 193 insertions(+), 58 deletions(-)

diff --git a/dist-material/alarm-settings.yml b/dist-material/alarm-settings.yml
index 8ed9c2e..c69591d 100644
--- a/dist-material/alarm-settings.yml
+++ b/dist-material/alarm-settings.yml
@@ -39,9 +39,9 @@ rules:
     message: Successful rate of service {name} is lower than 80% in 2 minutes of last 10 minutes
   service_p90_sla_rule:
     # Metrics value need to be long, double or int
-    metrics-name: service_p90
+    metrics-name: service_percentile
     op: ">"
-    threshold: 1000
+    threshold: 1000,1000,1000,1000,1000
     period: 10
     count: 3
     silence-period: 5
diff --git a/oap-server/exporter/src/main/java/org/apache/skywalking/oap/server/exporter/provider/grpc/GRPCExporter.java b/oap-server/exporter/src/main/java/org/apache/skywalking/oap/server/exporter/provider/grpc/GRPCExporter.java
index 136c2aa..3114d6b 100644
--- a/oap-server/exporter/src/main/java/org/apache/skywalking/oap/server/exporter/provider/grpc/GRPCExporter.java
+++ b/oap-server/exporter/src/main/java/org/apache/skywalking/oap/server/exporter/provider/grpc/GRPCExporter.java
@@ -117,6 +117,12 @@ public class GRPCExporter extends MetricFormatter implements MetricValuesExportS
                 double value = ((DoubleValueHolder)metrics).getValue();
                 builder.setDoubleValue(value);
                 builder.setType(ValueType.DOUBLE);
+            } else if (metrics instanceof MultiIntValuesHolder) {
+                int[] values = ((MultiIntValuesHolder)metrics).getValues();
+                for (int value : values) {
+                    builder.addLongValues(value);
+                }
+                builder.setType(ValueType.MULTI_LONG);
             } else {
                 return;
             }
diff --git a/oap-server/exporter/src/main/proto/metric-exporter.proto b/oap-server/exporter/src/main/proto/metric-exporter.proto
index a612b28..3ade1e3 100644
--- a/oap-server/exporter/src/main/proto/metric-exporter.proto
+++ b/oap-server/exporter/src/main/proto/metric-exporter.proto
@@ -38,6 +38,7 @@ message ExportMetricValue {
     int64 timeBucket = 5;
     int64 longValue = 6;
     double doubleValue = 7;
+    repeated int64 longValues = 8;
 }
 
 message SubscriptionsResp {
@@ -47,6 +48,7 @@ message SubscriptionsResp {
 enum ValueType {
     LONG = 0;
     DOUBLE = 1;
+    MULTI_LONG = 2;
 }
 
 message SubscriptionReq {
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java
index 04e9564..040b693 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java
@@ -19,5 +19,5 @@
 package org.apache.skywalking.oap.server.core.alarm.provider;
 
 public enum MetricsValueType {
-    LONG, INT, DOUBLE
+    LONG, INT, DOUBLE, MULTI_INTS
 }
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
index 6af7524..8a71d7f 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
@@ -24,6 +24,7 @@ import org.apache.skywalking.oap.server.core.analysis.metrics.DoubleValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.IntValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.LongValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
+import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.joda.time.LocalDateTime;
 import org.joda.time.Minutes;
@@ -116,6 +117,9 @@ public class RunningRule {
             } else if (metrics instanceof DoubleValueHolder) {
                 valueType = MetricsValueType.DOUBLE;
                 threshold.setType(MetricsValueType.DOUBLE);
+            } else if (metrics instanceof MultiIntValuesHolder) {
+                valueType = MetricsValueType.MULTI_INTS;
+                threshold.setType(MetricsValueType.MULTI_INTS);
             } else {
                 return;
             }
@@ -170,10 +174,8 @@ public class RunningRule {
         return alarmMessageList;
     }
 
-
-
     /**
-     * A metrics window, based on {@link AlarmRule#period}. This window slides with time, just keeps the recent
+     * A metrics window, based on {@link AlarmRule#getPeriod()}. This window slides with time, just keeps the recent
      * N(period) buckets.
      *
      * @author wusheng
@@ -325,7 +327,7 @@ public class RunningRule {
                         break;
                     case DOUBLE:
                         double dvalue = ((DoubleValueHolder)metrics).getValue();
-                        double dexpected = RunningRule.this.threshold.getDoubleThreadhold();
+                        double dexpected = RunningRule.this.threshold.getDoubleThreshold();
                         switch (op) {
                             case EQUAL:
                                 // NOTICE: double equal is not reliable in Java,
@@ -343,6 +345,31 @@ public class RunningRule {
                                 break;
                         }
                         break;
+                    case MULTI_INTS:
+                        int[] ivalueArray = ((MultiIntValuesHolder)metrics).getValues();
+                        int[] iaexpected = RunningRule.this.threshold.getIntValuesThreshold();
+                        MULTI_VALUE_CHECK: for (int i = 0; i < ivalueArray.length; i++) {
+                            ivalue = ivalueArray[i];
+                            iexpected = 0;
+                            if (iaexpected.length > i) {
+                                iexpected = iaexpected[i];
+                            }
+                            switch (op) {
+                                case LESS:
+                                    if (ivalue < iexpected)
+                                        matchCount++;
+                                    break MULTI_VALUE_CHECK;
+                                case GREATER:
+                                    if (ivalue > iexpected)
+                                        matchCount++;
+                                    break MULTI_VALUE_CHECK;
+                                case EQUAL:
+                                    if (ivalue == iexpected)
+                                        matchCount++;
+                                    break MULTI_VALUE_CHECK;
+                            }
+                            break;
+                        }
                 }
             }
 
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java
index aa67f3b..e4df06e 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java
@@ -30,8 +30,9 @@ public class Threshold {
     private String alarmRuleName;
     private final String threshold;
     private int intThreshold;
-    private double doubleThreadhold;
+    private double doubleThreshold;
     private long longThreshold;
+    private int[] intValuesThreshold;
 
     public Threshold(String alarmRuleName, String threshold) {
         this.alarmRuleName = alarmRuleName;
@@ -42,14 +43,18 @@ public class Threshold {
         return intThreshold;
     }
 
-    public double getDoubleThreadhold() {
-        return doubleThreadhold;
+    public double getDoubleThreshold() {
+        return doubleThreshold;
     }
 
     public long getLongThreshold() {
         return longThreshold;
     }
 
+    public int[] getIntValuesThreshold() {
+        return intValuesThreshold;
+    }
+
     public void setType(MetricsValueType type) {
         try {
             switch (type) {
@@ -60,8 +65,14 @@ public class Threshold {
                     longThreshold = Long.parseLong(threshold);
                     break;
                 case DOUBLE:
-                    doubleThreadhold = Double.parseDouble(threshold);
+                    doubleThreshold = Double.parseDouble(threshold);
                     break;
+                case MULTI_INTS:
+                    String[] strings = threshold.split(",");
+                    intValuesThreshold = new int[strings.length];
+                    for (int i = 0; i < strings.length; i++) {
+                        intValuesThreshold[i] = Integer.parseInt(strings[i]);
+                    }
             }
         } catch (NumberFormatException e) {
             logger.warn("Alarm rule {} threshold doesn't match the metrics type, expected type: {}", alarmRuleName, type);
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/ThresholdTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/ThresholdTest.java
index 0363b48..3d53271 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/ThresholdTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/ThresholdTest.java
@@ -31,7 +31,7 @@ public class ThresholdTest {
     public void setType() {
         Threshold threshold = new Threshold("my-rule", "75");
         threshold.setType(MetricsValueType.DOUBLE);
-        assertEquals(0, Double.compare(75, threshold.getDoubleThreadhold()));
+        assertEquals(0, Double.compare(75, threshold.getDoubleThreshold()));
 
         threshold.setType(MetricsValueType.INT);
         assertEquals(75, threshold.getIntThreshold());
diff --git a/oap-server/server-bootstrap/src/main/resources/official_analysis.oal b/oap-server/server-bootstrap/src/main/resources/official_analysis.oal
index da9b92c..48ebcf4 100755
--- a/oap-server/server-bootstrap/src/main/resources/official_analysis.oal
+++ b/oap-server/server-bootstrap/src/main/resources/official_analysis.oal
@@ -28,11 +28,7 @@ all_heatmap = from(All.latency).thermodynamic(100, 20);
 service_resp_time = from(Service.latency).longAvg();
 service_sla = from(Service.*).percent(status == true);
 service_cpm = from(Service.*).cpm();
-service_p99 = from(Service.latency).p99(10);
-service_p95 = from(Service.latency).p95(10);
-service_p90 = from(Service.latency).p90(10);
-service_p75 = from(Service.latency).p75(10);
-service_p50 = from(Service.latency).p50(10);
+service_percentile = from(Service.latency).percentile(10);
 service_apdex = from(Service.latency).apdex(name, status);
 
 // Service relation scope metrics for topology
@@ -42,16 +38,9 @@ service_relation_client_call_sla = from(ServiceRelation.*).filter(detectPoint ==
 service_relation_server_call_sla = from(ServiceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
 service_relation_client_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
 service_relation_server_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
-service_relation_client_p99 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p99(10);
-service_relation_server_p99 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p99(10);
-service_relation_client_p95 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p95(10);
-service_relation_server_p95 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p95(10);
-service_relation_client_p90 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p90(10);
-service_relation_server_p90 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p90(10);
-service_relation_client_p75 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p75(10);
-service_relation_server_p75 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p75(10);
-service_relation_client_p50 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p50(10);
-service_relation_server_p50 = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p50(10);
+service_relation_client_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10);
+service_relation_server_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10);
+
 
 // Service Instance relation scope metrics for topology
 service_instance_relation_client_cpm = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.CLIENT).cpm();
@@ -60,16 +49,8 @@ service_instance_relation_client_call_sla = from(ServiceInstanceRelation.*).filt
 service_instance_relation_server_call_sla = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
 service_instance_relation_client_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
 service_instance_relation_server_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
-service_instance_relation_client_p99 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p99(10);
-service_instance_relation_server_p99 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p99(10);
-service_instance_relation_client_p95 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p95(10);
-service_instance_relation_server_p95 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p95(10);
-service_instance_relation_client_p90 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p90(10);
-service_instance_relation_server_p90 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p90(10);
-service_instance_relation_client_p75 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p75(10);
-service_instance_relation_server_p75 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p75(10);
-service_instance_relation_client_p50 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).p50(10);
-service_instance_relation_server_p50 = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).p50(10);
+service_instance_relation_client_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10);
+service_instance_relation_server_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10);
 
 // Service Instance Scope metrics
 service_instance_sla = from(ServiceInstance.*).percent(status == true);
@@ -80,11 +61,7 @@ service_instance_cpm = from(ServiceInstance.*).cpm();
 endpoint_cpm = from(Endpoint.*).cpm();
 endpoint_avg = from(Endpoint.latency).longAvg();
 endpoint_sla = from(Endpoint.*).percent(status == true);
-endpoint_p99 = from(Endpoint.latency).p99(10);
-endpoint_p95 = from(Endpoint.latency).p95(10);
-endpoint_p90 = from(Endpoint.latency).p90(10);
-endpoint_p75 = from(Endpoint.latency).p75(10);
-endpoint_p50 = from(Endpoint.latency).p50(10);
+endpoint_percentile = from(Endpoint.latency).percentile(10);
 
 // Endpoint relation scope metrics
 endpoint_relation_cpm = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
@@ -104,11 +81,7 @@ instance_jvm_old_gc_count = from(ServiceInstanceJVMGC.count).filter(phrase == GC
 database_access_resp_time = from(DatabaseAccess.latency).longAvg();
 database_access_sla = from(DatabaseAccess.*).percent(status == true);
 database_access_cpm = from(DatabaseAccess.*).cpm();
-database_access_p99 = from(DatabaseAccess.latency).p99(10);
-database_access_p95 = from(DatabaseAccess.latency).p95(10);
-database_access_p90 = from(DatabaseAccess.latency).p90(10);
-database_access_p75 = from(DatabaseAccess.latency).p75(10);
-database_access_p50 = from(DatabaseAccess.latency).p50(10);
+database_access_percentile = from(DatabaseAccess.latency).percentile(10);
 
 // CLR instance metrics
 instance_clr_cpu = from(ServiceInstanceCLRCPU.usePercent).doubleAvg();
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java
similarity index 79%
copy from oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java
index 04e9564..4540b38 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/MetricsValueType.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java
@@ -16,8 +16,13 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core.alarm.provider;
+package org.apache.skywalking.oap.server.core.analysis.metrics;
 
-public enum MetricsValueType {
-    LONG, INT, DOUBLE
+/**
+ * IntValueHolder always holds a set of int(s).
+ *
+ * @author wusheng
+ */
+public interface MultiIntValuesHolder {
+    int[] getValues();
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java
new file mode 100644
index 0000000..9e59f7f
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java
@@ -0,0 +1,103 @@
+/*
+ * 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.skywalking.oap.server.core.analysis.metrics;
+
+import java.util.Comparator;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Arg;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entrance;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.MetricsFunction;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.SourceFrom;
+import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+
+/**
+ * Percentile is a better implementation than {@link PxxMetrics}. It is introduced since 7.0.0, it could calculate the
+ * multiple P50/75/90/95/99 values once for all.
+ *
+ * @author wusheng
+ */
+@MetricsFunction(functionName = "percentile")
+public abstract class PercentileMetrics extends GroupMetrics implements MultiIntValuesHolder {
+    protected static final String DETAIL_GROUP = "detail_group";
+    protected static final String VALUE = "value";
+    protected static final String PRECISION = "precision";
+
+    private static final int[] RANKS = {50, 75, 90, 95, 99};
+
+    @Getter @Setter @Column(columnName = VALUE) private int[] values = {0, 0, 0, 0, 0};
+    @Getter @Setter @Column(columnName = PRECISION) private int precision;
+    @Getter @Setter @Column(columnName = DETAIL_GROUP) private IntKeyLongValueHashMap detailGroup;
+
+    private boolean isCalculated;
+
+    public PercentileMetrics() {
+        detailGroup = new IntKeyLongValueHashMap(30);
+    }
+
+    @Entrance
+    public final void combine(@SourceFrom int value, @Arg int precision) {
+        this.isCalculated = false;
+        this.precision = precision;
+
+        int index = value / precision;
+        IntKeyLongValue element = detailGroup.get(index);
+        if (element == null) {
+            element = new IntKeyLongValue(index, 1);
+            detailGroup.put(element.getKey(), element);
+        } else {
+            element.addValue(1);
+        }
+    }
+
+    @Override
+    public void combine(Metrics metrics) {
+        this.isCalculated = false;
+
+        PxxMetrics pxxMetrics = (PxxMetrics)metrics;
+        combine(pxxMetrics.getDetailGroup(), this.detailGroup);
+    }
+
+    @Override
+    public final void calculate() {
+
+        if (!isCalculated) {
+            int total = detailGroup.values().stream().mapToInt(element -> (int)element.getValue()).sum();
+            for (int i = 0; i < RANKS.length; i++) {
+                int percentileRank = RANKS[i];
+                int roof = Math.round(total * percentileRank * 1.0f / 100);
+
+                int count = 0;
+                IntKeyLongValue[] sortedData = detailGroup.values().stream().sorted(new Comparator<IntKeyLongValue>() {
+                    @Override public int compare(IntKeyLongValue o1, IntKeyLongValue o2) {
+                        return o1.getKey() - o2.getKey();
+                    }
+                }).toArray(IntKeyLongValue[]::new);
+                for (IntKeyLongValue element : sortedData) {
+                    count += element.getValue();
+                    if (count >= roof) {
+                        values[i] = element.getKey() * precision;
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricQueryService.java
index a438793..0335cb7 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricQueryService.java
@@ -60,7 +60,7 @@ public class MetricQueryService implements Service {
         return metricQueryDAO;
     }
 
-    public IntValues getValues(final String indName, final List<String> ids, final Downsampling downsampling,
+    public IntValues getValues(final String metricsName, final List<String> ids, final Downsampling downsampling,
         final long startTB,
         final long endTB) throws IOException {
         if (CollectionUtils.isEmpty(ids)) {
@@ -69,7 +69,7 @@ public class MetricQueryService implements Service {
              * we return an empty list, and a debug level log,
              * rather than an exception, which always being considered as a serious error from new users.
              */
-            logger.debug("query metrics[{}] w/o IDs", indName);
+            logger.debug("query metrics[{}] w/o IDs", metricsName);
             return new IntValues();
         }
 
@@ -79,7 +79,7 @@ public class MetricQueryService implements Service {
         where.getKeyValues().add(intKeyValues);
         ids.forEach(intKeyValues.getValues()::add);
 
-        return getMetricQueryDAO().getValues(indName, downsampling, startTB, endTB, where, ValueColumnIds.INSTANCE.getValueCName(indName), ValueColumnIds.INSTANCE.getValueFunction(indName));
+        return getMetricQueryDAO().getValues(metricsName, downsampling, startTB, endTB, where, ValueColumnIds.INSTANCE.getValueCName(metricsName), ValueColumnIds.INSTANCE.getValueFunction(metricsName));
     }
 
     public IntValues getLinearIntValues(final String indName, final String id, final Downsampling downsampling,
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnIds.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnIds.java
index b25622c..ef00307 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnIds.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnIds.java
@@ -33,12 +33,20 @@ public enum ValueColumnIds {
         mapping.putIfAbsent(indName, new ValueColumn(valueCName, function));
     }
 
-    public String getValueCName(String indName) {
-        return mapping.get(indName).valueCName;
+    public String getValueCName(String metricsName) {
+        return findColumn(metricsName).valueCName;
     }
 
-    public Function getValueFunction(String indName) {
-        return mapping.get(indName).function;
+    public Function getValueFunction(String metricsName) {
+        return findColumn(metricsName).function;
+    }
+
+    private ValueColumn findColumn(String metricsName) {
+        ValueColumn column = mapping.get(metricsName);
+        if (column == null) {
+            throw new RuntimeException("Metrics:" + metricsName + " doesn't have value column definition");
+        }
+        return column;
     }
 
     class ValueColumn {
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index dde9a0d..0c2dfa1 160000
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit dde9a0dad56617ccbf4226f5f71e667fd9620222
+Subproject commit 0c2dfa18862596ed6790e2db0245b8f5af64e156