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:25 UTC

[skywalking] branch percentile created (now 39c9222)

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

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


      at 39c9222  Support new percentile func with new alarm and exporter for this new func.

This branch includes the following new commits:

     new 39c9222  Support new percentile func with new alarm and exporter for this new func.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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

Posted by wu...@apache.org.
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