You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/09/07 02:45:07 UTC

[incubator-servicecomb-java-chassis] 02/03: [SCB-894][WIP] measure http server

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

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git

commit 664f83d1dc9533c08a1a62228c90479872ff441f
Author: wujimin <wu...@huawei.com>
AuthorDate: Fri Sep 7 02:51:12 2018 +0800

    [SCB-894][WIP] measure http server
---
 .../vertx/metrics/DefaultHttpServerMetrics.java    | 140 ++++++++++++++
 .../metrics/metric/DefaultEndpointMetric.java      |  84 +++++++++
 .../metrics/metric/DefaultHttpSocketMetric.java    |  70 +++++++
 .../metrics/TestDefaultHttpServerMetrics.java      | 209 +++++++++++++++++++++
 4 files changed, 503 insertions(+)

diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java
new file mode 100644
index 0000000..ddfb958
--- /dev/null
+++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java
@@ -0,0 +1,140 @@
+/*
+ * 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.servicecomb.foundation.vertx.metrics;
+
+import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric;
+import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric;
+
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServer;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.core.net.SocketAddress;
+import io.vertx.core.spi.metrics.HttpServerMetrics;
+
+/**
+ * important: not singleton, every HttpServer instance relate to a HttpServerMetrics instance
+ */
+public class DefaultHttpServerMetrics implements HttpServerMetrics<Object, Object, DefaultHttpSocketMetric> {
+  private final DefaultEndpointMetric endpointMetric;
+
+  private final HttpServer server;
+
+  private final SocketAddress localAddress;
+
+  private final HttpServerOptions options;
+
+  public DefaultHttpServerMetrics(DefaultEndpointMetric endpointMetric, HttpServer server,
+      SocketAddress localAddress, HttpServerOptions options) {
+    this.endpointMetric = endpointMetric;
+    this.server = server;
+    this.localAddress = localAddress;
+    this.options = options;
+  }
+
+  public DefaultEndpointMetric getEndpointMetric() {
+    return endpointMetric;
+  }
+
+  public HttpServer getServer() {
+    return server;
+  }
+
+  public SocketAddress getLocalAddress() {
+    return localAddress;
+  }
+
+  public HttpServerOptions getOptions() {
+    return options;
+  }
+
+  @Override
+  public Object requestBegin(DefaultHttpSocketMetric socketMetric, HttpServerRequest request) {
+    return null;
+  }
+
+  @Override
+  public void requestReset(Object requestMetric) {
+
+  }
+
+  @Override
+  public Object responsePushed(DefaultHttpSocketMetric socketMetric, HttpMethod method, String uri,
+      HttpServerResponse response) {
+    return null;
+  }
+
+  @Override
+  public void responseEnd(Object requestMetric, HttpServerResponse response) {
+
+  }
+
+  @Override
+  public Object upgrade(Object requestMetric, ServerWebSocket serverWebSocket) {
+    return null;
+  }
+
+  @Override
+  public Object connected(DefaultHttpSocketMetric socketMetric, ServerWebSocket serverWebSocket) {
+    return null;
+  }
+
+  @Override
+  public void disconnected(Object serverWebSocketMetric) {
+
+  }
+
+  @Override
+  public DefaultHttpSocketMetric connected(SocketAddress remoteAddress, String remoteName) {
+    endpointMetric.onConnect();
+    return new DefaultHttpSocketMetric(endpointMetric);
+  }
+
+  @Override
+  public void disconnected(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress) {
+    endpointMetric.onDisconnect();
+    socketMetric.setConnected(false);
+  }
+
+  @Override
+  public void bytesRead(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
+    endpointMetric.addBytesRead(numberOfBytes);
+  }
+
+  @Override
+  public void bytesWritten(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
+    endpointMetric.addBytesWritten(numberOfBytes);
+  }
+
+  @Override
+  public void exceptionOccurred(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, Throwable t) {
+
+  }
+
+  @Override
+  @Deprecated
+  public boolean isEnabled() {
+    return true;
+  }
+
+  @Override
+  public void close() {
+
+  }
+}
diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java
new file mode 100644
index 0000000..f25ca64
--- /dev/null
+++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java
@@ -0,0 +1,84 @@
+/*
+ * 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.servicecomb.foundation.vertx.metrics.metric;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import io.vertx.core.net.SocketAddress;
+
+/**
+ * for one listen address, include multiple httpClient or httpServer
+ */
+public class DefaultEndpointMetric {
+  private SocketAddress address;
+
+  // summary of connect times from boot
+  // by this, we can know how many new connections connected recently
+  private AtomicLong connectCount = new AtomicLong();
+
+  // summary of disconnect times from boot
+  // by this, we can know how many connections disconnected recently
+  private AtomicLong disconnectCount = new AtomicLong();
+
+  private AtomicLong bytesRead = new AtomicLong();
+
+  private AtomicLong bytesWritten = new AtomicLong();
+
+  public DefaultEndpointMetric(SocketAddress address) {
+    this.address = address;
+  }
+
+  public SocketAddress getAddress() {
+    return address;
+  }
+
+  public long getConnectCount() {
+    return connectCount.get();
+  }
+
+  public long getDisconnectCount() {
+    return disconnectCount.get();
+  }
+
+  public long getCurrentConnectionCount() {
+    return connectCount.get() - disconnectCount.get();
+  }
+
+  public void onConnect() {
+    connectCount.incrementAndGet();
+  }
+
+  public void onDisconnect() {
+    disconnectCount.incrementAndGet();
+  }
+
+  public long getBytesRead() {
+    return bytesRead.get();
+  }
+
+  public long addBytesRead(long bytes) {
+    return bytesRead.addAndGet(bytes);
+  }
+
+  public long getBytesWritten() {
+    return bytesWritten.get();
+  }
+
+  public long addBytesWritten(long bytes) {
+    return bytesWritten.addAndGet(bytes);
+  }
+}
diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultHttpSocketMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultHttpSocketMetric.java
new file mode 100644
index 0000000..b486b62
--- /dev/null
+++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultHttpSocketMetric.java
@@ -0,0 +1,70 @@
+/*
+ * 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.servicecomb.foundation.vertx.metrics.metric;
+
+public class DefaultHttpSocketMetric {
+  private DefaultEndpointMetric endpointMetric;
+
+  private boolean connected = true;
+
+  private long connectedTime = System.nanoTime();
+
+  private long requestBeginTime;
+
+  private long requestEndTime;
+
+  public DefaultHttpSocketMetric(DefaultEndpointMetric endpointMetric) {
+    this.endpointMetric = endpointMetric;
+  }
+
+  public void setEndpointMetric(DefaultEndpointMetric endpointMetric) {
+    this.endpointMetric = endpointMetric;
+  }
+
+  @SuppressWarnings("unchecked")
+  public <T extends DefaultEndpointMetric> T getEndpointMetric() {
+    return (T) endpointMetric;
+  }
+
+  public boolean isConnected() {
+    return connected;
+  }
+
+  public void setConnected(boolean connected) {
+    this.connected = connected;
+  }
+
+  public long getConnectedTime() {
+    return connectedTime;
+  }
+
+  public long getRequestBeginTime() {
+    return requestBeginTime;
+  }
+
+  public void requestBegin() {
+    this.requestBeginTime = System.nanoTime();
+  }
+
+  public long getRequestEndTime() {
+    return requestEndTime;
+  }
+
+  public void requestEnd() {
+    this.requestEndTime = System.nanoTime();
+  }
+}
diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java
new file mode 100644
index 0000000..b039cdd
--- /dev/null
+++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java
@@ -0,0 +1,209 @@
+/*
+ * 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.servicecomb.foundation.vertx.metrics;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric;
+import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.core.http.HttpServer;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.net.SocketAddress;
+import mockit.Mocked;
+
+public class TestDefaultHttpServerMetrics {
+  @Mocked
+  Vertx vertx;
+
+  VertxOptions vertxOptions = new VertxOptions();
+
+  MetricsOptionsEx metricsOptionsEx = new MetricsOptionsEx();
+
+  DefaultVertxMetrics defaultVertxMetrics;
+
+  @Mocked
+  HttpServer listen1_server1;
+
+  @Mocked
+  HttpServer listen1_server2;
+
+  @Mocked
+  SocketAddress listen1_addr;
+
+  @Mocked
+  HttpServer listen2_server1;
+
+  @Mocked
+  HttpServer listen2_server2;
+
+  @Mocked
+  SocketAddress listen2_addr;
+
+  @Mocked
+  HttpServerOptions options;
+
+  @Mocked
+  SocketAddress anyRemoteAddr;
+
+  DefaultHttpServerMetrics metrics_listen1_server1;
+
+  DefaultHttpServerMetrics metrics_listen1_server2;
+
+  DefaultEndpointMetric endpointMetric1;
+
+  DefaultHttpServerMetrics metrics_listen2_server1;
+
+  DefaultHttpServerMetrics metrics_listen2_server2;
+
+  DefaultEndpointMetric endpointMetric2;
+
+  String remoteName = "remote";
+
+  DefaultHttpSocketMetric socketMetric_listen1_1;
+
+  DefaultHttpSocketMetric socketMetric_listen1_2;
+
+  DefaultHttpSocketMetric socketMetric_listen2_1;
+
+  DefaultHttpSocketMetric socketMetric_listen2_2;
+
+  DefaultHttpSocketMetric socketMetric_listen2_3;
+
+  @Before
+  public void setup() {
+    vertxOptions.setMetricsOptions(metricsOptionsEx);
+    defaultVertxMetrics = new DefaultVertxMetrics(vertx, vertxOptions);
+
+    metrics_listen1_server1 = (DefaultHttpServerMetrics) defaultVertxMetrics
+        .createMetrics(listen1_server1, listen1_addr, options);
+    metrics_listen1_server2 = (DefaultHttpServerMetrics) defaultVertxMetrics
+        .createMetrics(listen1_server2, listen1_addr, options);
+    endpointMetric1 = metrics_listen1_server1.getEndpointMetric();
+
+    metrics_listen2_server1 = (DefaultHttpServerMetrics) defaultVertxMetrics
+        .createMetrics(listen2_server1, listen2_addr, options);
+    metrics_listen2_server2 = (DefaultHttpServerMetrics) defaultVertxMetrics
+        .createMetrics(listen2_server2, listen2_addr, options);
+    endpointMetric2 = metrics_listen2_server1.getEndpointMetric();
+
+    socketMetric_listen1_1 = metrics_listen1_server1.connected(anyRemoteAddr, remoteName);
+    socketMetric_listen1_2 = metrics_listen1_server2.connected(anyRemoteAddr, remoteName);
+    socketMetric_listen2_1 = metrics_listen2_server1.connected(anyRemoteAddr, remoteName);
+    socketMetric_listen2_2 = metrics_listen2_server2.connected(anyRemoteAddr, remoteName);
+    socketMetric_listen2_3 = metrics_listen2_server2.connected(anyRemoteAddr, remoteName);
+  }
+
+  @Test
+  public void createMetrics() {
+    Map<Object, Object> instances = new IdentityHashMap<>();
+    instances.put(metrics_listen1_server1, null);
+    instances.put(metrics_listen1_server2, null);
+    instances.put(metrics_listen2_server1, null);
+    instances.put(metrics_listen2_server2, null);
+    Assert.assertEquals(4, instances.size());
+
+    Assert.assertSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen1_server2.getEndpointMetric());
+    Assert.assertNotSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen2_server1.getEndpointMetric());
+    Assert.assertSame(metrics_listen2_server1.getEndpointMetric(), metrics_listen2_server2.getEndpointMetric());
+  }
+
+  @Test
+  public void connectionCount() {
+    Map<Object, Object> instances = new IdentityHashMap<>();
+    instances.put(socketMetric_listen1_1, null);
+    instances.put(socketMetric_listen1_2, null);
+    instances.put(socketMetric_listen2_1, null);
+    instances.put(socketMetric_listen2_2, null);
+    instances.put(socketMetric_listen2_3, null);
+    Assert.assertEquals(5, instances.size());
+
+    Assert.assertTrue(socketMetric_listen1_1.isConnected());
+    Assert.assertTrue(socketMetric_listen1_2.isConnected());
+    Assert.assertTrue(socketMetric_listen2_1.isConnected());
+    Assert.assertTrue(socketMetric_listen2_2.isConnected());
+    Assert.assertTrue(socketMetric_listen2_3.isConnected());
+
+    Assert.assertEquals(2, endpointMetric1.getCurrentConnectionCount());
+    Assert.assertEquals(3, endpointMetric2.getCurrentConnectionCount());
+
+    // disconnect
+    metrics_listen1_server1.disconnected(socketMetric_listen1_1, anyRemoteAddr);
+    metrics_listen1_server2.disconnected(socketMetric_listen1_2, anyRemoteAddr);
+    metrics_listen2_server1.disconnected(socketMetric_listen2_1, anyRemoteAddr);
+    metrics_listen2_server2.disconnected(socketMetric_listen2_2, anyRemoteAddr);
+    metrics_listen2_server2.disconnected(socketMetric_listen2_3, anyRemoteAddr);
+
+    Assert.assertFalse(socketMetric_listen1_1.isConnected());
+    Assert.assertFalse(socketMetric_listen1_2.isConnected());
+    Assert.assertFalse(socketMetric_listen2_1.isConnected());
+    Assert.assertFalse(socketMetric_listen2_2.isConnected());
+    Assert.assertFalse(socketMetric_listen2_3.isConnected());
+
+    Assert.assertEquals(0, endpointMetric1.getCurrentConnectionCount());
+    Assert.assertEquals(0, endpointMetric2.getCurrentConnectionCount());
+  }
+
+  @Test
+  public void bytesRead() {
+    metrics_listen1_server1.bytesRead(socketMetric_listen1_1, anyRemoteAddr, 1);
+    metrics_listen1_server2.bytesRead(socketMetric_listen1_2, anyRemoteAddr, 2);
+    metrics_listen2_server1.bytesRead(socketMetric_listen2_1, anyRemoteAddr, 3);
+    metrics_listen2_server2.bytesRead(socketMetric_listen2_2, anyRemoteAddr, 4);
+    metrics_listen2_server2.bytesRead(socketMetric_listen2_3, anyRemoteAddr, 5);
+
+    Assert.assertEquals(3, endpointMetric1.getBytesRead());
+    Assert.assertEquals(12, endpointMetric2.getBytesRead());
+  }
+
+  @Test
+  public void bytesWritten() {
+    metrics_listen1_server1.bytesWritten(socketMetric_listen1_1, anyRemoteAddr, 1);
+    metrics_listen1_server2.bytesWritten(socketMetric_listen1_2, anyRemoteAddr, 2);
+    metrics_listen2_server1.bytesWritten(socketMetric_listen2_1, anyRemoteAddr, 3);
+    metrics_listen2_server2.bytesWritten(socketMetric_listen2_2, anyRemoteAddr, 4);
+    metrics_listen2_server2.bytesWritten(socketMetric_listen2_3, anyRemoteAddr, 5);
+
+    Assert.assertEquals(3, endpointMetric1.getBytesWritten());
+    Assert.assertEquals(12, endpointMetric2.getBytesWritten());
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void meaningless() {
+    Assert.assertSame(listen1_server1, metrics_listen1_server1.getServer());
+    Assert.assertSame(listen1_addr, metrics_listen1_server1.getLocalAddress());
+    Assert.assertSame(options, metrics_listen1_server1.getOptions());
+    Assert.assertTrue(metrics_listen1_server1.isEnabled());
+
+    metrics_listen1_server1.requestBegin(null, null);
+    metrics_listen1_server1.requestReset(null);
+    metrics_listen1_server1.responsePushed(null, null, null, null);
+    metrics_listen1_server1.responseEnd(null, null);
+    metrics_listen1_server1.upgrade(null, null);
+    metrics_listen1_server1.connected((DefaultHttpSocketMetric) null, null);
+    metrics_listen1_server1.disconnected(null);
+    metrics_listen1_server1.exceptionOccurred(null, null, null);
+    metrics_listen1_server1.close();
+  }
+}