You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@servicecomb.apache.org by GitBox <gi...@apache.org> on 2017/12/27 01:26:18 UTC

[GitHub] WillemJiang closed pull request #451: [JAV-539] & [SCB-9] Implement CallCount and TPS Metrics

WillemJiang closed pull request #451: [JAV-539] & [SCB-9] Implement CallCount and TPS Metrics
URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/451
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/common/common-rest/src/main/java/io/servicecomb/common/rest/AbstractRestInvocation.java b/common/common-rest/src/main/java/io/servicecomb/common/rest/AbstractRestInvocation.java
index f7f513483..8fae4efc2 100644
--- a/common/common-rest/src/main/java/io/servicecomb/common/rest/AbstractRestInvocation.java
+++ b/common/common-rest/src/main/java/io/servicecomb/common/rest/AbstractRestInvocation.java
@@ -51,6 +51,7 @@
 import io.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import io.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import io.servicecomb.foundation.vertx.stream.BufferOutputStream;
+import io.servicecomb.swagger.invocation.InvocationType;
 import io.servicecomb.swagger.invocation.Response;
 import io.servicecomb.swagger.invocation.exception.InvocationException;
 
@@ -109,7 +110,7 @@ protected void scheduleInvocation() {
     OperationMeta operationMeta = restOperationMeta.getOperationMeta();
 
     InvocationStartedEvent startedEvent = new InvocationStartedEvent(operationMeta.getMicroserviceQualifiedName(),
-        System.nanoTime());
+        InvocationType.PRODUCER, System.nanoTime());
     EventUtils.triggerEvent(startedEvent);
 
     QueueMetrics metricsData = initMetrics(operationMeta);
@@ -226,7 +227,7 @@ protected void sendResponse(Response response) throws Exception {
       }
     }
     responseEx.setStatus(response.getStatusCode(), response.getReasonPhrase());
