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/servicecomb-java-chassis.git
commit e6def8244c6990aaf396212adfbdf75eda53d7c0 Author: wujimin <[email protected]> AuthorDate: Thu Nov 22 08:57:49 2018 +0800 [SCB-1034] provide fast SimpleTimer to replace slow ServoTimer --- .../com/netflix/spectator/api/SpectatorUtils.java | 22 +++- .../AbstractPeriodMeter.java} | 30 ++++-- .../foundation/metrics/meter/PeriodMeter.java} | 15 ++- .../foundation/metrics/meter/SimpleTimer.java | 93 +++++++++++++++++ .../metrics/registry/GlobalRegistry.java | 114 +++++++++++++++++++++ .../foundation/metrics/meter/TestSimpleTimer.java} | 31 ++++-- .../metrics/metric/DefaultEndpointMetric.java | 32 +++--- java-chassis-dependencies/pom.xml | 2 +- java-chassis-distribution/src/release/LICENSE | 4 +- 9 files changed, 295 insertions(+), 48 deletions(-) diff --git a/foundations/foundation-test-scaffolding/src/main/java/com/netflix/spectator/api/SpectatorUtils.java b/foundations/foundation-metrics/src/main/java/com/netflix/spectator/api/SpectatorUtils.java similarity index 55% copy from foundations/foundation-test-scaffolding/src/main/java/com/netflix/spectator/api/SpectatorUtils.java copy to foundations/foundation-metrics/src/main/java/com/netflix/spectator/api/SpectatorUtils.java index 7a2f785..cccc710 100644 --- a/foundations/foundation-test-scaffolding/src/main/java/com/netflix/spectator/api/SpectatorUtils.java +++ b/foundations/foundation-metrics/src/main/java/com/netflix/spectator/api/SpectatorUtils.java @@ -16,8 +16,24 @@ */ package com.netflix.spectator.api; -public class SpectatorUtils { - public static CompositeRegistry createCompositeRegistry(Clock clock) { - return new CompositeRegistry(clock); +public final class SpectatorUtils { + private SpectatorUtils() { + } + + public static Id createDefaultId(String name) { + return new DefaultId(name); + } + + public static void removeExpiredMeters(Registry registry) { + if (registry instanceof AbstractRegistry) { + ((AbstractRegistry) registry).removeExpiredMeters(); + } + } + + public static void registerMeter(Registry registry, Meter meter) { + if (!(registry instanceof AbstractRegistry)) { + throw new IllegalStateException("registry must be a AbstractRegistry, class=" + registry.getClass().getName()); + } + ((AbstractRegistry) registry).getOrCreate(meter.id(), Meter.class, null, _id -> meter); } } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/AbstractPeriodMeter.java similarity index 60% copy from foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java copy to foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/AbstractPeriodMeter.java index 80a2055..d9e2f46 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/AbstractPeriodMeter.java @@ -14,19 +14,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.foundation.metrics; +package org.apache.servicecomb.foundation.metrics.meter; -/** - * give not standard meters to calc measurement , eg : cpu usage, net throughput, and so on - */ -public class PollEvent { - private final long msPollInterval; +import java.util.Collections; +import java.util.List; + +import com.netflix.spectator.api.Id; +import com.netflix.spectator.api.Measurement; + +public abstract class AbstractPeriodMeter implements PeriodMeter { + protected Id id; + + protected List<Measurement> allMeasurements = Collections.emptyList(); + + public Id id() { + return id; + } - public PollEvent(long msPollInterval) { - this.msPollInterval = msPollInterval; + @Override + public Iterable<Measurement> measure() { + return allMeasurements; } - public long getMsPollInterval() { - return msPollInterval; + public boolean hasExpired() { + return false; } } diff --git a/foundations/foundation-test-scaffolding/src/main/java/com/netflix/spectator/api/SpectatorUtils.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java similarity index 68% rename from foundations/foundation-test-scaffolding/src/main/java/com/netflix/spectator/api/SpectatorUtils.java rename to foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java index 7a2f785..f91d781 100644 --- a/foundations/foundation-test-scaffolding/src/main/java/com/netflix/spectator/api/SpectatorUtils.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java @@ -14,10 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.netflix.spectator.api; +package org.apache.servicecomb.foundation.metrics.meter; -public class SpectatorUtils { - public static CompositeRegistry createCompositeRegistry(Clock clock) { - return new CompositeRegistry(clock); - } +import java.util.List; + +import com.netflix.spectator.api.Measurement; +import com.netflix.spectator.api.Meter; + +public interface PeriodMeter extends Meter { + void calcMeasurements(long msNow, long secondInterval); + + void calcMeasurements(List<Measurement> measurements, long msNow, long secondInterval); } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/SimpleTimer.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/SimpleTimer.java new file mode 100644 index 0000000..09803a4 --- /dev/null +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/SimpleTimer.java @@ -0,0 +1,93 @@ +/* + * 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.metrics.meter; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.LongAdder; + +import com.netflix.spectator.api.Id; +import com.netflix.spectator.api.Measurement; +import com.netflix.spectator.api.Statistic; +import com.netflix.spectator.impl.AtomicDouble; + +/** + * ServoTimer is too slow + * this is a faster timer + */ +public class SimpleTimer extends AbstractPeriodMeter { + private static final double CNV_SECONDS = 1.0 / TimeUnit.SECONDS.toNanos(1L); + + private final Id idCount; + + private final Id idTotalTime; + + private final Id idMax; + + private final LongAdder count = new LongAdder(); + + private final LongAdder totalTime = new LongAdder(); + + private final AtomicDouble max = new AtomicDouble(); + + private long lastCount = 0; + + private long lastTotalTime = 0; + + public SimpleTimer(Id id) { + this.id = id; + this.idCount = id.withTag(Statistic.count); + this.idTotalTime = id.withTag(Statistic.totalTime); + this.idMax = id.withTag(Statistic.max); + } + + public void record(long nanoAmount) { + if (nanoAmount >= 0) { + totalTime.add(nanoAmount); + count.increment(); + max.max(nanoAmount); + } + } + + private Measurement newMeasurement(Id id, long msNow, Number n) { + return new Measurement(id, msNow, n.doubleValue()); + } + + @Override + public void calcMeasurements(long msNow, long secondInterval) { + List<Measurement> measurements = new ArrayList<>(3); + calcMeasurements(measurements, msNow, secondInterval); + allMeasurements = measurements; + } + + @Override + public void calcMeasurements(List<Measurement> measurements, long msNow, long secondInterval) { + long currentCount = count.longValue(); + long currentTotalTime = totalTime.longValue(); + + measurements.add(newMeasurement(idCount, msNow, (double) (currentCount - lastCount) / secondInterval)); + measurements + .add(newMeasurement(idTotalTime, msNow, (currentTotalTime - lastTotalTime) / secondInterval * CNV_SECONDS)); + measurements.add(newMeasurement(idMax, msNow, max.get() * CNV_SECONDS)); + + lastCount = currentCount; + lastTotalTime = currentTotalTime; + // maybe lost some max value, but not so important? + max.set(0); + } +} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/registry/GlobalRegistry.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/registry/GlobalRegistry.java new file mode 100644 index 0000000..9af39d0 --- /dev/null +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/registry/GlobalRegistry.java @@ -0,0 +1,114 @@ +/* + * 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.metrics.registry; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.servicecomb.foundation.metrics.PolledEvent; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; + +import com.netflix.spectator.api.Clock; +import com.netflix.spectator.api.Measurement; +import com.netflix.spectator.api.Meter; +import com.netflix.spectator.api.Registry; +import com.netflix.spectator.api.SpectatorUtils; + +public class GlobalRegistry { + private Clock clock; + + private List<Registry> registries = new CopyOnWriteArrayList<>(); + + private Registry defaultRegistry; + + public GlobalRegistry() { + this(Clock.SYSTEM); + } + + public GlobalRegistry(Clock clock) { + this.clock = clock; + } + + public Clock getClock() { + return clock; + } + + public List<Registry> getRegistries() { + return registries; + } + + public Registry getDefaultRegistry() { + return defaultRegistry; + } + + public synchronized void add(Registry registry) { + if (registries.isEmpty()) { + defaultRegistry = registry; + } + registries.add(registry); + } + + public synchronized void remove(Registry registry) { + registries.remove(registry); + if (registry != defaultRegistry) { + return; + } + + if (registries.isEmpty()) { + defaultRegistry = null; + return; + } + + defaultRegistry = registries.get(0); + } + + public synchronized void removeAll() { + registries.clear(); + defaultRegistry = null; + } + + @SuppressWarnings("unchecked") + public <T extends Registry> T find(Class<T> cls) { + for (Registry registry : registries) { + if (cls.isAssignableFrom(registry.getClass())) { + return (T) registry; + } + } + return null; + } + + public PolledEvent poll(long secondInterval) { + long msNow = clock.wallTime(); + List<Meter> meters = new ArrayList<>(); + List<Measurement> measurements = new ArrayList<>(); + for (Registry registry : registries) { + SpectatorUtils.removeExpiredMeters(registry); + + for (Meter meter : registry) { + if (meter instanceof PeriodMeter) { + ((PeriodMeter) meter).calcMeasurements(msNow, secondInterval); + } + + meters.add(meter); + meter.measure().forEach(measurements::add); + } + } + + return new PolledEvent(meters, measurements); + } +} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestSimpleTimer.java similarity index 51% rename from foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java rename to foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestSimpleTimer.java index 80a2055..1d34497 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestSimpleTimer.java @@ -14,19 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.foundation.metrics; +package org.apache.servicecomb.foundation.metrics.meter; -/** - * give not standard meters to calc measurement , eg : cpu usage, net throughput, and so on - */ -public class PollEvent { - private final long msPollInterval; +import org.junit.Assert; +import org.junit.Test; - public PollEvent(long msPollInterval) { - this.msPollInterval = msPollInterval; - } +import com.netflix.spectator.api.SpectatorUtils; + +public class TestSimpleTimer { + SimpleTimer timer = new SimpleTimer(SpectatorUtils.createDefaultId("name")); + + @Test + public void measure() { + timer.record(2); + timer.record(4); + + Assert.assertFalse(timer.measure().iterator().hasNext()); - public long getMsPollInterval() { - return msPollInterval; + timer.calcMeasurements(1, 2); + Assert.assertEquals( + "[Measurement(name:statistic=count,1,1.0), Measurement(name:statistic=totalTime,1,3.0000000000000004E-9), Measurement(name:statistic=max,1,4.0E-9)]", + timer.measure().toString()); + Assert.assertFalse(timer.hasExpired()); + Assert.assertEquals("name", timer.id().name()); } } 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 index f25ca64..86590ce 100644 --- 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 @@ -16,7 +16,7 @@ */ package org.apache.servicecomb.foundation.vertx.metrics.metric; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAdder; import io.vertx.core.net.SocketAddress; @@ -28,15 +28,15 @@ public class DefaultEndpointMetric { // summary of connect times from boot // by this, we can know how many new connections connected recently - private AtomicLong connectCount = new AtomicLong(); + private LongAdder connectCount = new LongAdder(); // summary of disconnect times from boot // by this, we can know how many connections disconnected recently - private AtomicLong disconnectCount = new AtomicLong(); + private LongAdder disconnectCount = new LongAdder(); - private AtomicLong bytesRead = new AtomicLong(); + private LongAdder bytesRead = new LongAdder(); - private AtomicLong bytesWritten = new AtomicLong(); + private LongAdder bytesWritten = new LongAdder(); public DefaultEndpointMetric(SocketAddress address) { this.address = address; @@ -47,38 +47,38 @@ public class DefaultEndpointMetric { } public long getConnectCount() { - return connectCount.get(); + return connectCount.longValue(); } public long getDisconnectCount() { - return disconnectCount.get(); + return disconnectCount.longValue(); } public long getCurrentConnectionCount() { - return connectCount.get() - disconnectCount.get(); + return connectCount.longValue() - disconnectCount.longValue(); } public void onConnect() { - connectCount.incrementAndGet(); + connectCount.increment(); } public void onDisconnect() { - disconnectCount.incrementAndGet(); + disconnectCount.increment(); } public long getBytesRead() { - return bytesRead.get(); + return bytesRead.longValue(); } - public long addBytesRead(long bytes) { - return bytesRead.addAndGet(bytes); + public void addBytesRead(long bytes) { + bytesRead.add(bytes); } public long getBytesWritten() { - return bytesWritten.get(); + return bytesWritten.longValue(); } - public long addBytesWritten(long bytes) { - return bytesWritten.addAndGet(bytes); + public void addBytesWritten(long bytes) { + bytesWritten.add(bytes); } } diff --git a/java-chassis-dependencies/pom.xml b/java-chassis-dependencies/pom.xml index 50a0778..0847d69 100644 --- a/java-chassis-dependencies/pom.xml +++ b/java-chassis-dependencies/pom.xml @@ -366,7 +366,7 @@ <dependency> <groupId>com.netflix.spectator</groupId> <artifactId>spectator-reg-servo</artifactId> - <version>0.63.0</version> + <version>0.71.0</version> </dependency> <dependency> <groupId>com.google.inject</groupId> diff --git a/java-chassis-distribution/src/release/LICENSE b/java-chassis-distribution/src/release/LICENSE index 31051f3..e166434 100644 --- a/java-chassis-distribution/src/release/LICENSE +++ b/java-chassis-distribution/src/release/LICENSE @@ -422,8 +422,8 @@ rxnetty-servo (https://github.com/ReactiveX/RxNetty) io.reactivex:rxnetty-servo: servo-core (https://github.com/Netflix/servo) com.netflix.servo:servo-core:jar:0.10.1 servo-internal (https://github.com/Netflix/servo) com.netflix.servo:servo-internal:jar:0.10.1 SnakeYAML (http://www.snakeyaml.org) org.yaml:snakeyaml:bundle:1.16 -spectator-api (https://github.com/Netflix/spectator) com.netflix.spectator:spectator-api:0.63.0 -spectator-reg-servo (https://github.com/Netflix/spectator) com.netflix.spectator:spectator-reg-servo:0.63.0 +spectator-api (https://github.com/Netflix/spectator) com.netflix.spectator:spectator-api:0.71.0 +spectator-reg-servo (https://github.com/Netflix/spectator) com.netflix.spectator:spectator-reg-servo:0.71.0 Spring AOP (https://github.com/spring-projects/spring-framework) org.springframework:spring-aop:jar:4.3.16.RELEASE Spring Aspects (https://github.com/spring-projects/spring-framework) org.springframework:spring-aspects:jar:4.3.16.RELEASE Spring Beans (https://github.com/spring-projects/spring-framework) org.springframework:spring-beans:jar:4.3.16.RELEASE
