From c041fa1f9331a96f65f5fe006f035d4679b41c04 Mon Sep 17 00:00:00 2001 From: wxbty <38374721+wxbty@users.noreply.github.com> Date: Sat, 25 Feb 2023 17:22:44 +0800 Subject: [PATCH] Observability task: registration center (#11493) --- dubbo-cluster/pom.xml | 6 + .../cluster/directory/AbstractDirectory.java | 63 +++-- .../directory/StaticDirectoryTest.java | 3 + .../support/AbstractClusterInvokerTest.java | 19 +- .../support/ConnectivityValidationTest.java | 3 + .../support/FailoverClusterInvokerTest.java | 12 +- .../wrapper/MockClusterInvokerTest.java | 3 + .../wrapper/MockProviderRpcExceptionTest.java | 3 + .../apache/dubbo/config/MetricsConfig.java | 15 +- dubbo-config/dubbo-config-api/pom.xml | 12 + .../deploy/DefaultApplicationDeployer.java | 8 + dubbo-distribution/dubbo-all/pom.xml | 8 + dubbo-distribution/dubbo-bom/pom.xml | 5 + dubbo-metrics/dubbo-metrics-api/pom.xml | 5 - .../event/SimpleMetricsEventMulticaster.java | 2 +- .../dubbo/metrics/model/MetricsKey.java | 23 +- .../apache/dubbo/metrics/model/TimePair.java | 5 + dubbo-metrics/dubbo-metrics-default/pom.xml | 6 + dubbo-metrics/dubbo-metrics-registry/pom.xml | 40 +++ .../collector/RegistryMetricsCollector.java | 123 +++++++++ .../collector/stat/RegistryStatComposite.java | 240 ++++++++++++++++++ .../collector/stat/ServiceKeyMetric.java | 83 ++++++ .../event/MetricsDirectoryListener.java | 43 ++++ .../registry/event/MetricsNotifyListener.java | 54 ++++ .../event/MetricsRegisterListener.java | 52 ++++ .../event/MetricsSubscribeListener.java | 52 ++++ .../metrics/registry/event/RegistryEvent.java | 156 ++++++++++++ .../RegistryMetricsEventMulticaster.java | 33 +++ ...e.dubbo.metrics.collector.MetricsCollector | 1 + .../RegistryMetricsCollectorTest.java | 115 +++++++++ .../collector/RegistryMetricsSampleTest.java | 97 +++++++ .../metrics/model/MethodMetricTest.java | 79 ++++++ .../model/sample/GaugeMetricSampleTest.java | 63 +++++ dubbo-metrics/pom.xml | 1 + dubbo-registry/dubbo-registry-api/pom.xml | 7 + .../ServiceInstancesChangedListener.java | 60 +++-- .../integration/RegistryDirectory.java | 39 ++- dubbo-test/dubbo-dependencies-all/pom.xml | 5 + 38 files changed, 1462 insertions(+), 82 deletions(-) create mode 100644 dubbo-metrics/dubbo-metrics-registry/pom.xml create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/ServiceKeyMetric.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsDirectoryListener.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/MethodMetricTest.java create mode 100644 dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/sample/GaugeMetricSampleTest.java diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml index f7235cf7d6..744d0f9f11 100644 --- a/dubbo-cluster/pom.xml +++ b/dubbo-cluster/pom.xml @@ -68,5 +68,11 @@ ${project.parent.version} test + + org.apache.dubbo + dubbo-metrics-registry + ${project.parent.version} + compile + diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java index eb69309f24..6af8bdb98d 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java @@ -16,6 +16,31 @@ */ package org.apache.dubbo.rpc.cluster.directory; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.Version; +import org.apache.dubbo.common.config.Configuration; +import org.apache.dubbo.common.config.ConfigurationUtils; +import org.apache.dubbo.common.constants.LoggerCodeConstants; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; +import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.cluster.Directory; +import org.apache.dubbo.rpc.cluster.Router; +import org.apache.dubbo.rpc.cluster.RouterChain; +import org.apache.dubbo.rpc.cluster.SingleRouterChain; +import org.apache.dubbo.rpc.cluster.router.state.BitList; +import org.apache.dubbo.rpc.cluster.support.ClusterUtils; +import org.apache.dubbo.rpc.model.ApplicationModel; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -31,29 +56,6 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.config.Configuration; -import org.apache.dubbo.common.config.ConfigurationUtils; -import org.apache.dubbo.common.constants.LoggerCodeConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; -import org.apache.dubbo.common.utils.ConcurrentHashSet; -import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcContext; -import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.cluster.Directory; -import org.apache.dubbo.rpc.cluster.Router; -import org.apache.dubbo.rpc.cluster.RouterChain; -import org.apache.dubbo.rpc.cluster.SingleRouterChain; -import org.apache.dubbo.rpc.cluster.router.state.BitList; -import org.apache.dubbo.rpc.cluster.support.ClusterUtils; -import org.apache.dubbo.rpc.model.ApplicationModel; - import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RECONNECT_TASK_PERIOD; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RECONNECT_TASK_TRY_COUNT; @@ -128,6 +130,10 @@ public abstract class AbstractDirectory implements Directory { */ private final int reconnectTaskPeriod; + private final GlobalMetricsEventMulticaster eventMulticaster; + + private ApplicationModel applicationModel; + public AbstractDirectory(URL url) { this(url, null, false); } @@ -153,7 +159,7 @@ public abstract class AbstractDirectory implements Directory { } // remove some local only parameters - ApplicationModel applicationModel = url.getOrDefaultApplicationModel(); + applicationModel = url.getOrDefaultApplicationModel(); this.queryMap = applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeLocalParams(queryMap); if (consumerUrl == null) { @@ -179,12 +185,14 @@ public abstract class AbstractDirectory implements Directory { this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT); this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD); setRouterChain(routerChain); + + eventMulticaster = applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class); } @Override public List> list(Invocation invocation) throws RpcException { if (destroyed) { - throw new RpcException("Directory of type " + this.getClass().getSimpleName() + " already destroyed for service " + getConsumerUrl().getServiceKey() + " from registry " + getUrl()); + throw new RpcException("Directory of type " + this.getClass().getSimpleName() + " already destroyed for service " + getConsumerUrl().getServiceKey() + " from registry " + getUrl()); } BitList> availableInvokers; @@ -381,6 +389,7 @@ public abstract class AbstractDirectory implements Directory { @Override public void addDisabledInvoker(Invoker invoker) { + eventMulticaster.publishEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.Type.D_DISABLE)); if (invokers.contains(invoker)) { disabledInvokers.add(invoker); removeValidInvoker(invoker); @@ -390,6 +399,7 @@ public abstract class AbstractDirectory implements Directory { @Override public void recoverDisabledInvoker(Invoker invoker) { + eventMulticaster.publishEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.Type.D_RECOVER_DISABLE)); if (disabledInvokers.remove(invoker)) { try { addValidInvoker(invoker); @@ -453,6 +463,7 @@ public abstract class AbstractDirectory implements Directory { this.invokers = invokers; refreshInvokerInternal(); this.invokersInitialized = true; + eventMulticaster.publishEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.Type.D_CURRENT, invokers.size())); } protected void destroyInvokers() { @@ -463,12 +474,14 @@ public abstract class AbstractDirectory implements Directory { } private boolean addValidInvoker(Invoker invoker) { + eventMulticaster.publishEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.Type.D_VALID)); synchronized (this.validInvokers) { return this.validInvokers.add(invoker); } } private boolean removeValidInvoker(Invoker invoker) { + eventMulticaster.publishEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.Type.D_UN_VALID)); synchronized (this.validInvokers) { return this.validInvokers.remove(invoker); } diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectoryTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectoryTest.java index 379d50b1c1..62787ccd2b 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectoryTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectoryTest.java @@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.cluster.directory; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.Holder; import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.cluster.router.MockInvoker; @@ -26,6 +27,7 @@ import org.apache.dubbo.rpc.cluster.router.condition.ConditionStateRouterFactory import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.state.StateRouter; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -60,6 +62,7 @@ class StaticDirectoryTest { List> filteredInvokers = router.route(invokers.clone(), URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation(), false, new Holder<>()); + ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class); StaticDirectory staticDirectory = new StaticDirectory<>(filteredInvokers); boolean isAvailable = staticDirectory.isAvailable(); Assertions.assertTrue(!isAvailable); diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java index 665a9ef65d..9028114aab 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java @@ -16,18 +16,11 @@ */ package org.apache.dubbo.rpc.cluster.support; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; - import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; @@ -41,6 +34,7 @@ import org.apache.dubbo.rpc.cluster.filter.DemoService; import org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance; import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance; import org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -50,6 +44,14 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static org.apache.dubbo.common.constants.CommonConstants.ENABLE_CONNECTIVITY_VALIDATION; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; @@ -104,6 +106,7 @@ class AbstractClusterInvokerTest { @SuppressWarnings({"unchecked"}) @BeforeEach public void setUp() throws Exception { + ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class); Map attributes = new HashMap<>(); attributes.put("application", "abstractClusterInvokerTest"); url = url.putAttribute(REFER_KEY, attributes); diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ConnectivityValidationTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ConnectivityValidationTest.java index 0ccb77b8d5..59fc9cfd10 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ConnectivityValidationTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ConnectivityValidationTest.java @@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.cluster.support; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; @@ -28,6 +29,7 @@ import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -70,6 +72,7 @@ class ConnectivityValidationTest { @BeforeEach public void setup() { + ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class); invoker1 = Mockito.mock(Invoker.class); invoker2 = Mockito.mock(Invoker.class); invoker3 = Mockito.mock(Invoker.class); diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java index 736d5a71d2..de20e2d262 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java @@ -16,11 +16,8 @@ */ package org.apache.dubbo.rpc.cluster.support; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - import org.apache.dubbo.common.URL; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; @@ -33,10 +30,15 @@ import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.SingleRouterChain; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; import org.apache.dubbo.rpc.cluster.router.state.BitList; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.protocol.AbstractInvoker; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertSame; @@ -65,7 +67,7 @@ class FailoverClusterInvokerTest { @BeforeEach public void setUp() throws Exception { - + ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class); dic = mock(Directory.class); given(dic.getUrl()).willReturn(url); diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java index 62646cb201..7db7129e81 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java @@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster.support.wrapper; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; @@ -28,6 +29,7 @@ import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.support.MockProtocol; import org.junit.jupiter.api.Assertions; @@ -49,6 +51,7 @@ class MockClusterInvokerTest { @BeforeEach public void beforeMethod() { + ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class); invokers.clear(); } diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockProviderRpcExceptionTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockProviderRpcExceptionTest.java index 89917f1de9..c0a737280f 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockProviderRpcExceptionTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockProviderRpcExceptionTest.java @@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster.support.wrapper; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.ProxyFactory; @@ -28,6 +29,7 @@ import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -46,6 +48,7 @@ class MockProviderRpcExceptionTest { @BeforeEach public void beforeMethod() { + ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class); invokers.clear(); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java index 1b8340138b..07a1e5f425 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java @@ -41,7 +41,12 @@ public class MetricsConfig extends AbstractConfig { private Boolean enableJvmMetrics; /** - * Enable jvm metrics when collecting. + * Enable registry metrics. + */ + private Boolean enableRegistryMetrics; + + /** + * Enable metadata metrics. */ private Boolean enableMetadataMetrics; @@ -103,6 +108,14 @@ public class MetricsConfig extends AbstractConfig { this.enableJvmMetrics = enableJvmMetrics; } + public Boolean getEnableRegistryMetrics() { + return enableRegistryMetrics; + } + + public void setEnableRegistryMetrics(Boolean enableRegistryMetrics) { + this.enableRegistryMetrics = enableRegistryMetrics; + } + public String getPort() { return port; } diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml index 2ba42d26a3..42ee10a4e0 100644 --- a/dubbo-config/dubbo-config-api/pom.xml +++ b/dubbo-config/dubbo-config-api/pom.xml @@ -42,12 +42,24 @@ ${project.parent.version} + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + org.apache.dubbo dubbo-metrics-default ${project.parent.version} + + org.apache.dubbo + dubbo-metrics-registry + ${project.parent.version} + + org.apache.dubbo dubbo-metrics-metadata diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java index c526864ab4..f605c6d09e 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java @@ -51,6 +51,9 @@ import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.metadata.report.MetadataReportFactory; import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; +import org.apache.dubbo.metrics.model.TimePair; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.metrics.report.MetricsReporter; import org.apache.dubbo.metrics.report.MetricsReporterFactory; import org.apache.dubbo.metrics.service.MetricsServiceExporter; @@ -825,10 +828,15 @@ public class DefaultApplicationDeployer extends AbstractDeployercompile true + + org.apache.dubbo + dubbo-metrics-registry + ${project.version} + compile + true + org.apache.dubbo dubbo-metrics-prometheus @@ -502,6 +509,7 @@ org.apache.dubbo:dubbo-metadata-report-zookeeper org.apache.dubbo:dubbo-metrics-api org.apache.dubbo:dubbo-metrics-default + org.apache.dubbo:dubbo-metrics-registry org.apache.dubbo:dubbo-metrics-metadata org.apache.dubbo:dubbo-metrics-prometheus org.apache.dubbo:dubbo-monitor-api diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index 42b26038cd..4b5b5fcd51 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -235,6 +235,11 @@ dubbo-metrics-default ${project.version} + + org.apache.dubbo + dubbo-metrics-registry + ${project.version} + org.apache.dubbo dubbo-metrics-prometheus diff --git a/dubbo-metrics/dubbo-metrics-api/pom.xml b/dubbo-metrics/dubbo-metrics-api/pom.xml index 7ee8df194d..3c31ae389c 100644 --- a/dubbo-metrics/dubbo-metrics-api/pom.xml +++ b/dubbo-metrics/dubbo-metrics-api/pom.xml @@ -36,11 +36,6 @@ dubbo-common ${project.parent.version} - - org.apache.dubbo - dubbo-cluster - ${project.parent.version} - org.apache.dubbo dubbo-rpc-api diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java index 6f5df6660b..c3f187c82e 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java @@ -71,7 +71,7 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster { publishTimeEvent(event, metricsLifeListener -> metricsLifeListener.onEventError(event)); } - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings({"rawtypes"}) private void publishTimeEvent(MetricsEvent event, Consumer consumer) { if (event instanceof EmptyEvent) { return; diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java index 96c879c8dd..39cecbfe49 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java @@ -23,7 +23,7 @@ public enum MetricsKey { // provider metrics key METRIC_REQUESTS("dubbo.%s.requests.total", "Total Requests"), METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", "Succeed Requests"), - METRIC_REQUEST_BUSINESS_FAILED("dubbo.%s.requests.business.failed.total","Failed Business Requests"), + METRIC_REQUEST_BUSINESS_FAILED("dubbo.%s.requests.business.failed.total", "Failed Business Requests"), METRIC_REQUESTS_PROCESSING("dubbo.%s.requests.processing", "Processing Requests"), METRIC_REQUESTS_TIMEOUT("dubbo.%s.requests.timeout.total", "Total Timeout Failed Requests"), METRIC_REQUESTS_LIMIT("dubbo.%s.requests.limit.total", "Total Limit Failed Requests"), @@ -59,6 +59,26 @@ public enum MetricsKey { GENERIC_METRIC_RT_P99("dubbo.%s.rt.seconds.p99", "Response Time P99"), GENERIC_METRIC_RT_P95("dubbo.%s.rt.seconds.p95", "Response Time P95"), + // register metrics key + REGISTER_METRIC_REQUESTS("dubbo.registry.register.requests.total", "Total Register Requests"), + REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.requests.succeed.total", "Succeed Register Requests"), + REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.requests.failed.total", "Failed Register Requests"), + + // subscribe metrics key + SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.num.total", "Total Subscribe Num"), + SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.registry.subscribe.num.succeed.total", "Succeed Subscribe Num"), + SUBSCRIBE_METRIC_NUM_FAILED("dubbo.registry.subscribe.num.failed.total", "Failed Subscribe Num"), + + // directory metrics key + DIRECTORY_METRIC_NUM_CURRENT("dubbo.registry.directory.num.current", "Current Directory Urls"), + DIRECTORY_METRIC_NUM_VALID("dubbo.registry.directory.num.valid.total", "Valid Directory Urls"), + DIRECTORY_METRIC_NUM_UN_VALID("dubbo.registry.directory.num.un_valid.total", "UnValid Directory Urls"), + DIRECTORY_METRIC_NUM_DISABLE("dubbo.registry.directory.num.disable.total", "Disable Directory Urls"), + DIRECTORY_METRIC_NUM_RECOVER_DISABLE("dubbo.registry.directory.num.recover.disable.total", "Recover Disable Directory Urls"), + + NOTIFY_METRIC_REQUESTS("dubbo.registry.notify.requests.total", "Total Notify Requests"), + NOTIFY_METRIC_NUM_LAST("dubbo.registry.notify.num.last", "Last Notify Nums"), + THREAD_POOL_CORE_SIZE("dubbo.thread.pool.core.size", "Thread Pool Core Size"), THREAD_POOL_LARGEST_SIZE("dubbo.thread.pool.largest.size", "Thread Pool Largest Size"), THREAD_POOL_MAX_SIZE("dubbo.thread.pool.max.size", "Thread Pool Max Size"), @@ -85,6 +105,7 @@ public enum MetricsKey { public final String getName() { return this.name; } + public final String getNameByType(String type) { return String.format(name, type); } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/TimePair.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/TimePair.java index 3994fe9dd2..70e0aba1d6 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/TimePair.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/TimePair.java @@ -21,6 +21,7 @@ public class TimePair { private final long begin; private long end; + private static final TimePair empty = new TimePair(0L); public TimePair(long currentTimeMillis) { this.begin = currentTimeMillis; @@ -37,4 +38,8 @@ public class TimePair { public long calc() { return end - begin; } + + public static TimePair empty() { + return empty; + } } diff --git a/dubbo-metrics/dubbo-metrics-default/pom.xml b/dubbo-metrics/dubbo-metrics-default/pom.xml index 71be413c6a..bc4165d765 100644 --- a/dubbo-metrics/dubbo-metrics-default/pom.xml +++ b/dubbo-metrics/dubbo-metrics-default/pom.xml @@ -46,5 +46,11 @@ micrometer-tracing-integration-test test + + org.apache.dubbo + dubbo-cluster + ${project.parent.version} + compile + diff --git a/dubbo-metrics/dubbo-metrics-registry/pom.xml b/dubbo-metrics/dubbo-metrics-registry/pom.xml new file mode 100644 index 0000000000..86f190ff76 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + org.apache.dubbo + dubbo-metrics + ${revision} + ../pom.xml + + dubbo-metrics-registry + jar + ${project.artifactId} + The metrics module of dubbo project + + false + + + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + + diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java new file mode 100644 index 0000000000..c30b7c0f11 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java @@ -0,0 +1,123 @@ +/* + * 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.dubbo.metrics.registry.collector; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.metrics.collector.ApplicationMetricsCollector; +import org.apache.dubbo.metrics.collector.MetricsCollector; +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.event.MetricsEventMulticaster; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; +import org.apache.dubbo.metrics.registry.event.RegistryMetricsEventMulticaster; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + + +/** + * Registry implementation of {@link MetricsCollector} + */ +@Activate +public class RegistryMetricsCollector implements ApplicationMetricsCollector { + + private Boolean collectEnabled = null; + private final RegistryStatComposite stats; + private final MetricsEventMulticaster registryMulticaster; + private final ApplicationModel applicationModel; + + public RegistryMetricsCollector(ApplicationModel applicationModel) { + this.stats = new RegistryStatComposite(); + this.registryMulticaster = new RegistryMetricsEventMulticaster(); + this.applicationModel = applicationModel; + } + + public void setCollectEnabled(Boolean collectEnabled) { + if (collectEnabled != null) { + this.collectEnabled = collectEnabled; + } + } + + @Override + public boolean isCollectEnabled() { + if (collectEnabled == null) { + ConfigManager configManager = applicationModel.getApplicationConfigManager(); + configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getEnableRegistryMetrics())); + } + return Optional.ofNullable(collectEnabled).orElse(false); + } + + public void setNum(RegistryEvent.Type registryType, String applicationName, Map lastNumMap) { + lastNumMap.forEach((serviceKey, num) -> + this.stats.setServiceKey(registryType, applicationName, serviceKey, num)); + } + + public void setNum(RegistryEvent.Type registryType, String applicationName, Integer num) { + this.stats.setApplicationKey(registryType, applicationName, num); + } + + + @Override + public void increment(String applicationName, RegistryEvent.Type registryType) { + this.stats.increment(registryType, applicationName); + } + + @Override + public void addRT(String applicationName, String registryOpType, Long responseTime) { + stats.calcRt(applicationName, registryOpType, responseTime); + } + + @Override + public List collect() { + if (!isCollectEnabled()) { + new ArrayList<>(); + } + List list = new ArrayList<>(); + list.addAll(stats.exportNumMetrics()); + list.addAll(stats.exportRtMetrics()); + list.addAll(stats.exportSkMetrics()); + + return list; + } + + @Override + public boolean isSupport(MetricsEvent event) { + return event instanceof RegistryEvent; + } + + @Override + public void onEvent(RegistryEvent event) { + registryMulticaster.publishEvent(event); + } + + + @Override + public void onEventFinish(RegistryEvent event) { + registryMulticaster.publishFinishEvent(event); + } + + @Override + public void onEventError(RegistryEvent event) { + registryMulticaster.publishErrorEvent(event); + } +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java new file mode 100644 index 0000000000..1d955cd7a7 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java @@ -0,0 +1,240 @@ +/* + * 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.dubbo.metrics.registry.collector.stat; + +import org.apache.dubbo.common.utils.ConcurrentHashMapUtils; +import org.apache.dubbo.metrics.collector.MetricsCollector; +import org.apache.dubbo.metrics.model.ApplicationMetric; +import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.MetricsKey; +import org.apache.dubbo.metrics.model.MetricsKeyWrapper; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; +import org.apache.dubbo.metrics.report.MetricsExport; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAccumulator; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * As a data aggregator, use internal data containers calculates and classifies + * the registry data collected by {@link MetricsCollector MetricsCollector}, and + * provides an {@link MetricsExport MetricsExport} interface for exporting standard output formats. + */ +public class RegistryStatComposite implements MetricsExport { + + + public Map> numStats = new ConcurrentHashMap<>(); + public Map> skStats = new ConcurrentHashMap<>(); + public List> rtStats = new ArrayList<>(); + public static String OP_TYPE_REGISTER = "register"; + public static String OP_TYPE_SUBSCRIBE = "subscribe"; + public static String OP_TYPE_NOTIFY = "notify"; + + public RegistryStatComposite() { + for (RegistryEvent.Type type : RegistryEvent.Type.values()) { + numStats.put(type, new ConcurrentHashMap<>()); + } + + rtStats.addAll(initStats(OP_TYPE_REGISTER)); + rtStats.addAll(initStats(OP_TYPE_SUBSCRIBE)); + rtStats.addAll(initStats(OP_TYPE_NOTIFY)); + } + + private List> initStats(String registryOpType) { + List> singleRtStats = new ArrayList<>(); + singleRtStats.add(new AtomicLongContainer(new MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_LAST))); + singleRtStats.add(new LongAccumulatorContainer(new MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_MIN), new LongAccumulator(Long::min, Long.MAX_VALUE))); + singleRtStats.add(new LongAccumulatorContainer(new MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_MAX), new LongAccumulator(Long::max, Long.MIN_VALUE))); + singleRtStats.add(new AtomicLongContainer(new MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_SUM), (responseTime, longAccumulator) -> longAccumulator.addAndGet(responseTime))); + // AvgContainer is a special counter that stores the number of times but outputs function of sum/times + AtomicLongContainer avgContainer = new AtomicLongContainer(new MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_AVG), (k, v) -> v.incrementAndGet()); + avgContainer.setValueSupplier(applicationName -> { + LongContainer totalContainer = rtStats.stream().filter(longContainer -> longContainer.isKeyWrapper(MetricsKey.GENERIC_METRIC_RT_SUM, registryOpType)).findFirst().get(); + AtomicLong totalRtTimes = avgContainer.get(applicationName); + AtomicLong totalRtSum = (AtomicLong) totalContainer.get(applicationName); + return totalRtSum.get() / totalRtTimes.get(); + }); + singleRtStats.add(avgContainer); + return singleRtStats; + } + + public void setApplicationKey(RegistryEvent.Type type, String applicationName, int num) { + if (!numStats.containsKey(type)) { + return; + } + numStats.get(type).computeIfAbsent(applicationName, k -> new AtomicLong(0L)).set(num); + } + + public void setServiceKey(RegistryEvent.Type type, String applicationName, String serviceKey, int num) { + if (!skStats.containsKey(type)) { + return; + } + skStats.get(type).computeIfAbsent(new ServiceKeyMetric(applicationName, serviceKey), k -> new AtomicLong(0L)).set(num); + } + + public void increment(RegistryEvent.Type type, String applicationName) { + if (!numStats.containsKey(type)) { + return; + } + numStats.get(type).computeIfAbsent(applicationName, k -> new AtomicLong(0L)).incrementAndGet(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public void calcRt(String applicationName, String registryOpType, Long responseTime) { + for (LongContainer container : rtStats.stream().filter(longContainer -> longContainer.specifyType(registryOpType)).collect(Collectors.toList())) { + Number current = (Number) ConcurrentHashMapUtils.computeIfAbsent(container, applicationName, container.getInitFunc()); + container.getConsumerFunc().accept(responseTime, current); + } + } + + @Override + public List exportNumMetrics() { + List list = new ArrayList<>(); + for (RegistryEvent.Type type : numStats.keySet()) { + Map stringAtomicLongMap = numStats.get(type); + for (String applicationName : stringAtomicLongMap.keySet()) { + list.add(convertToSample(applicationName, type, MetricsCategory.REGISTRY, stringAtomicLongMap.get(applicationName))); + } + } + return list; + } + + @Override + public List exportRtMetrics() { + List list = new ArrayList<>(); + for (LongContainer rtContainer : rtStats) { + MetricsKeyWrapper metricsKeyWrapper = rtContainer.getMetricsKeyWrapper(); + for (Map.Entry entry : rtContainer.entrySet()) { + list.add(new GaugeMetricSample(metricsKeyWrapper.targetKey(), metricsKeyWrapper.targetDesc(), ApplicationMetric.getTagsByName(entry.getKey()), MetricsCategory.RT, () -> rtContainer.getValueSupplier().apply(entry.getKey()))); + } + } + return list; + } + + public List exportSkMetrics() { + List list = new ArrayList<>(); + for (RegistryEvent.Type type : skStats.keySet()) { + Map stringAtomicLongMap = skStats.get(type); + for (ServiceKeyMetric serviceKeyMetric : stringAtomicLongMap.keySet()) { + list.add(new GaugeMetricSample(type.getMetricsKey(), serviceKeyMetric.getTags(), MetricsCategory.REGISTRY, stringAtomicLongMap.get(serviceKeyMetric)::get)); + } + } + return list; + } + + public GaugeMetricSample convertToSample(String applicationName, RegistryEvent.Type type, MetricsCategory category, AtomicLong targetNumber) { + return new GaugeMetricSample(type.getMetricsKey(), ApplicationMetric.getTagsByName(applicationName), category, targetNumber::get); + } + + + /** + * Collect Number type data + * + * @param + */ + public static class LongContainer extends ConcurrentHashMap { + + /** + * Provide the metric type name + */ + private final MetricsKeyWrapper metricsKeyWrapper; + /** + * The initial value corresponding to the key is generally 0 of different data types + */ + private final Function initFunc; + /** + * Statistical data calculation function, which can be self-increment, self-decrement, or more complex avg function + */ + private final BiConsumer consumerFunc; + /** + * Data output function required by {@link GaugeMetricSample GaugeMetricSample} + */ + private Function valueSupplier; + + + public LongContainer(MetricsKeyWrapper metricsKeyWrapper, Supplier initFunc, BiConsumer consumerFunc) { + this.metricsKeyWrapper = metricsKeyWrapper; + this.initFunc = s -> initFunc.get(); + this.consumerFunc = consumerFunc; + this.valueSupplier = k -> this.get(k).longValue(); + } + + public boolean specifyType(String type) { + return type.equals(getMetricsKeyWrapper().getType()); + } + + public MetricsKeyWrapper getMetricsKeyWrapper() { + return metricsKeyWrapper; + } + + public boolean isKeyWrapper(MetricsKey metricsKey, String registryOpType) { + return metricsKeyWrapper.isKey(metricsKey,registryOpType); + } + + public Function getInitFunc() { + return initFunc; + } + + public BiConsumer getConsumerFunc() { + return consumerFunc; + } + + public Function getValueSupplier() { + return valueSupplier; + } + + public void setValueSupplier(Function valueSupplier) { + this.valueSupplier = valueSupplier; + } + + @Override + public String toString() { + return "LongContainer{" + + "metricsKeyWrapper=" + metricsKeyWrapper + + '}'; + } + } + + public static class AtomicLongContainer extends LongContainer { + + public AtomicLongContainer(MetricsKeyWrapper metricsKeyWrapper) { + super(metricsKeyWrapper, AtomicLong::new, (responseTime, longAccumulator) -> longAccumulator.set(responseTime)); + } + + public AtomicLongContainer(MetricsKeyWrapper metricsKeyWrapper, BiConsumer consumerFunc) { + super(metricsKeyWrapper, AtomicLong::new, consumerFunc); + } + + } + + public static class LongAccumulatorContainer extends LongContainer { + public LongAccumulatorContainer(MetricsKeyWrapper metricsKeyWrapper, LongAccumulator accumulator) { + super(metricsKeyWrapper, () -> accumulator, (responseTime, longAccumulator) -> longAccumulator.accumulate(responseTime)); + } + } + + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/ServiceKeyMetric.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/ServiceKeyMetric.java new file mode 100644 index 0000000000..0b39ff8376 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/ServiceKeyMetric.java @@ -0,0 +1,83 @@ +/* + * 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.dubbo.metrics.registry.collector.stat; + +import org.apache.dubbo.metrics.model.Metric; + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName; + +/** + * Metric class for service. + */ +public class ServiceKeyMetric implements Metric { + private final String applicationName; + private final String serviceKey; + + public ServiceKeyMetric(String applicationName, String serviceKey) { + this.applicationName = applicationName; + this.serviceKey = serviceKey; + } + + public String getServiceKey() { + return serviceKey; + } + + public Map getTags() { + Map tags = new HashMap<>(); + tags.put(TAG_IP, getLocalHost()); + tags.put(TAG_HOSTNAME, getLocalHostName()); + tags.put(TAG_APPLICATION_NAME, applicationName); + + tags.put(TAG_INTERFACE_KEY, serviceKey); + return tags; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ServiceKeyMetric that = (ServiceKeyMetric) o; + + if (!applicationName.equals(that.applicationName)) return false; + return serviceKey.equals(that.serviceKey); + } + + @Override + public int hashCode() { + int result = applicationName.hashCode(); + result = 31 * result + serviceKey.hashCode(); + return result; + } + + @Override + public String toString() { + return "ServiceKeyMetric{" + + "applicationName='" + applicationName + '\'' + + ", serviceKey='" + serviceKey + '\'' + + '}'; + } +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsDirectoryListener.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsDirectoryListener.java new file mode 100644 index 0000000000..27648f962d --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsDirectoryListener.java @@ -0,0 +1,43 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.listener.MetricsListener; + +public class MetricsDirectoryListener implements MetricsListener { + + @Override + public boolean isSupport(MetricsEvent event) { + return event instanceof RegistryEvent.MetricsDirectoryEvent; + } + + @Override + public void onEvent(RegistryEvent.MetricsDirectoryEvent event) { + if (!event.isAvailable()) { + return; + } + if (event.getType().isIncrement()) { + event.getCollector().increment(event.getSource().getApplicationName(), event.getType()); + } else { + event.getCollector().setNum(event.getType(), event.getSource().getApplicationName(), event.getSize()); + } + } + + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java new file mode 100644 index 0000000000..3b5561cb1f --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java @@ -0,0 +1,54 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.listener.MetricsLifeListener; + +import static org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_NOTIFY; + +/** + * The registration center actively pushes Listener, no failure and rt statistics + */ +public class MetricsNotifyListener implements MetricsLifeListener { + + protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass()); + + @Override + public boolean isSupport(MetricsEvent event) { + return event instanceof RegistryEvent.MetricsNotifyEvent; + } + + @Override + public void onEvent(RegistryEvent.MetricsNotifyEvent event) { + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.N_TOTAL); + } + + @Override + public void onEventFinish(RegistryEvent.MetricsNotifyEvent event) { + event.getCollector().setNum(RegistryEvent.Type.N_LAST_NUM, event.getSource().getApplicationName(), event.getLastNotifyNum()); + event.getCollector().addRT(event.getSource().getApplicationName(), OP_TYPE_NOTIFY, event.getTimePair().calc()); + } + + @Override + public void onEventError(RegistryEvent.MetricsNotifyEvent event) { + } + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java new file mode 100644 index 0000000000..f3c6352fcf --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java @@ -0,0 +1,52 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.listener.MetricsLifeListener; + +import static org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_REGISTER; + +public class MetricsRegisterListener implements MetricsLifeListener { + + + @Override + public boolean isSupport(MetricsEvent event) { + return event instanceof RegistryEvent.MetricsRegisterEvent; + } + + @Override + public void onEvent(RegistryEvent.MetricsRegisterEvent event) { + if (!event.isAvailable()) { + return; + } + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.R_TOTAL); + } + + @Override + public void onEventFinish(RegistryEvent.MetricsRegisterEvent event) { + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.R_SUCCEED); + event.getCollector().addRT(event.getSource().getApplicationName(), OP_TYPE_REGISTER, event.getTimePair().calc()); + } + + @Override + public void onEventError(RegistryEvent.MetricsRegisterEvent event) { + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.R_FAILED); + event.getCollector().addRT(event.getSource().getApplicationName(), OP_TYPE_REGISTER, event.getTimePair().calc()); + } +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java new file mode 100644 index 0000000000..abfc5a0624 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java @@ -0,0 +1,52 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.listener.MetricsLifeListener; + +import static org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_SUBSCRIBE; + +public class MetricsSubscribeListener implements MetricsLifeListener { + + @Override + public boolean isSupport(MetricsEvent event) { + return event instanceof RegistryEvent.MetricsSubscribeEvent; + } + + @Override + public void onEvent(RegistryEvent.MetricsSubscribeEvent event) { + if (!event.isAvailable()) { + return; + } + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.S_TOTAL); + } + + @Override + public void onEventFinish(RegistryEvent.MetricsSubscribeEvent event) { + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.S_SUCCEED); + event.getCollector().addRT(event.getSource().getApplicationName(), OP_TYPE_SUBSCRIBE, event.getTimePair().calc()); + } + + @Override + public void onEventError(RegistryEvent.MetricsSubscribeEvent event) { + event.getCollector().increment(event.getSource().getApplicationName(), RegistryEvent.Type.S_FAILED); + event.getCollector().addRT(event.getSource().getApplicationName(), OP_TYPE_SUBSCRIBE, event.getTimePair().calc()); + } + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java new file mode 100644 index 0000000000..c13eb2310d --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java @@ -0,0 +1,156 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.event.TimeCounter; +import org.apache.dubbo.metrics.model.MetricsKey; +import org.apache.dubbo.metrics.model.TimePair; +import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.Map; + +/** + * Registry related events + */ +public class RegistryEvent extends MetricsEvent implements TimeCounter { + private final TimePair timePair; + private final RegistryMetricsCollector collector; + private final boolean available; + + public RegistryEvent(ApplicationModel applicationModel, TimePair timePair) { + super(applicationModel); + this.timePair = timePair; + this.collector = applicationModel.getBeanFactory().getBean(RegistryMetricsCollector.class); + this.available = this.collector != null && collector.isCollectEnabled(); + } + + public ApplicationModel getSource() { + return (ApplicationModel) source; + } + + public RegistryMetricsCollector getCollector() { + return collector; + } + + public boolean isAvailable() { + return available; + } + + @Override + public TimePair getTimePair() { + return timePair; + } + + public enum Type { + R_TOTAL(MetricsKey.REGISTER_METRIC_REQUESTS), + R_SUCCEED(MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED), + R_FAILED(MetricsKey.REGISTER_METRIC_REQUESTS_FAILED), + + S_TOTAL(MetricsKey.SUBSCRIBE_METRIC_NUM), + S_SUCCEED(MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED), + S_FAILED(MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED), + + D_VALID(MetricsKey.DIRECTORY_METRIC_NUM_VALID), + D_UN_VALID(MetricsKey.DIRECTORY_METRIC_NUM_UN_VALID), + D_DISABLE(MetricsKey.DIRECTORY_METRIC_NUM_DISABLE), + D_CURRENT(MetricsKey.DIRECTORY_METRIC_NUM_CURRENT, false), + D_RECOVER_DISABLE(MetricsKey.DIRECTORY_METRIC_NUM_RECOVER_DISABLE), + + N_TOTAL(MetricsKey.NOTIFY_METRIC_REQUESTS), + N_LAST_NUM(MetricsKey.NOTIFY_METRIC_NUM_LAST), + ; + + + private final MetricsKey metricsKey; + private final boolean isIncrement; + + + Type(MetricsKey metricsKey) { + this(metricsKey, true); + } + + Type(MetricsKey metricsKey, boolean isIncrement) { + this.metricsKey = metricsKey; + this.isIncrement = isIncrement; + } + + public MetricsKey getMetricsKey() { + return metricsKey; + } + + public boolean isIncrement() { + return isIncrement; + } + } + + public static class MetricsRegisterEvent extends RegistryEvent { + + public MetricsRegisterEvent(ApplicationModel applicationModel, TimePair timePair) { + super(applicationModel, timePair); + } + + } + + public static class MetricsSubscribeEvent extends RegistryEvent { + + public MetricsSubscribeEvent(ApplicationModel applicationModel, TimePair timePair) { + super(applicationModel, timePair); + } + + } + + public static class MetricsNotifyEvent extends RegistryEvent { + + private final Map lastNumMap; + + public MetricsNotifyEvent(ApplicationModel applicationModel, TimePair timePair, Map lastNumMap) { + super(applicationModel, timePair); + this.lastNumMap = lastNumMap; + } + + public Map getLastNotifyNum() { + return lastNumMap; + } + } + + public static class MetricsDirectoryEvent extends RegistryEvent { + + private final RegistryEvent.Type type; + private final int size; + + public MetricsDirectoryEvent(ApplicationModel applicationModel, RegistryEvent.Type type) { + this(applicationModel, type, 1); + } + + public MetricsDirectoryEvent(ApplicationModel applicationModel, RegistryEvent.Type type, int size) { + super(applicationModel, TimePair.empty()); + this.type = type; + this.size = size; + } + + public RegistryEvent.Type getType() { + return type; + } + + public int getSize() { + return size; + } + } +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java new file mode 100644 index 0000000000..566607efdb --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java @@ -0,0 +1,33 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster; + +public final class RegistryMetricsEventMulticaster extends SimpleMetricsEventMulticaster { + + public RegistryMetricsEventMulticaster() { + super.addListener(new MetricsRegisterListener()); + super.addListener(new MetricsSubscribeListener()); + super.addListener(new MetricsNotifyListener()); + super.addListener(new MetricsDirectoryListener()); + + setAvailable(); + } + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector b/dubbo-metrics/dubbo-metrics-registry/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector new file mode 100644 index 0000000000..3b14cf6c7b --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector @@ -0,0 +1 @@ +registry-collector=org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java new file mode 100644 index 0000000000..d4e8f34cec --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java @@ -0,0 +1,115 @@ +/* + * 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.dubbo.metrics.registry.metrics.collector; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; +import org.apache.dubbo.metrics.model.MetricsKey; +import org.apache.dubbo.metrics.model.MetricsKeyWrapper; +import org.apache.dubbo.metrics.model.TimePair; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_REGISTER; + + +class RegistryMetricsCollectorTest { + + private ApplicationModel applicationModel; + + @BeforeEach + public void setup() { + FrameworkModel frameworkModel = FrameworkModel.defaultModel(); + applicationModel = frameworkModel.newApplication(); + ApplicationConfig config = new ApplicationConfig(); + config.setName("MockMetrics"); + + applicationModel.getApplicationConfigManager().setApplication(config); + + } + + @AfterEach + public void teardown() { + applicationModel.destroy(); + } + + @Test + void testPushMetrics() throws InterruptedException { + + TimePair timePair = TimePair.start(); + GlobalMetricsEventMulticaster eventMulticaster = applicationModel.getBeanFactory().getOrRegisterBean(GlobalMetricsEventMulticaster.class); + RegistryMetricsCollector collector = applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class); + collector.setCollectEnabled(true); + + eventMulticaster.publishEvent(new RegistryEvent.MetricsRegisterEvent(applicationModel, timePair)); + List metricSamples = collector.collect(); + + // push success +1 + Assertions.assertEquals(metricSamples.size(), 1); + Assertions.assertTrue(metricSamples.get(0) instanceof GaugeMetricSample); + + eventMulticaster.publishFinishEvent(new RegistryEvent.MetricsRegisterEvent(applicationModel, timePair)); + // push finish rt +1 + metricSamples = collector.collect(); + //num(total+success) + rt(5) = 7 + Assertions.assertEquals(metricSamples.size(), 7); + long c1 = timePair.calc(); + TimePair lastTimePair = TimePair.start(); + eventMulticaster.publishEvent(new RegistryEvent.MetricsRegisterEvent(applicationModel, lastTimePair)); + Thread.sleep(50); + // push error rt +1 + eventMulticaster.publishErrorEvent(new RegistryEvent.MetricsRegisterEvent(applicationModel, lastTimePair)); + long c2 = lastTimePair.calc(); + metricSamples = collector.collect(); + + // num(total+success+error) + rt(5) + Assertions.assertEquals(metricSamples.size(), 8); + + // calc rt + for (MetricSample sample : metricSamples) { + Map tags = sample.getTags(); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName()); + } + Map sampleMap = metricSamples.stream().collect(Collectors.toMap(MetricSample::getName, k -> { + Number number = ((GaugeMetricSample) k).getSupplier().get(); + return number.longValue(); + })); + + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_LAST).targetKey()), lastTimePair.calc()); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_MIN).targetKey()), Math.min(c1, c2)); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_MAX).targetKey()), Math.max(c1, c2)); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_AVG).targetKey()), (c1 + c2) / 2); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_SUM).targetKey()), c1 + c2); + } + + + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java new file mode 100644 index 0000000000..92025d71c9 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java @@ -0,0 +1,97 @@ +/* + * 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.dubbo.metrics.registry.metrics.collector; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metrics.model.MetricsKey; +import org.apache.dubbo.metrics.model.MetricsKeyWrapper; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; +import org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; + +class RegistryMetricsSampleTest { + + private ApplicationModel applicationModel; + + @BeforeEach + public void setup() { + FrameworkModel frameworkModel = FrameworkModel.defaultModel(); + applicationModel = frameworkModel.newApplication(); + ApplicationConfig config = new ApplicationConfig(); + config.setName("MockMetrics"); + applicationModel.getApplicationConfigManager().setApplication(config); + } + + @AfterEach + public void teardown() { + applicationModel.destroy(); + } + + @Test + void testRegisterMetrics() { + } + + @Test + void testRTMetrics() { + RegistryMetricsCollector collector = new RegistryMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + String applicationName = applicationModel.getApplicationName(); + collector.addRT(applicationName, RegistryStatComposite.OP_TYPE_REGISTER, 10L); + collector.addRT(applicationName, RegistryStatComposite.OP_TYPE_REGISTER, 0L); + + List samples = collector.collect(); + for (MetricSample sample : samples) { + Map tags = sample.getTags(); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName); + } + + Map sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> { + Number number = ((GaugeMetricSample) k).getSupplier().get(); + return number.longValue(); + })); + + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(RegistryStatComposite.OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_LAST).targetKey()), 0L); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(RegistryStatComposite.OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_MIN).targetKey()), 0L); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(RegistryStatComposite.OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_MAX).targetKey()), 10L); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(RegistryStatComposite.OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_AVG).targetKey()), 5L); + Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(RegistryStatComposite.OP_TYPE_REGISTER, MetricsKey.GENERIC_METRIC_RT_SUM).targetKey()), 10L); + } + + @Test + void testListener() { + RegistryMetricsCollector collector = new RegistryMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + String applicationName = applicationModel.getApplicationName(); + collector.increment(applicationName,RegistryEvent.Type.R_TOTAL); + } + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/MethodMetricTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/MethodMetricTest.java new file mode 100644 index 0000000000..44beb3a608 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/MethodMetricTest.java @@ -0,0 +1,79 @@ +/* + * 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.dubbo.metrics.registry.metrics.model; + +import org.apache.dubbo.metrics.model.MethodMetric; +import org.apache.dubbo.rpc.RpcInvocation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName; + +class MethodMetricTest { + + private static final String applicationName = null; + private static String interfaceName; + private static String methodName; + private static String group; + private static String version; + private static RpcInvocation invocation; + + @BeforeAll + public static void setup() { + interfaceName = "org.apache.dubbo.MockInterface"; + methodName = "mockMethod"; + group = "mockGroup"; + version = "1.0.0"; + invocation = new RpcInvocation(methodName, interfaceName, "serviceKey", null, null); + invocation.setTargetServiceUniqueName(group + "/" + interfaceName + ":" + version); + invocation.setAttachment(GROUP_KEY, group); + invocation.setAttachment(VERSION_KEY, version); + } + + @Test + void test() { + MethodMetric metric = new MethodMetric(applicationName, invocation); + Assertions.assertEquals(metric.getInterfaceName(), interfaceName); + Assertions.assertEquals(metric.getMethodName(), methodName); + Assertions.assertEquals(metric.getGroup(), group); + Assertions.assertEquals(metric.getVersion(), version); + + Map tags = metric.getTags(); + Assertions.assertEquals(tags.get(TAG_IP), getLocalHost()); + Assertions.assertEquals(tags.get(TAG_HOSTNAME), getLocalHostName()); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName); + + Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName); + Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName); + Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group); + Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version); + } +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/sample/GaugeMetricSampleTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/sample/GaugeMetricSampleTest.java new file mode 100644 index 0000000000..bfa6d2e176 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/model/sample/GaugeMetricSampleTest.java @@ -0,0 +1,63 @@ +/* + * 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.dubbo.metrics.registry.metrics.model.sample; + +import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +class GaugeMetricSampleTest { + + private static String name; + private static String description; + private static Map tags; + private static MetricsCategory category; + private static String baseUnit; + private static Supplier supplier; + + @BeforeAll + public static void setup() { + name = "test"; + description = "test"; + tags = new HashMap<>(); + category = MetricsCategory.REQUESTS; + baseUnit = "byte"; + supplier = () -> 1; + } + + @Test + void test() { + GaugeMetricSample sample = new GaugeMetricSample(name, description, tags, category, baseUnit, supplier); + Assertions.assertEquals(sample.getName(), name); + Assertions.assertEquals(sample.getDescription(), description); + Assertions.assertEquals(sample.getTags(), tags); + Assertions.assertEquals(sample.getType(), MetricSample.Type.GAUGE); + Assertions.assertEquals(sample.getCategory(), category); + Assertions.assertEquals(sample.getBaseUnit(), baseUnit); + Assertions.assertEquals(sample.getSupplier().get(), 1); + sample.setSupplier(() -> 2); + Assertions.assertEquals(sample.getSupplier().get(), 2); + } +} diff --git a/dubbo-metrics/pom.xml b/dubbo-metrics/pom.xml index 835c2b1b44..d5527ecf7c 100644 --- a/dubbo-metrics/pom.xml +++ b/dubbo-metrics/pom.xml @@ -20,6 +20,7 @@ dubbo-metrics-api dubbo-metrics-default + dubbo-metrics-registry dubbo-metrics-metadata dubbo-metrics-prometheus diff --git a/dubbo-registry/dubbo-registry-api/pom.xml b/dubbo-registry/dubbo-registry-api/pom.xml index f9c580f8c9..4c3a15f353 100644 --- a/dubbo-registry/dubbo-registry-api/pom.xml +++ b/dubbo-registry/dubbo-registry-api/pom.xml @@ -98,5 +98,12 @@ ${project.parent.version} compile + + + org.apache.dubbo + dubbo-metrics-registry + ${project.parent.version} + compile + diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java index c6eb7a83ec..0859c1e9e2 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java @@ -16,6 +16,32 @@ */ package org.apache.dubbo.registry.client.event.listener; +import org.apache.dubbo.common.ProtocolServiceKey; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.URLBuilder; +import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.metadata.MetadataInfo; +import org.apache.dubbo.metadata.MetadataInfo.ServiceInfo; +import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster; +import org.apache.dubbo.metrics.model.TimePair; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.registry.client.DefaultServiceInstance; +import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.ServiceInstance; +import org.apache.dubbo.registry.client.event.RetryServiceInstancesChangedEvent; +import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; +import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils; +import org.apache.dubbo.registry.client.metadata.ServiceInstanceNotificationCustomizer; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.ScopeModelUtil; + import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -32,28 +58,6 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.dubbo.common.ProtocolServiceKey; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.URLBuilder; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.ConcurrentHashSet; -import org.apache.dubbo.metadata.MetadataInfo; -import org.apache.dubbo.metadata.MetadataInfo.ServiceInfo; -import org.apache.dubbo.registry.NotifyListener; -import org.apache.dubbo.registry.client.DefaultServiceInstance; -import org.apache.dubbo.registry.client.ServiceDiscovery; -import org.apache.dubbo.registry.client.ServiceInstance; -import org.apache.dubbo.registry.client.event.RetryServiceInstancesChangedEvent; -import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; -import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils; -import org.apache.dubbo.registry.client.metadata.ServiceInstanceNotificationCustomizer; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.ScopeModelUtil; - import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR; import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_REFRESH_ADDRESS; @@ -87,6 +91,7 @@ public class ServiceInstancesChangedListener { private final ScheduledExecutorService scheduler; private volatile boolean hasEmptyMetadata; private final Set serviceInstanceNotificationCustomizers; + private final ApplicationModel applicationModel; public ServiceInstancesChangedListener(Set serviceNames, ServiceDiscovery serviceDiscovery) { @@ -99,6 +104,7 @@ public class ServiceInstancesChangedListener { ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(serviceDiscovery == null || serviceDiscovery.getUrl() == null ? null : serviceDiscovery.getUrl().getScopeModel()); this.scheduler = applicationModel.getBeanFactory().getBean(FrameworkExecutorRepository.class).getMetadataRetryExecutor(); this.serviceInstanceNotificationCustomizers = applicationModel.getExtensionLoader(ServiceInstanceNotificationCustomizer.class).getSupportedExtensionInstances(); + this.applicationModel = applicationModel; } /** @@ -398,6 +404,13 @@ public class ServiceInstancesChangedListener { * race condition is protected by onEvent/doOnEvent */ protected void notifyAddressChanged() { + + ScopeBeanFactory beanFactory = applicationModel.getFrameworkModel().getBeanFactory(); + SimpleMetricsEventMulticaster eventMulticaster = beanFactory.getOrRegisterBean(SimpleMetricsEventMulticaster.class); + + TimePair timePair = TimePair.start(); + eventMulticaster.publishEvent(new RegistryEvent.MetricsNotifyEvent(applicationModel, timePair, null)); + Map lastNumMap = new HashMap<>(); // 1 different services listeners.forEach((serviceKey, listenerSet) -> { // 2 multiple subscription listener of the same service @@ -407,8 +420,11 @@ public class ServiceInstancesChangedListener { List urls = toUrlsWithEmpty(getAddresses(listenerWithKey.getProtocolServiceKey(), notifyListener.getConsumerUrl())); logger.info("Notify service " + listenerWithKey.getProtocolServiceKey() + " with urls " + urls.size()); notifyListener.notify(urls); + lastNumMap.put(serviceKey, urls.size()); } }); + eventMulticaster.publishFinishEvent(new RegistryEvent.MetricsNotifyEvent(applicationModel, timePair, lastNumMap)); + } protected List toUrlsWithEmpty(List urls) { diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java index a994f1f1c7..65c8ef3190 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java @@ -16,19 +16,6 @@ */ package org.apache.dubbo.registry.integration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URLBuilder; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; @@ -43,6 +30,9 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; +import org.apache.dubbo.metrics.model.TimePair; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.registry.AddressListener; import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.rpc.Invoker; @@ -53,8 +43,22 @@ import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.support.ClusterUtils; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.ModuleModel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; @@ -110,11 +114,18 @@ public class RegistryDirectory extends DynamicDirectory { super(serviceType, url); moduleModel = getModuleModel(url.getScopeModel()); consumerConfigurationListener = getConsumerConfigurationListener(moduleModel); + } @Override public void subscribe(URL url) { + ApplicationModel applicationModel = url.getApplicationModel(); + GlobalMetricsEventMulticaster eventMulticaster = applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class); + TimePair timePair = TimePair.start(); + + eventMulticaster.publishEvent(new RegistryEvent.MetricsSubscribeEvent(applicationModel, timePair)); super.subscribe(url); + eventMulticaster.publishFinishEvent(new RegistryEvent.MetricsSubscribeEvent(applicationModel, timePair)); if (moduleModel.getModelEnvironment().getConfiguration().convert(Boolean.class, org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN, true)) { consumerConfigurationListener.addNotifyListener(this); referenceConfigurationListener = new ReferenceConfigurationListener(moduleModel, this, url); @@ -233,7 +244,7 @@ public class RegistryDirectory extends DynamicDirectory { // use local reference to avoid NPE as this.cachedInvokerUrls will be set null by destroyAllInvokers(). Set localCachedInvokerUrls = this.cachedInvokerUrls; if (invokerUrls.isEmpty()) { - if(CollectionUtils.isNotEmpty(localCachedInvokerUrls)){ + if (CollectionUtils.isNotEmpty(localCachedInvokerUrls)) { // 1-4 Empty address. logger.warn(REGISTRY_EMPTY_ADDRESS, "configuration ", "", "Service" + serviceKey + " received empty address list with no EMPTY protocol set, trigger empty protection."); diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml b/dubbo-test/dubbo-dependencies-all/pom.xml index 66f84b58f6..8922e63208 100644 --- a/dubbo-test/dubbo-dependencies-all/pom.xml +++ b/dubbo-test/dubbo-dependencies-all/pom.xml @@ -148,6 +148,11 @@ org.apache.dubbo dubbo-metrics-default + + org.apache.dubbo + dubbo-metrics-registry + + org.apache.dubbo dubbo-metrics-metadata