-    responseEx.setContentType(produceProcessor.getName()+"; charset=utf-8");
+    responseEx.setContentType(produceProcessor.getName() + "; charset=utf-8");
 
     Object body = response.getResult();
     if (response.isFailed()) {
diff --git a/common/common-rest/src/test/java/io/servicecomb/common/rest/TestAbstractRestInvocation.java b/common/common-rest/src/test/java/io/servicecomb/common/rest/TestAbstractRestInvocation.java
index ddab59655..898f0d448 100644
--- a/common/common-rest/src/test/java/io/servicecomb/common/rest/TestAbstractRestInvocation.java
+++ b/common/common-rest/src/test/java/io/servicecomb/common/rest/TestAbstractRestInvocation.java
@@ -43,21 +43,20 @@
 import io.servicecomb.core.Endpoint;
 import io.servicecomb.core.Handler;
 import io.servicecomb.core.Invocation;
-import io.servicecomb.core.metrics.InvocationStartedEvent;
 import io.servicecomb.core.definition.MicroserviceMeta;
 import io.servicecomb.core.definition.MicroserviceMetaManager;
 import io.servicecomb.core.definition.OperationMeta;
 import io.servicecomb.core.definition.SchemaMeta;
 import io.servicecomb.core.executor.ReactiveExecutor;
+import io.servicecomb.core.metrics.InvocationStartedEvent;
 import io.servicecomb.core.provider.consumer.ReferenceConfig;
 import io.servicecomb.foundation.common.utils.JsonUtils;
-import io.servicecomb.foundation.metrics.MetricsServoRegistry;
 import io.servicecomb.foundation.metrics.performance.QueueMetrics;
-import io.servicecomb.foundation.metrics.performance.QueueMetricsData;
 import io.servicecomb.foundation.vertx.http.AbstractHttpServletRequest;
 import io.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import io.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import io.servicecomb.swagger.invocation.AsyncResponse;
+import io.servicecomb.swagger.invocation.InvocationType;
 import io.servicecomb.swagger.invocation.Response;
 import io.servicecomb.swagger.invocation.exception.CommonExceptionData;
 import io.servicecomb.swagger.invocation.exception.InvocationException;
@@ -374,7 +373,6 @@ protected void sendResponse(Response response) throws Exception {
     restInvocation.sendResponseQuietly(response);
 
     Assert.assertSame(response, result.value);
-
   }
 
   @Test
@@ -625,7 +623,7 @@ public void scheduleInvocationException(@Mocked OperationMeta operationMeta) {
     Error error = new Error("run on executor");
     restInvocation = new AbstractRestInvocationForTest() {
       @Override
-      protected void runOnExecutor(QueueMetrics metricsData,InvocationStartedEvent startedEvent) {
+      protected void runOnExecutor(QueueMetrics metricsData, InvocationStartedEvent startedEvent) {
         throw error;
       }
 
@@ -662,7 +660,7 @@ public void scheduleInvocationTimeout(@Mocked OperationMeta operationMeta) {
 
     restInvocation = new AbstractRestInvocationForTest() {
       @Override
-      protected void runOnExecutor(QueueMetrics metricsData,InvocationStartedEvent startedEvent) {
+      protected void runOnExecutor(QueueMetrics metricsData, InvocationStartedEvent startedEvent) {
         throw new Error("run on executor");
       }
 
@@ -698,7 +696,7 @@ public void scheduleInvocationNormal(@Mocked OperationMeta operationMeta) {
     Holder<Boolean> result = new Holder<>();
     restInvocation = new AbstractRestInvocationForTest() {
       @Override
-      protected void runOnExecutor(QueueMetrics metricsData,InvocationStartedEvent startedEvent) {
+      protected void runOnExecutor(QueueMetrics metricsData, InvocationStartedEvent startedEvent) {
         result.value = true;
       }
     };
@@ -729,7 +727,7 @@ public void invoke() {
     restInvocation.requestEx = requestEx;
     restInvocation.restOperationMeta = restOperation;
 
-    restInvocation.runOnExecutor(null, new InvocationStartedEvent("", System.nanoTime()));
+    restInvocation.runOnExecutor(null, new InvocationStartedEvent("", InvocationType.PRODUCER, System.nanoTime()));
     Assert.assertTrue(result.value);
     Assert.assertSame(invocation, restInvocation.invocation);
   }
diff --git a/core/src/main/java/io/servicecomb/core/metrics/InvocationFinishedEvent.java b/core/src/main/java/io/servicecomb/core/metrics/InvocationFinishedEvent.java
index 90260ca01..077e9a80e 100644
--- a/core/src/main/java/io/servicecomb/core/metrics/InvocationFinishedEvent.java
+++ b/core/src/main/java/io/servicecomb/core/metrics/InvocationFinishedEvent.java
@@ -23,13 +23,21 @@
 public class InvocationFinishedEvent implements Event {
   private final String operationName;
 
+  private final InvocationType invocationType;
+
   private final long finishedTime;
 
   private final long processElapsedNanoTime;
 
   private final long totalElapsedNanoTime;
 
-  private final InvocationType invocationType;
+  public String getOperationName() {
+    return operationName;
+  }
+
+  public InvocationType getInvocationType() {
+    return invocationType;
+  }
 
   public long getProcessElapsedNanoTime() {
     return processElapsedNanoTime;
@@ -39,14 +47,6 @@ public long getTotalElapsedNanoTime() {
     return totalElapsedNanoTime;
   }
 
-  public InvocationType getInvocationType() {
-    return invocationType;
-  }
-
-  public String getOperationName() {
-    return operationName;
-  }
-
   public InvocationFinishedEvent(String operationName, InvocationType invocationType, long finishedTime,
       long processElapsedNanoTime,
       long totalElapsedNanoTime) {
diff --git a/core/src/main/java/io/servicecomb/core/metrics/InvocationStartProcessingEvent.java b/core/src/main/java/io/servicecomb/core/metrics/InvocationStartProcessingEvent.java
index 3d39982ce..9f8ec9460 100644
--- a/core/src/main/java/io/servicecomb/core/metrics/InvocationStartProcessingEvent.java
+++ b/core/src/main/java/io/servicecomb/core/metrics/InvocationStartProcessingEvent.java
@@ -23,16 +23,12 @@
 public class InvocationStartProcessingEvent implements Event {
   private final String operationName;
 
+  private final InvocationType invocationType;
+
   private final long startProcessingTime;
 
   private final long inQueueNanoTime;
 
-  private final InvocationType invocationType;
-
-  public long getInQueueNanoTime() {
-    return inQueueNanoTime;
-  }
-
   public String getOperationName() {
     return operationName;
   }
@@ -41,7 +37,12 @@ public InvocationType getInvocationType() {
     return invocationType;
   }
 
-  public InvocationStartProcessingEvent(String operationName, InvocationType invocationType, long startProcessingTime, long inQueueNanoTime) {
+  public long getInQueueNanoTime() {
+    return inQueueNanoTime;
+  }
+
+  public InvocationStartProcessingEvent(String operationName, InvocationType invocationType, long startProcessingTime,
+      long inQueueNanoTime) {
     this.operationName = operationName;
     this.invocationType = invocationType;
     this.startProcessingTime = startProcessingTime;
diff --git a/core/src/main/java/io/servicecomb/core/metrics/InvocationStartedEvent.java b/core/src/main/java/io/servicecomb/core/metrics/InvocationStartedEvent.java
index 09b205b2b..b233a626f 100644
--- a/core/src/main/java/io/servicecomb/core/metrics/InvocationStartedEvent.java
+++ b/core/src/main/java/io/servicecomb/core/metrics/InvocationStartedEvent.java
@@ -18,22 +18,30 @@
 package io.servicecomb.core.metrics;
 
 import io.servicecomb.foundation.common.event.Event;
+import io.servicecomb.swagger.invocation.InvocationType;
 
 public class InvocationStartedEvent implements Event {
   private final String operationName;
 
+  private final InvocationType invocationType;
+
   private final long startedTime;
 
   public String getOperationName() {
     return operationName;
   }
 
+  public InvocationType getInvocationType() {
+    return invocationType;
+  }
+
   public long getStartedTime() {
     return startedTime;
   }
 
-  public InvocationStartedEvent(String operationName, long startedTime) {
+  public InvocationStartedEvent(String operationName, InvocationType invocationType, long startedTime) {
     this.operationName = operationName;
+    this.invocationType = invocationType;
     this.startedTime = startedTime;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/MetricsConst.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/MetricsConst.java
new file mode 100644
index 000000000..555479646
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/MetricsConst.java
@@ -0,0 +1,28 @@
+/*
+ * 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 io.servicecomb.metrics.core;
+
+public class MetricsConst {
+  public static final String CONSUMER_PREFIX_TEMPLATE = "servicecomb.%s.consumer";
+
+  public static final String PRODUCER_PREFIX_TEMPLATE = "servicecomb.%s.producer";
+
+  public static final String INSTANCE_CONSUMER_PREFIX = String.format(CONSUMER_PREFIX_TEMPLATE, "instance");
+
+  public static final String INSTANCE_PRODUCER_PREFIX = String.format(PRODUCER_PREFIX_TEMPLATE, "instance");
+}
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationFinishedEventListener.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
index 63ecc99ff..4c03dc8dc 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
@@ -20,7 +20,8 @@
 import io.servicecomb.core.metrics.InvocationFinishedEvent;
 import io.servicecomb.foundation.common.event.Event;
 import io.servicecomb.foundation.common.event.EventListener;
-import io.servicecomb.metrics.core.monitor.InvocationMonitor;
+import io.servicecomb.metrics.core.monitor.ConsumerInvocationMonitor;
+import io.servicecomb.metrics.core.monitor.ProducerInvocationMonitor;
 import io.servicecomb.metrics.core.monitor.RegistryMonitor;
 import io.servicecomb.swagger.invocation.InvocationType;
 
@@ -40,11 +41,12 @@ public InvocationFinishedEventListener(RegistryMonitor registryMonitor) {
   @Override
   public void process(Event data) {
     InvocationFinishedEvent event = (InvocationFinishedEvent) data;
-    InvocationMonitor monitor = registryMonitor.getInvocationMonitor(event.getOperationName());
     if (InvocationType.PRODUCER.equals(event.getInvocationType())) {
+      ProducerInvocationMonitor monitor = registryMonitor.getProducerInvocationMonitor(event.getOperationName());
       monitor.getExecutionTime().update(event.getProcessElapsedNanoTime());
       monitor.getProducerLatency().update(event.getTotalElapsedNanoTime());
     } else {
+      ConsumerInvocationMonitor monitor = registryMonitor.getConsumerInvocationMonitor(event.getOperationName());
       monitor.getConsumerLatency().update(event.getTotalElapsedNanoTime());
     }
   }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartProcessingEventListener.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartProcessingEventListener.java
index 1680ec325..dd29b3be8 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartProcessingEventListener.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartProcessingEventListener.java
@@ -20,7 +20,7 @@
 import io.servicecomb.core.metrics.InvocationStartProcessingEvent;
 import io.servicecomb.foundation.common.event.Event;
 import io.servicecomb.foundation.common.event.EventListener;
-import io.servicecomb.metrics.core.monitor.InvocationMonitor;
+import io.servicecomb.metrics.core.monitor.ProducerInvocationMonitor;
 import io.servicecomb.metrics.core.monitor.RegistryMonitor;
 import io.servicecomb.swagger.invocation.InvocationType;
 
@@ -40,9 +40,9 @@ public InvocationStartProcessingEventListener(RegistryMonitor registryMonitor) {
   @Override
   public void process(Event data) {
     InvocationStartProcessingEvent event = (InvocationStartProcessingEvent) data;
-    InvocationMonitor monitor = registryMonitor.getInvocationMonitor(event.getOperationName());
-    monitor.getWaitInQueue().increment(-1);
     if (InvocationType.PRODUCER.equals(event.getInvocationType())) {
+      ProducerInvocationMonitor monitor = registryMonitor.getProducerInvocationMonitor(event.getOperationName());
+      monitor.getWaitInQueue().increment(-1);
       monitor.getLifeTimeInQueue().update(event.getInQueueNanoTime());
     }
   }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartedEventListener.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartedEventListener.java
index c9b776340..7602c8271 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartedEventListener.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/event/InvocationStartedEventListener.java
@@ -20,7 +20,10 @@
 import io.servicecomb.core.metrics.InvocationStartedEvent;
 import io.servicecomb.foundation.common.event.Event;
 import io.servicecomb.foundation.common.event.EventListener;
+import io.servicecomb.metrics.core.monitor.ConsumerInvocationMonitor;
+import io.servicecomb.metrics.core.monitor.ProducerInvocationMonitor;
 import io.servicecomb.metrics.core.monitor.RegistryMonitor;
+import io.servicecomb.swagger.invocation.InvocationType;
 
 public class InvocationStartedEventListener implements EventListener {
 
@@ -38,6 +41,13 @@ public InvocationStartedEventListener(RegistryMonitor registryMonitor) {
   @Override
   public void process(Event data) {
     InvocationStartedEvent event = (InvocationStartedEvent) data;
-    registryMonitor.getInvocationMonitor(event.getOperationName()).getWaitInQueue().increment();
+    if (InvocationType.PRODUCER.equals(event.getInvocationType())) {
+      ProducerInvocationMonitor monitor = registryMonitor.getProducerInvocationMonitor(event.getOperationName());
+      monitor.getWaitInQueue().increment();
+      monitor.getProducerCall().increment();
+    } else {
+      ConsumerInvocationMonitor monitor = registryMonitor.getConsumerInvocationMonitor(event.getOperationName());
+      monitor.getConsumerCall().increment();
+    }
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/CallMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/CallMetric.java
new file mode 100644
index 000000000..9c3b0a7d7
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/CallMetric.java
@@ -0,0 +1,58 @@
+/*
+ * 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 io.servicecomb.metrics.core.metric;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CallMetric {
+  private final String prefix;
+
+  private final long total;
+
+  private final double tps;
+
+  public long getTotal() {
+    return total;
+  }
+
+  public double getTps() {
+    return tps;
+  }
+
+  public CallMetric(String prefix) {
+    this(prefix, 0, 0);
+  }
+
+  public CallMetric(String prefix, long total, double tps) {
+    this.prefix = prefix;
+    this.total = total;
+    this.tps = tps;
+  }
+
+  public CallMetric merge(CallMetric metric) {
+    return new CallMetric(this.prefix, this.total + metric.total, this.tps + metric.tps);
+  }
+
+  public Map<String, Number> toMap() {
+    Map<String, Number> metrics = new HashMap<>();
+    metrics.put(prefix + ".total", total);
+    metrics.put(prefix + ".tps", tps);
+    return metrics;
+  }
+}
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ConsumerInvocationMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ConsumerInvocationMetric.java
new file mode 100644
index 000000000..0c0ddfe01
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ConsumerInvocationMetric.java
@@ -0,0 +1,55 @@
+/*
+ * 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 io.servicecomb.metrics.core.metric;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ConsumerInvocationMetric extends InvocationMetric {
+  private final TimerMetric consumerLatency;
+
+  private final CallMetric consumerCall;
+
+  public TimerMetric getConsumerLatency() {
+    return consumerLatency;
+  }
+
+  public CallMetric getConsumerCall() {
+    return consumerCall;
+  }
+
+  public ConsumerInvocationMetric(String operationName, String prefix,
+      TimerMetric consumerLatency, CallMetric consumerCall) {
+    super(operationName, prefix);
+    this.consumerLatency = consumerLatency;
+    this.consumerCall = consumerCall;
+  }
+
+  public ConsumerInvocationMetric merge(ConsumerInvocationMetric metric) {
+    return new ConsumerInvocationMetric(this.getOperationName(), this.getPrefix(),
+        metric.getConsumerLatency().merge(consumerLatency),
+        metric.getConsumerCall().merge(consumerCall));
+  }
+
+  public Map<String, Number> toMap() {
+    Map<String, Number> metrics = new HashMap<>();
+    metrics.putAll(consumerLatency.toMap());
+    metrics.putAll(consumerCall.toMap());
+    return metrics;
+  }
+}
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InstanceMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InstanceMetric.java
index c3e8fa1b1..614fa485d 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InstanceMetric.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InstanceMetric.java
@@ -17,18 +17,30 @@
 
 package io.servicecomb.metrics.core.metric;
 
-public class InstanceMetric extends ModelMetric {
-
+public class InstanceMetric {
   private final SystemMetric systemMetric;
 
+  private final ConsumerInvocationMetric consumerMetric;
+
+  private final ProducerInvocationMetric producerMetric;
+
   public SystemMetric getSystemMetric() {
     return systemMetric;
   }
 
-  public InstanceMetric(long waitInQueue, SystemMetric systemMetric,
-      TimerMetric lifeTimeInQueue, TimerMetric executionTime, TimerMetric consumerLatency,
-      TimerMetric producerLatency) {
-    super(waitInQueue, lifeTimeInQueue, executionTime, consumerLatency, producerLatency);
+  public ConsumerInvocationMetric getConsumerMetric() {
+    return consumerMetric;
+  }
+
+  public ProducerInvocationMetric getProducerMetric() {
+    return producerMetric;
+  }
+
+  public InstanceMetric(SystemMetric systemMetric,
+      ConsumerInvocationMetric consumerMetric,
+      ProducerInvocationMetric producerMetric) {
     this.systemMetric = systemMetric;
+    this.consumerMetric = consumerMetric;
+    this.producerMetric = producerMetric;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InvocationMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InvocationMetric.java
index d62ddc3c5..c452a4e43 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InvocationMetric.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/InvocationMetric.java
@@ -17,17 +17,21 @@
 
 package io.servicecomb.metrics.core.metric;
 
-public class InvocationMetric extends ModelMetric {
+public class InvocationMetric {
   private final String operationName;
 
+  private final String prefix;
+
   public String getOperationName() {
     return operationName;
   }
 
-  public InvocationMetric(String operationName, long waitInQueue,
-      TimerMetric lifeTimeInQueue, TimerMetric executionTime, TimerMetric consumerLatency,
-      TimerMetric producerLatency) {
-    super(waitInQueue, lifeTimeInQueue, executionTime, consumerLatency, producerLatency);
+  public String getPrefix() {
+    return prefix;
+  }
+
+  public InvocationMetric(String operationName, String prefix) {
     this.operationName = operationName;
+    this.prefix = prefix;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ModelMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ProducerInvocationMetric.java
similarity index 55%
rename from metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ModelMetric.java
rename to metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ProducerInvocationMetric.java
index 05436c93d..0692e9057 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ModelMetric.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/ProducerInvocationMetric.java
@@ -17,17 +17,20 @@
 
 package io.servicecomb.metrics.core.metric;
 
-public abstract class ModelMetric {
+import java.util.HashMap;
+import java.util.Map;
+
+public class ProducerInvocationMetric extends InvocationMetric {
   private final long waitInQueue;
 
   private final TimerMetric lifeTimeInQueue;
 
   private final TimerMetric executionTime;
 
-  private final TimerMetric consumerLatency;
-
   private final TimerMetric producerLatency;
 
+  private final CallMetric producerCall;
+
   public long getWaitInQueue() {
     return waitInQueue;
   }
@@ -40,21 +43,40 @@ public TimerMetric getExecutionTime() {
     return executionTime;
   }
 
-  public TimerMetric getConsumerLatency() {
-    return consumerLatency;
-  }
-
   public TimerMetric getProducerLatency() {
     return producerLatency;
   }
 
-  public ModelMetric(long waitInQueue,
-      TimerMetric lifeTimeInQueue, TimerMetric executionTime, TimerMetric consumerLatency,
-      TimerMetric producerLatency) {
+  public CallMetric getProducerCall() {
+    return producerCall;
+  }
+
+  public ProducerInvocationMetric(String operationName, String prefix, long waitInQueue,
+      TimerMetric lifeTimeInQueue, TimerMetric executionTime, TimerMetric producerLatency, CallMetric producerCall) {
+    super(operationName, prefix);
     this.waitInQueue = waitInQueue;
     this.lifeTimeInQueue = lifeTimeInQueue;
     this.executionTime = executionTime;
-    this.consumerLatency = consumerLatency;
     this.producerLatency = producerLatency;
+    this.producerCall = producerCall;
+  }
+
+  public ProducerInvocationMetric merge(ProducerInvocationMetric metric) {
+    return new ProducerInvocationMetric(this.getOperationName(), this.getPrefix(),
+        this.getWaitInQueue() + metric.getWaitInQueue(),
+        metric.getLifeTimeInQueue().merge(lifeTimeInQueue),
+        metric.getExecutionTime().merge(executionTime),
+        metric.getProducerLatency().merge(producerLatency),
+        metric.getProducerCall().merge(producerCall));
+  }
+
+  public Map<String, Number> toMap() {
+    Map<String, Number> metrics = new HashMap<>();
+    metrics.put(getPrefix() + ".waitInQueue.count", getWaitInQueue());
+    metrics.putAll(lifeTimeInQueue.toMap());
+    metrics.putAll(executionTime.toMap());
+    metrics.putAll(producerLatency.toMap());
+    metrics.putAll(producerCall.toMap());
+    return metrics;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/RegistryMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/RegistryMetric.java
index 7569420bc..7bafee798 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/RegistryMetric.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/RegistryMetric.java
@@ -17,49 +17,72 @@
 
 package io.servicecomb.metrics.core.metric;
 
+import java.util.HashMap;
 import java.util.Map;
 
-import io.servicecomb.metrics.core.extra.SystemResource;
-import io.servicecomb.metrics.core.monitor.RegistryMonitor;
+import io.servicecomb.metrics.core.MetricsConst;
 
 public class RegistryMetric {
 
   private final InstanceMetric instanceMetric;
 
-  private final Map<String, InvocationMetric> invocationMetrics;
+  private final Map<String, ConsumerInvocationMetric> consumerMetrics;
+
+  private final Map<String, ProducerInvocationMetric> producerMetrics;
 
   public InstanceMetric getInstanceMetric() {
     return instanceMetric;
   }
 
-  public Map<String, InvocationMetric> getInvocationMetrics() {
-    return invocationMetrics;
+  public Map<String, ConsumerInvocationMetric> getConsumerMetrics() {
+    return consumerMetrics;
+  }
+
+  public Map<String, ProducerInvocationMetric> getProducerMetrics() {
+    return producerMetrics;
   }
 
-  public RegistryMetric(SystemResource systemResource, RegistryMonitor registryMonitor, int pollerIndex) {
-    invocationMetrics = registryMonitor.toInvocationMetrics(pollerIndex);
+  public RegistryMetric(SystemMetric systemMetric,
+      Map<String, ConsumerInvocationMetric> consumerMetrics,
+      Map<String, ProducerInvocationMetric> producerMetrics) {
+
+    this.consumerMetrics = consumerMetrics;
+    this.producerMetrics = producerMetrics;
+
+    ConsumerInvocationMetric instanceConsumerInvocationMetric = new ConsumerInvocationMetric("instance",
+        MetricsConst.INSTANCE_CONSUMER_PREFIX,
+        new TimerMetric(MetricsConst.INSTANCE_PRODUCER_PREFIX + ".producerLatency"),
+        new CallMetric(MetricsConst.INSTANCE_CONSUMER_PREFIX + ".consumerCall"));
+    ProducerInvocationMetric instanceProducerInvocationMetric = new ProducerInvocationMetric("instance",
+        MetricsConst.INSTANCE_PRODUCER_PREFIX, 0,
+        new TimerMetric(MetricsConst.INSTANCE_PRODUCER_PREFIX + ".lifeTimeInQueue"),
+        new TimerMetric(MetricsConst.INSTANCE_PRODUCER_PREFIX + ".executionTime"),
+        new TimerMetric(MetricsConst.INSTANCE_PRODUCER_PREFIX + ".producerLatency"),
+        new CallMetric(MetricsConst.INSTANCE_PRODUCER_PREFIX + ".producerCall"));
 
     //sum instance level metric
-    long waitInQueue = 0;
-    TimerMetric lifeTimeInQueue = new TimerMetric();
-    TimerMetric executionTime = new TimerMetric();
-    TimerMetric consumerLatency = new TimerMetric();
-    TimerMetric producerLatency = new TimerMetric();
-    for (InvocationMetric metric : invocationMetrics.values()) {
-      waitInQueue += metric.getWaitInQueue();
-      lifeTimeInQueue = lifeTimeInQueue.merge(metric.getLifeTimeInQueue());
-      executionTime = executionTime.merge(metric.getExecutionTime());
-      consumerLatency = consumerLatency.merge(metric.getConsumerLatency());
-      producerLatency = producerLatency.merge(metric.getProducerLatency());
+    for (ConsumerInvocationMetric metric : consumerMetrics.values()) {
+      instanceConsumerInvocationMetric = instanceConsumerInvocationMetric.merge(metric);
+    }
+    for (ProducerInvocationMetric metric : producerMetrics.values()) {
+      instanceProducerInvocationMetric = instanceProducerInvocationMetric.merge(metric);
     }
 
-    SystemMetric systemMetric = new SystemMetric(systemResource.getCpuLoad(), systemResource.getCpuRunningThreads(),
-        systemResource.getHeapInit(), systemResource.getHeapMax(), systemResource.getHeapCommit(),
-        systemResource.getHeapUsed(),
-        systemResource.getNonHeapInit(), systemResource.getNonHeapMax(), systemResource.getNonHeapCommit(),
-        systemResource.getNonHeapUsed());
+    this.instanceMetric = new InstanceMetric(systemMetric,
+        instanceConsumerInvocationMetric, instanceProducerInvocationMetric);
+  }
 
-    instanceMetric = new InstanceMetric(waitInQueue, systemMetric, lifeTimeInQueue, executionTime, consumerLatency,
-        producerLatency);
+  public Map<String, Number> toMap() {
+    Map<String, Number> metrics = new HashMap<>();
+    metrics.putAll(instanceMetric.getSystemMetric().toMap());
+    metrics.putAll(instanceMetric.getConsumerMetric().toMap());
+    metrics.putAll(instanceMetric.getProducerMetric().toMap());
+    for (ConsumerInvocationMetric metric : consumerMetrics.values()) {
+      metrics.putAll(metric.toMap());
+    }
+    for (ProducerInvocationMetric metric : producerMetrics.values()) {
+      metrics.putAll(metric.toMap());
+    }
+    return metrics;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/SystemMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/SystemMetric.java
index be7725dfb..68fff7223 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/SystemMetric.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/SystemMetric.java
@@ -17,6 +17,9 @@
 
 package io.servicecomb.metrics.core.metric;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class SystemMetric {
   private final double cpuLoad;
 
@@ -92,4 +95,20 @@ public SystemMetric(double cpuLoad, int cpuRunningThreads,
     this.nonHeapCommit = nonHeapCommit;
     this.nonHeapUsed = nonHeapUsed;
   }
+
+  public Map<String, Number> toMap() {
+    String prefix = "servicecomb.instance.system";
+    Map<String, Number> metrics = new HashMap<>();
+    metrics.put(prefix + ".cpu.load", cpuLoad);
+    metrics.put(prefix + ".cpu.runningThreads", cpuRunningThreads);
+    metrics.put(prefix + ".heap.init", heapInit);
+    metrics.put(prefix + ".heap.max", heapMax);
+    metrics.put(prefix + ".heap.commit", heapCommit);
+    metrics.put(prefix + ".heap.used", heapUsed);
+    metrics.put(prefix + ".nonHeap.init", nonHeapInit);
+    metrics.put(prefix + ".nonHeap.max", nonHeapMax);
+    metrics.put(prefix + ".nonHeap.commit", nonHeapCommit);
+    metrics.put(prefix + ".nonHeap.used", nonHeapUsed);
+    return metrics;
+  }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/TimerMetric.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/TimerMetric.java
index 8bd7297db..0c3848033 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/TimerMetric.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/metric/TimerMetric.java
@@ -17,7 +17,12 @@
 
 package io.servicecomb.metrics.core.metric;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class TimerMetric {
+  private final String prefix;
+
   private final long total;
 
   private final long count;
@@ -48,15 +53,16 @@ public long getMax() {
     return max;
   }
 
-  public TimerMetric() {
-    this(0, 0, 0, 0);
+  public TimerMetric(String prefix) {
+    this(prefix, 0, 0, 0, 0);
   }
 
-  public TimerMetric(long total, long count, long min, long max) {
+  public TimerMetric(String prefix, long total, long count, long min, long max) {
+    this.prefix = prefix;
     this.total = total;
     this.count = count;
     if (count != 0) {
-      this.average = (double) total / (double) count;
+      this.average = total / (double) count;
     } else {
       this.average = 0;
     }
@@ -65,7 +71,7 @@ public TimerMetric(long total, long count, long min, long max) {
   }
 
   public TimerMetric merge(TimerMetric metric) {
-    return new TimerMetric(this.total + metric.total, this.count + metric.count,
+    return new TimerMetric(this.prefix, this.total + metric.total, this.count + metric.count,
         getMin(this.min, metric.min), getMax(this.max, metric.max));
   }
 
@@ -74,6 +80,16 @@ private long getMin(long value1, long value2) {
   }
 
   private long getMax(long value1, long value2) {
-    return value1 == 0 || value2 > value1 ? value2 : value1;
+    return value2 > value1 ? value2 : value1;
+  }
+
+  public Map<String, Number> toMap() {
+    Map<String, Number> metrics = new HashMap<>();
+    metrics.put(prefix + ".total", total);
+    metrics.put(prefix + ".count", count);
+    metrics.put(prefix + ".average", average);
+    metrics.put(prefix + ".max", max);
+    metrics.put(prefix + ".min", min);
+    return metrics;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/CallMonitor.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/CallMonitor.java
new file mode 100644
index 000000000..76778ca1e
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/CallMonitor.java
@@ -0,0 +1,55 @@
+/*
+ * 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 io.servicecomb.metrics.core.monitor;
+
+import com.netflix.servo.monitor.BasicCounter;
+import com.netflix.servo.monitor.MonitorConfig;
+import com.netflix.servo.monitor.StepCounter;
+
+import io.servicecomb.metrics.core.metric.CallMetric;
+
+public class CallMonitor {
+  private final String prefix;
+
+  private final BasicCounter total;
+
+  private final StepCounter tps;
+
+  public CallMonitor(String prefix) {
+    this.prefix = prefix;
+    this.total = new BasicCounter(MonitorConfig.builder(prefix + ".total").build());
+    this.tps = new StepCounter(MonitorConfig.builder(prefix + ".tps").build());
+  }
+
+  public void increment() {
+    total.increment();
+    tps.increment();
+  }
+
+  public CallMetric toMetric(int windowTimeIndex) {
+    return new CallMetric(this.prefix, total.getValue(windowTimeIndex).longValue(),
+        this.adjustValue(tps.getValue(windowTimeIndex).doubleValue()));
+  }
+
+  //for time-related monitor type, if stop poll value over one window time,
+  //the value may return -1 because servo can't known precise value of previous step
+  //so must change to return 0
+  public double adjustValue(double value) {
+    return value < 0 ? 0 : value;
+  }
+}
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java
new file mode 100644
index 000000000..a297ec446
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java
@@ -0,0 +1,46 @@
+/*
+ * 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 io.servicecomb.metrics.core.monitor;
+
+import io.servicecomb.metrics.core.MetricsConst;
+import io.servicecomb.metrics.core.metric.ConsumerInvocationMetric;
+
+public class ConsumerInvocationMonitor extends InvocationMonitor {
+  private final TimerMonitor consumerLatency;
+
+  private final CallMonitor consumerCall;
+
+  public TimerMonitor getConsumerLatency() {
+    return consumerLatency;
+  }
+
+  public CallMonitor getConsumerCall() {
+    return consumerCall;
+  }
+
+  public ConsumerInvocationMonitor(String operationName) {
+    super(operationName, String.format(MetricsConst.CONSUMER_PREFIX_TEMPLATE, operationName));
+    this.consumerLatency = new TimerMonitor(this.getPrefix() + ".consumerLatency");
+    this.consumerCall = new CallMonitor(this.getPrefix() + ".consumerCall");
+  }
+
+  public ConsumerInvocationMetric toMetric(int windowTimeIndex) {
+    return new ConsumerInvocationMetric(this.getOperationName(), this.getPrefix(),
+        consumerLatency.toMetric(windowTimeIndex), consumerCall.toMetric(windowTimeIndex));
+  }
+}
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/extra/DefaultSystemResource.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/DefaultSystemMonitor.java
similarity index 81%
rename from metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/extra/DefaultSystemResource.java
rename to metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/DefaultSystemMonitor.java
index c045dc662..d027a2c11 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/extra/DefaultSystemResource.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/DefaultSystemMonitor.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package io.servicecomb.metrics.core.extra;
+package io.servicecomb.metrics.core.monitor;
 
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
@@ -24,8 +24,10 @@
 
 import org.springframework.stereotype.Component;
 
+import io.servicecomb.metrics.core.metric.SystemMetric;
+
 @Component
-public class DefaultSystemResource implements SystemResource {
+public class DefaultSystemMonitor implements SystemMonitor {
 
   private final OperatingSystemMXBean systemMXBean;
 
@@ -33,12 +35,12 @@
 
   private final MemoryMXBean memoryMXBean;
 
-  public DefaultSystemResource() {
+  public DefaultSystemMonitor() {
     this(ManagementFactory.getOperatingSystemMXBean(), ManagementFactory.getThreadMXBean(),
         ManagementFactory.getMemoryMXBean());
   }
 
-  public DefaultSystemResource(OperatingSystemMXBean systemMXBean, ThreadMXBean threadMXBean,
+  public DefaultSystemMonitor(OperatingSystemMXBean systemMXBean, ThreadMXBean threadMXBean,
       MemoryMXBean memoryMXBean) {
     this.systemMXBean = systemMXBean;
     this.threadMXBean = threadMXBean;
@@ -94,4 +96,11 @@ public long getNonHeapCommit() {
   public long getNonHeapUsed() {
     return memoryMXBean.getNonHeapMemoryUsage().getUsed();
   }
+
+  @Override
+  public SystemMetric toMetric() {
+    return new SystemMetric(getCpuLoad(),
+        getCpuRunningThreads(), getHeapInit(), getHeapMax(), getHeapCommit(), getHeapUsed(),
+        getNonHeapInit(), getNonHeapMax(), getNonHeapCommit(), getNonHeapUsed());
+  }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/InvocationMonitor.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/InvocationMonitor.java
index 35a6ca8e2..c3c19a180 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/InvocationMonitor.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/InvocationMonitor.java
@@ -17,62 +17,21 @@
 
 package io.servicecomb.metrics.core.monitor;
 
-import com.netflix.servo.monitor.BasicCounter;
-import com.netflix.servo.monitor.MonitorConfig;
-
-import io.servicecomb.metrics.core.metric.InvocationMetric;
-
 public class InvocationMonitor {
   private final String operationName;
 
-  private final BasicCounter waitInQueue;
-
-  private final TimerMonitor lifeTimeInQueue;
-
-  private final TimerMonitor executionTime;
-
-  private final TimerMonitor consumerLatency;
-
-  private final TimerMonitor producerLatency;
+  private final String prefix;
 
   public String getOperationName() {
     return operationName;
   }
 
-  public BasicCounter getWaitInQueue() {
-    return waitInQueue;
-  }
-
-  public TimerMonitor getLifeTimeInQueue() {
-    return lifeTimeInQueue;
+  public String getPrefix() {
+    return prefix;
   }
 
-  public TimerMonitor getExecutionTime() {
-    return executionTime;
-  }
-
-  public TimerMonitor getConsumerLatency() {
-    return consumerLatency;
-  }
-
-  public TimerMonitor getProducerLatency() {
-    return producerLatency;
-  }
-
-  public InvocationMonitor(String operationName) {
+  public InvocationMonitor(String operationName, String prefix) {
     this.operationName = operationName;
-    this.waitInQueue = new BasicCounter(MonitorConfig.builder("waitInQueue").build());
-    this.lifeTimeInQueue = new TimerMonitor("lifeTimeInQueue");
-    this.executionTime = new TimerMonitor("executionTime");
-    this.consumerLatency = new TimerMonitor("consumerLatency");
-    this.producerLatency = new TimerMonitor("producerLatency");
-  }
-
-  public InvocationMetric toInvocationMetric(int pollerIndex) {
-    return new InvocationMetric(this.getOperationName(), this.getWaitInQueue().getValue(pollerIndex).longValue(),
-        this.lifeTimeInQueue.toTimerMetric(pollerIndex),
-        this.executionTime.toTimerMetric(pollerIndex),
-        this.consumerLatency.toTimerMetric(pollerIndex),
-        this.producerLatency.toTimerMetric(pollerIndex));
+    this.prefix = prefix;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java
new file mode 100644
index 000000000..b1f945f5b
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java
@@ -0,0 +1,74 @@
+/*
+ * 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 io.servicecomb.metrics.core.monitor;
+
+import com.netflix.servo.monitor.BasicCounter;
+import com.netflix.servo.monitor.MonitorConfig;
+
+import io.servicecomb.metrics.core.MetricsConst;
+import io.servicecomb.metrics.core.metric.ProducerInvocationMetric;
+
+public class ProducerInvocationMonitor extends InvocationMonitor {
+  private final BasicCounter waitInQueue;
+
+  private final TimerMonitor lifeTimeInQueue;
+
+  private final TimerMonitor executionTime;
+
+  private final TimerMonitor producerLatency;
+
+  private final CallMonitor producerCall;
+
+  public BasicCounter getWaitInQueue() {
+    return waitInQueue;
+  }
+
+  public TimerMonitor getLifeTimeInQueue() {
+    return lifeTimeInQueue;
+  }
+
+  public TimerMonitor getExecutionTime() {
+    return executionTime;
+  }
+
+  public TimerMonitor getProducerLatency() {
+    return producerLatency;
+  }
+
+  public CallMonitor getProducerCall() {
+    return producerCall;
+  }
+
+  public ProducerInvocationMonitor(String operationName) {
+    super(operationName, String.format(MetricsConst.PRODUCER_PREFIX_TEMPLATE, operationName));
+    this.waitInQueue = new BasicCounter(MonitorConfig.builder(this.getPrefix() + ".waitInQueue.count").build());
+    this.lifeTimeInQueue = new TimerMonitor(this.getPrefix() + ".lifeTimeInQueue");
+    this.executionTime = new TimerMonitor(this.getPrefix() + ".executionTime");
+    this.producerLatency = new TimerMonitor(this.getPrefix() + ".producerLatency");
+    this.producerCall = new CallMonitor(this.getPrefix() + ".producerCall");
+  }
+
+  public ProducerInvocationMetric toMetric(int windowTimeIndex) {
+    return new ProducerInvocationMetric(this.getOperationName(), this.getPrefix(),
+        this.getWaitInQueue().getValue(windowTimeIndex).longValue(),
+        lifeTimeInQueue.toMetric(windowTimeIndex),
+        executionTime.toMetric(windowTimeIndex),
+        producerLatency.toMetric(windowTimeIndex),
+        producerCall.toMetric(windowTimeIndex));
+  }
+}
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/RegistryMonitor.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/RegistryMonitor.java
index 75ffc33df..077246378 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/RegistryMonitor.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/RegistryMonitor.java
@@ -17,29 +17,50 @@
 
 package io.servicecomb.metrics.core.monitor;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import io.servicecomb.metrics.core.metric.InvocationMetric;
+import io.servicecomb.metrics.core.metric.ConsumerInvocationMetric;
+import io.servicecomb.metrics.core.metric.ProducerInvocationMetric;
+import io.servicecomb.metrics.core.metric.RegistryMetric;
 
 @Component
 public class RegistryMonitor {
 
-  private final Map<String, InvocationMonitor> invocationMonitors;
+  private final SystemMonitor systemMonitor;
 
-  public RegistryMonitor() {
-    this.invocationMonitors = new ConcurrentHashMap<>();
+  private final Map<String, ConsumerInvocationMonitor> consumerInvocationMonitors;
+
+  private final Map<String, ProducerInvocationMonitor> producerInvocationMonitors;
+
+  @Autowired
+  public RegistryMonitor(SystemMonitor systemMonitor) {
+    this.systemMonitor = systemMonitor;
+    this.consumerInvocationMonitors = new ConcurrentHashMap<>();
+    this.producerInvocationMonitors = new ConcurrentHashMap<>();
+  }
+
+  public ConsumerInvocationMonitor getConsumerInvocationMonitor(String operationName) {
+    return consumerInvocationMonitors.computeIfAbsent(operationName, i -> new ConsumerInvocationMonitor(operationName));
   }
 
-  public InvocationMonitor getInvocationMonitor(String operationName) {
-    return invocationMonitors.computeIfAbsent(operationName, i -> new InvocationMonitor(operationName));
+  public ProducerInvocationMonitor getProducerInvocationMonitor(String operationName) {
+    return producerInvocationMonitors.computeIfAbsent(operationName, i -> new ProducerInvocationMonitor(operationName));
   }
 
-  public Map<String, InvocationMetric> toInvocationMetrics(int pollerIndex) {
-    return invocationMonitors.values().stream().collect(Collectors.toMap(InvocationMonitor::getOperationName,
-        monitor -> monitor.toInvocationMetric(pollerIndex)));
+  public RegistryMetric toRegistryMetric(int windowTimeIndex) {
+    Map<String, ConsumerInvocationMetric> consumerInvocationMetrics = new HashMap<>();
+    for (ConsumerInvocationMonitor monitor : this.consumerInvocationMonitors.values()) {
+      consumerInvocationMetrics.put(monitor.getOperationName(), monitor.toMetric(windowTimeIndex));
+    }
+    Map<String, ProducerInvocationMetric> producerInvocationMetrics = new HashMap<>();
+    for (ProducerInvocationMonitor monitor : this.producerInvocationMonitors.values()) {
+      producerInvocationMetrics.put(monitor.getOperationName(), monitor.toMetric(windowTimeIndex));
+    }
+    return new RegistryMetric(systemMonitor.toMetric(), consumerInvocationMetrics, producerInvocationMetrics);
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/extra/SystemResource.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/SystemMonitor.java
similarity index 86%
rename from metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/extra/SystemResource.java
rename to metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/SystemMonitor.java
index d1b72beb9..1780e3f1b 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/extra/SystemResource.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/SystemMonitor.java
@@ -15,9 +15,11 @@
  * limitations under the License.
  */
 
-package io.servicecomb.metrics.core.extra;
+package io.servicecomb.metrics.core.monitor;
 
-public interface SystemResource {
+import io.servicecomb.metrics.core.metric.SystemMetric;
+
+public interface SystemMonitor {
   double getCpuLoad();
 
   int getCpuRunningThreads();
@@ -37,4 +39,6 @@
   long getNonHeapCommit();
 
   long getNonHeapUsed();
+
+  SystemMetric toMetric();
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/TimerMonitor.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/TimerMonitor.java
index 8d7e27605..1a1557194 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/TimerMonitor.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/monitor/TimerMonitor.java
@@ -17,6 +17,8 @@
 
 package io.servicecomb.metrics.core.monitor;
 
+import java.util.concurrent.TimeUnit;
+
 import com.netflix.servo.monitor.MaxGauge;
 import com.netflix.servo.monitor.MinGauge;
 import com.netflix.servo.monitor.MonitorConfig;
@@ -25,12 +27,17 @@
 import io.servicecomb.metrics.core.metric.TimerMetric;
 
 public class TimerMonitor {
+  private final String prefix;
+
+  //nanosecond sum
   private final StepCounter total;
 
   private final StepCounter count;
 
+  //nanosecond min
   private final MinGauge min;
 
+  //nanosecond max
   private final MaxGauge max;
 
   public void update(long value) {
@@ -42,15 +49,32 @@ public void update(long value) {
     }
   }
 
-  public TimerMonitor(String name) {
-    total = new StepCounter(MonitorConfig.builder(name + ".total").build());
-    count = new StepCounter(MonitorConfig.builder(name + ".count").build());
-    min = new MinGauge(MonitorConfig.builder(name + ".min").build());
-    max = new MaxGauge(MonitorConfig.builder(name + ".max").build());
+  public TimerMonitor(String prefix) {
+    this.prefix = prefix;
+    total = new StepCounter(MonitorConfig.builder(prefix + ".total").build());
+    count = new StepCounter(MonitorConfig.builder(prefix + ".count").build());
+    min = new MinGauge(MonitorConfig.builder(prefix + ".min").build());
+    max = new MaxGauge(MonitorConfig.builder(prefix + ".max").build());
+  }
+
+  public TimerMetric toMetric(int windowTimeIndex) {
+    return new TimerMetric(this.prefix,
+        this.convertNanosecondToMillisecond(this.adjustValue(total.getCount(windowTimeIndex))),
+        this.adjustValue(count.getCount(windowTimeIndex)),
+        this.convertNanosecondToMillisecond(this.adjustValue(min.getValue(windowTimeIndex))),
+        this.convertNanosecondToMillisecond(this.adjustValue(max.getValue(windowTimeIndex))));
+  }
+
+  //for time-related monitor type, if stop poll value over one window time,
+  //the value may return -1 because servo can't known precise value of previous step
+  //so must change to return 0
+  public long adjustValue(long value) {
+    return value < 0 ? 0 : value;
   }
 
-  public TimerMetric toTimerMetric(int pollerIndex) {
-    return new TimerMetric(total.getCount(pollerIndex), count.getCount(pollerIndex),
-        min.getValue(pollerIndex), max.getValue(pollerIndex));
+  //Counting use System.nano get more precise time
+  //so we need change unit to millisecond when ouput
+  public long convertNanosecondToMillisecond(long nanoValue) {
+    return TimeUnit.NANOSECONDS.toMillis(nanoValue);
   }
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DataSource.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DataSource.java
index de3977757..53ad61e1e 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DataSource.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DataSource.java
@@ -23,8 +23,40 @@
 
 public interface DataSource {
 
-  //?????Metric??
-  RegistryMetric getRegistryMetric(int pollerIndex);
+  /**  What's the WindowTime ?
+  We all know there are two major type of metric :
+   1.Time-unrelated,you can get the latest value any time immediately:
+   Counter -> increase or decrease
+   Guage -> set a certain one value
+   2.Time-related,only after a centain time pass you can compute the right value,"a centain time" called WindowTime
+   Max & Min -> the max value or min value in a centain time
+   Average -> average value, the simplest algorithm is f = sum / count
+   Rate -> like TPS,algorithm is f = sum / second
 
-  List<Long> getAppliedPollingIntervals();
+   Will be return "servicecomb.metrics.window_time" setting in microservice.yaml
+  */
+  List<Long> getAppliedWindowTime();
+
+  //return getRegistryMetric(0)
+  RegistryMetric getRegistryMetric();
+
+  /**
+   * windowTimeIndex usage example:
+   * if there is two window time set in "servicecomb.metrics.window_time" like 1000,2000
+   * then windowTimeIndex = 0 will return result of the setting 1000(1 second)
+   * windowTimeIndex = 1 will return result of the setting 2000(2 second)
+   *
+   * there are three monitor of max,min,total
+   * 0----------1----------2----------3----------  <-time line (second)
+   *   100,200    300,400                          <-value record
+   *
+   *                 ? getRegistryMetric(0) will return max=200 min=100 total=300
+   *                   getRegistryMetric(1) will return max=0 min=0 total=0
+   *                             ? getRegistryMetric(0) will return max=300 min=400 total=700
+   *                               getRegistryMetric(1) will return max=400 min=100 total=1000
+   *
+   * @param windowTimeIndex index of getAppliedWindowTime() item
+   * @return RegistryMetric
+   */
+  RegistryMetric getRegistryMetric(int windowTimeIndex);
 }
diff --git a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DefaultDataSource.java b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DefaultDataSource.java
index 70ddb18d7..95498845b 100644
--- a/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DefaultDataSource.java
+++ b/metrics/metrics-core/src/main/java/io/servicecomb/metrics/core/publish/DefaultDataSource.java
@@ -17,13 +17,7 @@
 
 package io.servicecomb.metrics.core.publish;
 
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executors;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -31,63 +25,37 @@
 import com.netflix.config.DynamicPropertyFactory;
 import com.netflix.servo.monitor.Pollers;
 
-import io.servicecomb.metrics.core.extra.SystemResource;
 import io.servicecomb.metrics.core.metric.RegistryMetric;
 import io.servicecomb.metrics.core.monitor.RegistryMonitor;
 
 @Component
 public class DefaultDataSource implements DataSource {
-  private static final String METRICS_POLLING_TIME = "servicecomb.metrics.polling.time";
-
-  private static final String METRICS_POLLING_MIN = "servicecomb.metrics.polling.min";
-
-  private final List<Long> appliedPollingIntervals;
+  private static final String METRICS_POLLING_TIME = "servicecomb.metrics.window_time";
 
   private final RegistryMonitor registryMonitor;
 
-  private final SystemResource systemResource;
-
-  private final Map<Integer, RegistryMetric> registryMetrics;
-
   @Autowired
-  public DefaultDataSource(SystemResource systemResource, RegistryMonitor registryMonitor) {
-    this(systemResource, registryMonitor,
-        DynamicPropertyFactory.getInstance().getStringProperty(METRICS_POLLING_TIME, "10000").get());
+  public DefaultDataSource(RegistryMonitor registryMonitor) {
+    this(registryMonitor, DynamicPropertyFactory.getInstance().getStringProperty(METRICS_POLLING_TIME, "5000").get());
   }
 
-  public DefaultDataSource(SystemResource systemResource, RegistryMonitor registryMonitor, String pollingSettings) {
-    this.registryMetrics = new ConcurrentHashMap<>();
-    this.systemResource = systemResource;
+  public DefaultDataSource(RegistryMonitor registryMonitor, String pollingSettings) {
     this.registryMonitor = registryMonitor;
-    //??????Polling???????? Servo???10000?10??????????100??
-    long minPollingTime = DynamicPropertyFactory.getInstance().getLongProperty(METRICS_POLLING_MIN, 100).get();
     System.getProperties().setProperty("servo.pollers", pollingSettings);
-
-    List<Long> intervals = Pollers.getPollingIntervals();
-    List<Long> appliedIntervals = new ArrayList<>();
-    for (int index = 0; index < intervals.size(); index++) {
-      int finalIndex = index;
-      long finalInterval = intervals.get(finalIndex) < minPollingTime ? minPollingTime : intervals.get(finalIndex);
-      final Runnable poller = () -> reloadRegistryMetric(finalIndex);
-      Executors.newScheduledThreadPool(1)
-          //for step counter correct work we need poll in time ,otherwise current step will return Datapoint.UNKNOWN (missing last sample)
-          .scheduleWithFixedDelay(poller, 0, (long) (finalInterval * 0.5), MILLISECONDS);
-      appliedIntervals.add(finalInterval);
-    }
-    this.appliedPollingIntervals = appliedIntervals;
   }
 
   @Override
-  public RegistryMetric getRegistryMetric(int pollerIndex) {
-    return registryMetrics.getOrDefault(pollerIndex, new RegistryMetric(systemResource, registryMonitor, pollerIndex));
+  public RegistryMetric getRegistryMetric() {
+    return getRegistryMetric(0);
   }
 
   @Override
-  public List<Long> getAppliedPollingIntervals() {
-    return appliedPollingIntervals;
+  public RegistryMetric getRegistryMetric(int windowTimeIndex) {
+    return registryMonitor.toRegistryMetric(windowTimeIndex);
   }
 
-  private void reloadRegistryMetric(Integer pollingIndex) {
-    registryMetrics.put(pollingIndex, new RegistryMetric(systemResource, registryMonitor, pollingIndex));
+  @Override
+  public List<Long> getAppliedWindowTime() {
+    return Pollers.getPollingIntervals();
   }
 }
diff --git a/metrics/metrics-core/src/test/java/io/servicecomb/metrics/core/TestEventAndRunner.java b/metrics/metrics-core/src/test/java/io/servicecomb/metrics/core/TestEventAndRunner.java
index f98f04fbb..d9a7e2b91 100644
--- a/metrics/metrics-core/src/test/java/io/servicecomb/metrics/core/TestEventAndRunner.java
+++ b/metrics/metrics-core/src/test/java/io/servicecomb/metrics/core/TestEventAndRunner.java
@@ -23,6 +23,8 @@
 import java.lang.management.MemoryUsage;
 import java.lang.management.OperatingSystemMXBean;
 import java.lang.management.ThreadMXBean;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import org.junit.Assert;
@@ -34,8 +36,8 @@
 import io.servicecomb.core.metrics.InvocationStartedEvent;
 import io.servicecomb.foundation.common.utils.EventUtils;
 import io.servicecomb.metrics.core.event.DefaultEventListenerManager;
-import io.servicecomb.metrics.core.extra.DefaultSystemResource;
 import io.servicecomb.metrics.core.metric.RegistryMetric;
+import io.servicecomb.metrics.core.monitor.DefaultSystemMonitor;
 import io.servicecomb.metrics.core.monitor.RegistryMonitor;
 import io.servicecomb.metrics.core.publish.DefaultDataSource;
 import io.servicecomb.swagger.invocation.InvocationType;
@@ -62,13 +64,18 @@ public void test() throws InterruptedException {
     when(nonHeap.getMax()).thenReturn(700L);
     when(nonHeap.getUsed()).thenReturn(800L);
 
-    RegistryMonitor monitor = new RegistryMonitor();
-    DefaultSystemResource systemResource = new DefaultSystemResource(systemMXBean, threadMXBean, memoryMXBean);
-    DefaultDataSource dataSource = new DefaultDataSource(systemResource, monitor, "2000");
+    DefaultSystemMonitor systemMonitor = new DefaultSystemMonitor(systemMXBean, threadMXBean, memoryMXBean);
+    RegistryMonitor monitor = new RegistryMonitor(systemMonitor);
+    DefaultDataSource dataSource = new DefaultDataSource(monitor, "1000");
 
-    DefaultEventListenerManager manager = new DefaultEventListenerManager(monitor);
+    List<Long> intervals = dataSource.getAppliedWindowTime();
+    Assert.assertEquals(intervals.size(), 1);
+    Assert.assertEquals(intervals.get(0).intValue(), 1000);
 
-    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", System.nanoTime()));
+    new DefaultEventListenerManager(monitor);
+
+    //fun1 is a PRODUCER invocation call twice and all is completed
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", InvocationType.PRODUCER, System.nanoTime()));
     EventUtils.triggerEvent(
         new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER, System.nanoTime(),
             TimeUnit.MILLISECONDS.toNanos(100)));
@@ -76,7 +83,7 @@ public void test() throws InterruptedException {
         .triggerEvent(new InvocationFinishedEvent("fun1", InvocationType.PRODUCER, System.nanoTime(),
             TimeUnit.MILLISECONDS.toNanos(200), TimeUnit.MILLISECONDS.toNanos(300)));
 
-    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", System.nanoTime()));
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", InvocationType.PRODUCER, System.nanoTime()));
     EventUtils.triggerEvent(
         new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER, System.nanoTime(),
             TimeUnit.MILLISECONDS.toNanos(300)));
@@ -84,84 +91,164 @@ public void test() throws InterruptedException {
         .triggerEvent(new InvocationFinishedEvent("fun1", InvocationType.PRODUCER, System.nanoTime(),
             TimeUnit.MILLISECONDS.toNanos(400), TimeUnit.MILLISECONDS.toNanos(700)));
 
-    EventUtils.triggerEvent(new InvocationStartedEvent("fun12", System.nanoTime()));
+    //fun3 is a PRODUCER invocation call uncompleted
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun3", InvocationType.PRODUCER, System.nanoTime()));
     EventUtils.triggerEvent(
-        new InvocationStartProcessingEvent("fun12", InvocationType.PRODUCER, System.nanoTime(),
+        new InvocationStartProcessingEvent("fun3", InvocationType.PRODUCER, System.nanoTime(),
             TimeUnit.MILLISECONDS.toNanos(500)));
+
+    //fun2 is a CONSUMER invocation call once and completed
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun2", InvocationType.CONSUMER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun2", InvocationType.CONSUMER, System.nanoTime(),
+            TimeUnit.MILLISECONDS.toNanos(100)));
     EventUtils
-        .triggerEvent(new InvocationFinishedEvent("fun12", InvocationType.PRODUCER, System.nanoTime(),
-            TimeUnit.MILLISECONDS.toNanos(600), TimeUnit.MILLISECONDS.toNanos(1100)));
-
-    EventUtils.triggerEvent(new InvocationStartedEvent("fun11", System.nanoTime()));
-
-    Thread.sleep(2000);
-
-    RegistryMetric model = dataSource.getRegistryMetric(0);
-
-    Assert.assertEquals(model.getInvocationMetrics().get("fun1").getWaitInQueue(), 0);
-    Assert.assertEquals(model.getInvocationMetrics().get("fun11").getWaitInQueue(), 1);
-    Assert.assertEquals(model.getInstanceMetric().getWaitInQueue(), 1);
-
-    Assert.assertEquals(model.getInvocationMetrics().get("fun1").getLifeTimeInQueue().getMin(),
-        TimeUnit.MILLISECONDS.toNanos(100),
-        0);
-    Assert.assertEquals(model.getInvocationMetrics().get("fun1").getLifeTimeInQueue().getMax(),
-        TimeUnit.MILLISECONDS.toNanos(300),
-        0);
-    Assert.assertEquals(
-        model.getInvocationMetrics().get("fun1").getLifeTimeInQueue().getAverage(), TimeUnit.MILLISECONDS.toNanos(200),
-        0);
-    Assert.assertEquals(model.getInstanceMetric().getLifeTimeInQueue().getMin(), TimeUnit.MILLISECONDS.toNanos(100), 0);
-    Assert.assertEquals(model.getInstanceMetric().getLifeTimeInQueue().getMax(), TimeUnit.MILLISECONDS.toNanos(500), 0);
-    Assert.assertEquals(model.getInstanceMetric().getLifeTimeInQueue().getAverage(), TimeUnit.MILLISECONDS.toNanos(300),
-        0);
-
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getExecutionTime().getMin(),
-            TimeUnit.MILLISECONDS.toNanos(200), 0);
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getExecutionTime().getMax(),
-            TimeUnit.MILLISECONDS.toNanos(400), 0);
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getExecutionTime().getAverage(),
-            TimeUnit.MILLISECONDS.toNanos(300),
-            0);
-    Assert.assertEquals(model.getInstanceMetric().getExecutionTime().getMin(), TimeUnit.MILLISECONDS.toNanos(200), 0);
-    Assert.assertEquals(model.getInstanceMetric().getExecutionTime().getMax(), TimeUnit.MILLISECONDS.toNanos(600), 0);
-    Assert
-        .assertEquals(model.getInstanceMetric().getExecutionTime().getAverage(), TimeUnit.MILLISECONDS.toNanos(400), 0);
-
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getProducerLatency().getMin(),
-            TimeUnit.MILLISECONDS.toNanos(300), 0);
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getProducerLatency().getMax(),
-            TimeUnit.MILLISECONDS.toNanos(700), 0);
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getProducerLatency().getAverage(),
-            TimeUnit.MILLISECONDS.toNanos(500),
-            0);
-    Assert.assertEquals(model.getInstanceMetric().getProducerLatency().getMin(), TimeUnit.MILLISECONDS.toNanos(300), 0);
-    Assert
-        .assertEquals(model.getInstanceMetric().getProducerLatency().getMax(), TimeUnit.MILLISECONDS.toNanos(1100), 0);
-    Assert
-        .assertEquals(model.getInstanceMetric().getProducerLatency().getAverage(), TimeUnit.MILLISECONDS.toNanos(700),
-            0);
-
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getConsumerLatency().getMin(),
-            TimeUnit.MILLISECONDS.toNanos(0), 0);
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getConsumerLatency().getMax(),
-            TimeUnit.MILLISECONDS.toNanos(0), 0);
-    Assert
-        .assertEquals(model.getInvocationMetrics().get("fun1").getConsumerLatency().getAverage(),
-            TimeUnit.MILLISECONDS.toNanos(0),
-            0);
-    Assert.assertEquals(model.getInstanceMetric().getConsumerLatency().getMin(), TimeUnit.MILLISECONDS.toNanos(0), 0);
-    Assert.assertEquals(model.getInstanceMetric().getConsumerLatency().getMax(), TimeUnit.MILLISECONDS.toNanos(0), 0);
-    Assert
-        .assertEquals(model.getInstanceMetric().getConsumerLatency().getAverage(), TimeUnit.MILLISECONDS.toNanos(0), 0);
+        .triggerEvent(new InvocationFinishedEvent("fun2", InvocationType.CONSUMER, System.nanoTime(),
+            TimeUnit.MILLISECONDS.toNanos(200), TimeUnit.MILLISECONDS.toNanos(300)));
+
+    //fun4 is a invocation call only started and no processing start and finished
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun4", InvocationType.PRODUCER, System.nanoTime()));
+
+    //sim lease one window time
+    Thread.sleep(1000);
+
+    RegistryMetric model = dataSource.getRegistryMetric();
+
+    //check InstanceMetric
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getWaitInQueue(), 1);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getLifeTimeInQueue().getCount(), 3);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getLifeTimeInQueue().getTotal(),
+        900, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getLifeTimeInQueue().getAverage(),
+        300, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getLifeTimeInQueue().getMax(),
+        500, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getLifeTimeInQueue().getMin(),
+        100, 0);
+
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getExecutionTime().getCount(), 2);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getExecutionTime().getTotal(),
+        600, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getExecutionTime().getAverage(),
+        300, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getExecutionTime().getMax(),
+        400, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getExecutionTime().getMin(),
+        200, 0);
+
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerLatency().getCount(), 2);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerLatency().getTotal(),
+        1000, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerLatency().getAverage(),
+        500, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerLatency().getMax(),
+        700, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerLatency().getMin(),
+        300, 0);
+
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerCall().getTps(), 4, 0);
+    Assert.assertEquals(model.getInstanceMetric().getProducerMetric().getProducerCall().getTotal(), 4);
+
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getCount(), 1);
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getTotal(),
+        300, 0);
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getAverage(),
+        300, 0);
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getMax(),
+        300, 0);
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getMin(),
+        300, 0);
+
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerCall().getTps(), 1, 0);
+    Assert.assertEquals(model.getInstanceMetric().getConsumerMetric().getConsumerCall().getTotal(), 1);
+
+    //check ProducerMetrics
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getWaitInQueue(), 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getLifeTimeInQueue().getCount(), 2);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getLifeTimeInQueue().getTotal(),
+        400, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getLifeTimeInQueue().getAverage(),
+        200, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getLifeTimeInQueue().getMax(),
+        300, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getLifeTimeInQueue().getMin(),
+        100, 0);
+
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getExecutionTime().getCount(), 2);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getExecutionTime().getTotal(),
+        600, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getExecutionTime().getAverage(),
+        300, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getExecutionTime().getMax(),
+        400, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getExecutionTime().getMin(),
+        200, 0);
+
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerLatency().getCount(), 2);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerLatency().getTotal(),
+        1000, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerLatency().getAverage(),
+        500, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerLatency().getMax(),
+        700, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerLatency().getMin(),
+        300, 0);
+
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerCall().getTps(), 2, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun1").getProducerCall().getTotal(), 2);
+
+    //fun3
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getWaitInQueue(), 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getLifeTimeInQueue().getCount(), 1);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getLifeTimeInQueue().getTotal(),
+        500, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getLifeTimeInQueue().getAverage(),
+        500, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getLifeTimeInQueue().getMax(),
+        500, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getLifeTimeInQueue().getMin(),
+        500, 0);
+
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getExecutionTime().getCount(), 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getExecutionTime().getTotal(),
+        0, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getExecutionTime().getAverage(),
+        0, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getExecutionTime().getMax(),
+        0, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getExecutionTime().getMin(),
+        0, 0);
+
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerLatency().getCount(), 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerLatency().getTotal(),
+        0, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerLatency().getAverage(),
+        0, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerLatency().getMax(),
+        0, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerLatency().getMin(),
+        0, 0);
+
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerCall().getTps(), 1, 0);
+    Assert.assertEquals(model.getProducerMetrics().get("fun3").getProducerCall().getTotal(), 1);
+
+    //check ConsumerMetrics
+    //no need
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerLatency().getCount(), 1);
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerLatency().getTotal(),
+        300, 0);
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerLatency().getAverage(),
+        300, 0);
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerLatency().getMax(),
+        300, 0);
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerLatency().getMin(),
+        300, 0);
+
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerCall().getTps(), 1, 0);
+    Assert.assertEquals(model.getConsumerMetrics().get("fun2").getConsumerCall().getTotal(), 1);
+
+    Map<String, Number> metrics = model.toMap();
+    Assert.assertEquals(metrics.size(), 72);
 
     Assert.assertEquals(model.getInstanceMetric().getSystemMetric().getCpuLoad(), 1.0, 0);
     Assert.assertEquals(model.getInstanceMetric().getSystemMetric().getCpuRunningThreads(), 2, 0);
