blob: a6448767d6abf4c0cc2a4a5e9970c6952f67cf71 [file] [log] [blame]
/*
* 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.monitor.dubbo;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.monitor.MetricsService;
import org.apache.dubbo.monitor.dubbo.service.DemoService;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
import com.alibaba.metrics.FastCompass;
import com.alibaba.metrics.IMetricManager;
import com.alibaba.metrics.MetricLevel;
import com.alibaba.metrics.MetricManager;
import com.alibaba.metrics.MetricName;
import com.alibaba.metrics.common.MetricObject;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.monitor.Constants.DUBBO_CONSUMER;
import static org.apache.dubbo.monitor.Constants.DUBBO_CONSUMER_METHOD;
import static org.apache.dubbo.monitor.Constants.DUBBO_GROUP;
import static org.apache.dubbo.monitor.Constants.DUBBO_PROVIDER;
import static org.apache.dubbo.monitor.Constants.DUBBO_PROVIDER_METHOD;
import static org.apache.dubbo.monitor.Constants.METHOD;
import static org.apache.dubbo.monitor.Constants.SERVICE;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
public class MetricsFilterTest {
private Invoker<DemoService> serviceInvoker;
private static final String host;
private static final Integer port;
private final URL url = URL.valueOf("dubbo://" + host + ":" + port + "/org.apache.dubbo.monitor.dubbo.service.DemoService?" + METRICS_PORT + "=" + port);
static {
host = NetUtils.getLocalHost();
port = NetUtils.getAvailablePort();
}
@BeforeEach
void setUp() {
serviceInvoker = mock(Invoker.class);
given(serviceInvoker.isAvailable()).willReturn(false);
given(serviceInvoker.getInterface()).willReturn(DemoService.class);
given(serviceInvoker.getUrl()).willReturn(getUrl());
given(serviceInvoker.invoke(Mockito.any(Invocation.class))).willReturn(null);
doNothing().when(serviceInvoker).destroy();
}
private URL getUrl() {
return url;
}
private void onInvokeReturns(AppResponse response) {
given(serviceInvoker.invoke(Mockito.any(Invocation.class))).willReturn(response);
}
private final Invoker<DemoService> timeoutInvoker = new Invoker<DemoService>() {
@Override
public Class<DemoService> getInterface() {
return DemoService.class;
}
public URL getUrl() {
return url;
}
@Override
public boolean isAvailable() {
return false;
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION);
}
@Override
public void destroy() {
}
};
@Test
public void testConsumerSuccess() throws Exception {
IMetricManager metricManager = MetricManager.getIMetricManager();
metricManager.clear();
MetricsFilter metricsFilter = new MetricsFilter();
Invocation invocation = new RpcInvocation("sayName", DemoService.class.getName(), "", new Class<?>[]{Integer.class}, new Object[0]);
RpcContext.getContext().setRemoteAddress(host, url.getPort()).setLocalAddress(host, NetUtils.getAvailablePort());
RpcContext.getContext().setUrl(serviceInvoker.getUrl().addParameter(SIDE_KEY, CONSUMER_SIDE));
AppResponse response = AppResponseBuilder.create()
.build();
onInvokeReturns(response);
for (int i = 0; i < 100; i++) {
metricsFilter.invoke(serviceInvoker, invocation);
}
FastCompass dubboClient = metricManager.getFastCompass(DUBBO_GROUP, new MetricName(DUBBO_CONSUMER, MetricLevel.MAJOR));
FastCompass dubboMethod = metricManager.getFastCompass(DUBBO_GROUP, new MetricName(DUBBO_CONSUMER_METHOD, new HashMap<String, String>(4) {
{
put(SERVICE, "org.apache.dubbo.monitor.dubbo.service.DemoService");
put(METHOD, "void sayName(Integer)");
}
}, MetricLevel.NORMAL));
long timestamp = System.currentTimeMillis() / 5000 * 5000;
Assertions.assertEquals(100, dubboClient.getMethodCountPerCategory(0).get("success").get(timestamp));
timestamp = timestamp / 15000 * 15000;
Assertions.assertEquals(100, dubboMethod.getMethodCountPerCategory(0).get("success").get(timestamp));
}
@Test
public void testConsumerTimeout() {
IMetricManager metricManager = MetricManager.getIMetricManager();
metricManager.clear();
MetricsFilter metricsFilter = new MetricsFilter();
Invocation invocation = new RpcInvocation("timeoutException", DemoService.class.getName(), "", null, null);
RpcContext.getContext().setRemoteAddress(host, url.getPort()).setLocalAddress(host, NetUtils.getAvailablePort());
RpcContext.getContext().setUrl(timeoutInvoker.getUrl().addParameter(SIDE_KEY, CONSUMER_SIDE)
.addParameter(TIMEOUT_KEY, 300));
AppResponse response = AppResponseBuilder.create()
.build();
onInvokeReturns(response);
for (int i = 0; i < 10; i++) {
try {
metricsFilter.invoke(timeoutInvoker, invocation);
} catch (RpcException e) {
//ignore
}
}
FastCompass dubboClient = metricManager.getFastCompass(DUBBO_GROUP, new MetricName(DUBBO_CONSUMER, MetricLevel.MAJOR));
FastCompass dubboMethod = metricManager.getFastCompass(DUBBO_GROUP, new MetricName(DUBBO_CONSUMER_METHOD, new HashMap<String, String>(4) {
{
put(SERVICE, "org.apache.dubbo.monitor.dubbo.service.DemoService");
put(METHOD, "void timeoutException()");
}
}, MetricLevel.NORMAL));
long timestamp = System.currentTimeMillis() / 5000 * 5000;
Assertions.assertEquals(10, dubboClient.getMethodCountPerCategory(0).get("timeoutError").get(timestamp));
timestamp = timestamp / 15000 * 15000;
Assertions.assertEquals(10, dubboMethod.getMethodCountPerCategory(0).get("timeoutError").get(timestamp));
}
@Test
public void testProviderSuccess() throws Exception {
IMetricManager metricManager = MetricManager.getIMetricManager();
metricManager.clear();
MetricsFilter metricsFilter = new MetricsFilter();
Invocation invocation = new RpcInvocation("sayName", DemoService.class.getName(), "", new Class<?>[0], new Object[0]);
RpcContext.getContext().setRemoteAddress(host, url.getPort()).setLocalAddress(host, NetUtils.getAvailablePort());
RpcContext.getContext().setUrl(serviceInvoker.getUrl().addParameter(SIDE_KEY, PROVIDER));
AppResponse response = AppResponseBuilder.create()
.build();
onInvokeReturns(response);
for (int i = 0; i < 100; i++) {
metricsFilter.invoke(serviceInvoker, invocation);
}
FastCompass dubboClient = metricManager.getFastCompass(DUBBO_GROUP, new MetricName(DUBBO_PROVIDER, MetricLevel.MAJOR));
FastCompass dubboMethod = metricManager.getFastCompass(DUBBO_GROUP, new MetricName(DUBBO_PROVIDER_METHOD, new HashMap<String, String>(4) {
{
put(SERVICE, "org.apache.dubbo.monitor.dubbo.service.DemoService");
put(METHOD, "void sayName()");
}
}, MetricLevel.NORMAL));
long timestamp = System.currentTimeMillis() / 5000 * 5000;
Assertions.assertEquals(100, dubboClient.getMethodCountPerCategory(0).get("success").get(timestamp));
timestamp = timestamp / 15000 * 15000;
Assertions.assertEquals(100, dubboMethod.getMethodCountPerCategory(0).get("success").get(timestamp));
}
@Test
public void testInvokeMetricsService() {
IMetricManager metricManager = MetricManager.getIMetricManager();
metricManager.clear();
MetricsFilter metricsFilter = new MetricsFilter();
Invocation invocation = new RpcInvocation("sayName", DemoService.class.getName(), "", new Class<?>[0], new Object[0]);
RpcContext.getContext().setRemoteAddress(host, url.getPort()).setLocalAddress(host, NetUtils.getAvailablePort());
RpcContext.getContext().setUrl(serviceInvoker.getUrl().addParameter(SIDE_KEY, PROVIDER_SIDE)
.addParameter(TIMEOUT_KEY, 300));
AppResponse response = AppResponseBuilder.create()
.build();
onInvokeReturns(response);
for (int i = 0; i < 50; i++) {
try {
metricsFilter.invoke(serviceInvoker, invocation);
metricsFilter.invoke(timeoutInvoker, invocation);
} catch (RpcException e) {
//ignore
}
}
Protocol protocol = new DubboProtocol();
URL metricUrl = URL.valueOf("dubbo://" + url.getHost() + ":" + url.getPort() + "/" + MetricsService.class.getName() + "?" + METRICS_PORT + "=" + port);
Invoker<MetricsService> invoker = protocol.refer(MetricsService.class, metricUrl);
invocation = new RpcInvocation("getMetricsByGroup", DemoService.class.getName(), "", new Class<?>[]{String.class}, new Object[]{DUBBO_GROUP});
try {
Thread.sleep(5000);
} catch (Exception e) {
// ignore
}
String resStr = invoker.invoke(invocation).getValue().toString();
List<MetricObject> metricObjectList = new Gson().fromJson(resStr, new TypeToken<List<MetricObject>>() {
}.getType());
Map<String, Object> metricMap = new HashMap<>();
for (int i = 0; i < metricObjectList.size(); i++) {
MetricObject object = metricObjectList.get(i);
String metric = object.getMetric().substring(object.getMetric().lastIndexOf(".") + 1);
if ((double) object.getValue() > 0.0 && object.getMetricLevel().equals(MetricLevel.MAJOR))
metricMap.put(metric, object.getValue());
}
Assertions.assertEquals(50.0, metricMap.get("success_bucket_count"));
Assertions.assertEquals(50.0, metricMap.get("timeoutError_bucket_count"));
Assertions.assertEquals(100.0, metricMap.get("bucket_count"));
Assertions.assertEquals(100.0 / 5, metricMap.get("qps"));
Assertions.assertEquals(50.0 / 100.0, metricMap.get("success_rate"));
}
@Test
public void testInvokeMetricsMethodService() {
IMetricManager metricManager = MetricManager.getIMetricManager();
metricManager.clear();
MetricsFilter metricsFilter = new MetricsFilter();
Invocation sayNameInvocation = new RpcInvocation("sayName", DemoService.class.getName(), "", new Class<?>[0], new Object[0]);
Invocation echoInvocation = new RpcInvocation("echo", DemoService.class.getName(), "", new Class<?>[]{Integer.class}, new Integer[]{1});
RpcContext.getContext().setRemoteAddress(host, url.getPort()).setLocalAddress(host, NetUtils.getAvailablePort());
RpcContext.getContext().setUrl(serviceInvoker.getUrl().addParameter(SIDE_KEY, PROVIDER_SIDE)
.addParameter(TIMEOUT_KEY, 300));
AppResponse response = AppResponseBuilder.create()
.build();
onInvokeReturns(response);
for (int i = 0; i < 50; i++) {
metricsFilter.invoke(serviceInvoker, sayNameInvocation);
metricsFilter.invoke(serviceInvoker, echoInvocation);
try {
metricsFilter.invoke(timeoutInvoker, sayNameInvocation);
} catch (RpcException e) {
// ignore
}
try {
metricsFilter.invoke(timeoutInvoker, echoInvocation);
} catch (RpcException e) {
// ignore
}
}
Protocol protocol = new DubboProtocol();
URL metricUrl = URL.valueOf("dubbo://" + url.getHost() + ":" + url.getPort() + "/" + MetricsService.class.getName() + "?" + METRICS_PORT + "=" + port);
Invoker<MetricsService> invoker = protocol.refer(MetricsService.class, metricUrl);
Invocation invocation = new RpcInvocation("getMetricsByGroup", DemoService.class.getName(), "", new Class<?>[]{String.class}, new Object[]{DUBBO_GROUP});
try {
Thread.sleep(15000);
} catch (Exception e) {
// ignore
}
String resStr = invoker.invoke(invocation).getValue().toString();
List<MetricObject> metricObjectList = new Gson().fromJson(resStr, new TypeToken<List<MetricObject>>() {
}.getType());
Map<String, Map<String, Object>> methodMetricMap = new HashMap<>();
for (int i = 0; i < metricObjectList.size(); i++) {
MetricObject object = metricObjectList.get(i);
String service = object.getTags().get("service");
String method = service + "." + object.getTags().get("method");
String metric = object.getMetric().substring(object.getMetric().lastIndexOf(".") + 1);
Map map = methodMetricMap.get(method);
if (map == null) {
map = new HashMap();
methodMetricMap.put(method, map);
}
map.put(metric, object.getValue());
}
Assertions.assertEquals(50.0,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void sayName()").get("success_bucket_count"));
Assertions.assertEquals(50.0,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void echo(Integer)").get("success_bucket_count"));
Assertions.assertEquals(50.0,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void sayName()").get("timeoutError_bucket_count"));
Assertions.assertEquals(50.0,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void echo(Integer)").get("timeoutError_bucket_count"));
Assertions.assertEquals(100.0 / 15,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void sayName()").get("qps"));
Assertions.assertEquals(100.0 / 15,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void echo(Integer)").get("qps"));
Assertions.assertEquals(50.0 / 100.0,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void sayName()").get("success_rate"));
Assertions.assertEquals(50.0 / 100.0,
methodMetricMap.get("org.apache.dubbo.monitor.dubbo.service.DemoService.void echo(Integer)").get("success_rate"));
}
}