@@ -174,4 +261,4 @@ public void test() throws InterruptedException {
     Assert.assertEquals(model.getInstanceMetric().getSystemMetric().getNonHeapMax(), 700, 0);
     Assert.assertEquals(model.getInstanceMetric().getSystemMetric().getNonHeapUsed(), 800, 0);
   }
-}
\ No newline at end of file
+}
diff --git a/metrics/metrics-sample/metrics-performance-test/src/main/resources/microservice.yaml b/metrics/metrics-sample/metrics-performance-test/src/main/resources/microservice.yaml
index 0e12fdeab..b5edcd167 100644
--- a/metrics/metrics-sample/metrics-performance-test/src/main/resources/microservice.yaml
+++ b/metrics/metrics-sample/metrics-performance-test/src/main/resources/microservice.yaml
@@ -1,18 +1,19 @@
-#
-#  Copyright 2017 Huawei Technologies Co., Ltd
-#
-#  Licensed 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.
-#
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
 
 # all interconnected microservices must belong to an application wth the same ID
 APPLICATION_ID: metricsPerfTest
@@ -29,7 +30,8 @@ cse:
 
 servicecomb:
   metrics:
-    #polling setting
-    polling:
-      #Time Unit is MILLISECONDS
-      time: 10000
\ No newline at end of file
+    #Support Muti-WindowTime (MILLISECONDS) like 10000,60000 (10s and 60s), Use WindowTimeIndex make selection,start from 0
+    #Default value is single WindowTime : 5000 (5 second)
+    #Will direct set value of "servo.pollers"
+    #More info can be found here : https://github.com/Netflix/servo/wiki/Getting-Started -> Polling Intervals Chapter
+    window_time: 5000
\ No newline at end of file
diff --git a/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java b/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java
index 68e95e30c..8a14252b8 100644
--- a/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java
+++ b/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java
@@ -39,6 +39,7 @@
 import io.servicecomb.foundation.metrics.performance.QueueMetrics;
 import io.servicecomb.foundation.metrics.performance.QueueMetricsData;
 import io.servicecomb.foundation.vertx.tcp.TcpConnection;
+import io.servicecomb.swagger.invocation.InvocationType;
 import io.servicecomb.swagger.invocation.Response;
 import io.servicecomb.swagger.invocation.exception.InvocationException;
 import io.servicecomb.transport.highway.message.RequestHeader;
@@ -167,7 +168,7 @@ private void sendResponse(Map<String, String> context, Response response) {
    */
   public void execute() {
     InvocationStartedEvent startedEvent = new InvocationStartedEvent(operationMeta.getMicroserviceQualifiedName(),
-        System.nanoTime());
+        InvocationType.PRODUCER, System.nanoTime());
     EventUtils.triggerEvent(startedEvent);
     QueueMetrics metricsData = initMetrics(operationMeta);
     operationMeta.getExecutor().execute(() -> runInExecutor(metricsData,startedEvent));


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services