mirror of https://github.com/grpc/grpc-java.git
services, xds, orca: LRS named metrics support (#10282)
Implements gRFC A64: xDS LRS Custom Metrics Support
This commit is contained in:
parent
8dbd47ceb5
commit
4fa2814d65
|
|
@ -41,6 +41,8 @@ public final class CallMetricRecorder {
|
||||||
new AtomicReference<>();
|
new AtomicReference<>();
|
||||||
private final AtomicReference<ConcurrentHashMap<String, Double>> requestCostMetrics =
|
private final AtomicReference<ConcurrentHashMap<String, Double>> requestCostMetrics =
|
||||||
new AtomicReference<>();
|
new AtomicReference<>();
|
||||||
|
private final AtomicReference<ConcurrentHashMap<String, Double>> namedMetrics =
|
||||||
|
new AtomicReference<>();
|
||||||
private double cpuUtilizationMetric = 0;
|
private double cpuUtilizationMetric = 0;
|
||||||
private double applicationUtilizationMetric = 0;
|
private double applicationUtilizationMetric = 0;
|
||||||
private double memoryUtilizationMetric = 0;
|
private double memoryUtilizationMetric = 0;
|
||||||
|
|
@ -127,6 +129,27 @@ public final class CallMetricRecorder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records an application-specific opaque custom metric measurement. If RPC has already finished,
|
||||||
|
* this method is no-op.
|
||||||
|
*
|
||||||
|
* <p>A latter record will overwrite its former name-sakes.
|
||||||
|
*
|
||||||
|
* @return this recorder object
|
||||||
|
*/
|
||||||
|
public CallMetricRecorder recordNamedMetric(String name, double value) {
|
||||||
|
if (disabled) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (namedMetrics.get() == null) {
|
||||||
|
// The chance of race of creation of the map should be very small, so it should be fine
|
||||||
|
// to create these maps that might be discarded.
|
||||||
|
namedMetrics.compareAndSet(null, new ConcurrentHashMap<String, Double>());
|
||||||
|
}
|
||||||
|
namedMetrics.get().put(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records a call metric measurement for CPU utilization in the range [0, inf). Values outside the
|
* Records a call metric measurement for CPU utilization in the range [0, inf). Values outside the
|
||||||
* valid range are ignored. If RPC has already finished, this method is no-op.
|
* valid range are ignored. If RPC has already finished, this method is no-op.
|
||||||
|
|
@ -235,12 +258,17 @@ public final class CallMetricRecorder {
|
||||||
MetricReport finalizeAndDump2() {
|
MetricReport finalizeAndDump2() {
|
||||||
Map<String, Double> savedRequestCostMetrics = finalizeAndDump();
|
Map<String, Double> savedRequestCostMetrics = finalizeAndDump();
|
||||||
Map<String, Double> savedUtilizationMetrics = utilizationMetrics.get();
|
Map<String, Double> savedUtilizationMetrics = utilizationMetrics.get();
|
||||||
|
Map<String, Double> savedNamedMetrics = namedMetrics.get();
|
||||||
if (savedUtilizationMetrics == null) {
|
if (savedUtilizationMetrics == null) {
|
||||||
savedUtilizationMetrics = Collections.emptyMap();
|
savedUtilizationMetrics = Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
if (savedNamedMetrics == null) {
|
||||||
|
savedNamedMetrics = Collections.emptyMap();
|
||||||
|
}
|
||||||
return new MetricReport(cpuUtilizationMetric, applicationUtilizationMetric,
|
return new MetricReport(cpuUtilizationMetric, applicationUtilizationMetric,
|
||||||
memoryUtilizationMetric, qps, eps, Collections.unmodifiableMap(savedRequestCostMetrics),
|
memoryUtilizationMetric, qps, eps, Collections.unmodifiableMap(savedRequestCostMetrics),
|
||||||
Collections.unmodifiableMap(savedUtilizationMetrics)
|
Collections.unmodifiableMap(savedUtilizationMetrics),
|
||||||
|
Collections.unmodifiableMap(savedNamedMetrics)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,9 @@ public final class InternalCallMetricRecorder {
|
||||||
|
|
||||||
public static MetricReport createMetricReport(double cpuUtilization,
|
public static MetricReport createMetricReport(double cpuUtilization,
|
||||||
double applicationUtilization, double memoryUtilization, double qps, double eps,
|
double applicationUtilization, double memoryUtilization, double qps, double eps,
|
||||||
Map<String, Double> requestCostMetrics, Map<String, Double> utilizationMetrics) {
|
Map<String, Double> requestCostMetrics, Map<String, Double> utilizationMetrics,
|
||||||
|
Map<String, Double> namedMetrics) {
|
||||||
return new MetricReport(cpuUtilization, applicationUtilization, memoryUtilization, qps, eps,
|
return new MetricReport(cpuUtilization, applicationUtilization, memoryUtilization, qps, eps,
|
||||||
requestCostMetrics, utilizationMetrics);
|
requestCostMetrics, utilizationMetrics, namedMetrics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,6 @@ public final class MetricRecorder {
|
||||||
|
|
||||||
MetricReport getMetricReport() {
|
MetricReport getMetricReport() {
|
||||||
return new MetricReport(cpuUtilization, applicationUtilization, memoryUtilization, qps, eps,
|
return new MetricReport(cpuUtilization, applicationUtilization, memoryUtilization, qps, eps,
|
||||||
Collections.emptyMap(), Collections.unmodifiableMap(metricsData));
|
Collections.emptyMap(), Collections.unmodifiableMap(metricsData), Collections.emptyMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,11 @@ public final class MetricReport {
|
||||||
private double eps;
|
private double eps;
|
||||||
private Map<String, Double> requestCostMetrics;
|
private Map<String, Double> requestCostMetrics;
|
||||||
private Map<String, Double> utilizationMetrics;
|
private Map<String, Double> utilizationMetrics;
|
||||||
|
private Map<String, Double> namedMetrics;
|
||||||
|
|
||||||
MetricReport(double cpuUtilization, double applicationUtilization, double memoryUtilization,
|
MetricReport(double cpuUtilization, double applicationUtilization, double memoryUtilization,
|
||||||
double qps, double eps, Map<String, Double> requestCostMetrics,
|
double qps, double eps, Map<String, Double> requestCostMetrics,
|
||||||
Map<String, Double> utilizationMetrics) {
|
Map<String, Double> utilizationMetrics, Map<String, Double> namedMetrics) {
|
||||||
this.cpuUtilization = cpuUtilization;
|
this.cpuUtilization = cpuUtilization;
|
||||||
this.applicationUtilization = applicationUtilization;
|
this.applicationUtilization = applicationUtilization;
|
||||||
this.memoryUtilization = memoryUtilization;
|
this.memoryUtilization = memoryUtilization;
|
||||||
|
|
@ -46,6 +47,7 @@ public final class MetricReport {
|
||||||
this.eps = eps;
|
this.eps = eps;
|
||||||
this.requestCostMetrics = checkNotNull(requestCostMetrics, "requestCostMetrics");
|
this.requestCostMetrics = checkNotNull(requestCostMetrics, "requestCostMetrics");
|
||||||
this.utilizationMetrics = checkNotNull(utilizationMetrics, "utilizationMetrics");
|
this.utilizationMetrics = checkNotNull(utilizationMetrics, "utilizationMetrics");
|
||||||
|
this.namedMetrics = checkNotNull(namedMetrics, "namedMetrics");
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getCpuUtilization() {
|
public double getCpuUtilization() {
|
||||||
|
|
@ -68,6 +70,10 @@ public final class MetricReport {
|
||||||
return utilizationMetrics;
|
return utilizationMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Double> getNamedMetrics() {
|
||||||
|
return namedMetrics;
|
||||||
|
}
|
||||||
|
|
||||||
public double getQps() {
|
public double getQps() {
|
||||||
return qps;
|
return qps;
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +90,7 @@ public final class MetricReport {
|
||||||
.add("memoryUtilization", memoryUtilization)
|
.add("memoryUtilization", memoryUtilization)
|
||||||
.add("requestCost", requestCostMetrics)
|
.add("requestCost", requestCostMetrics)
|
||||||
.add("utilization", utilizationMetrics)
|
.add("utilization", utilizationMetrics)
|
||||||
|
.add("named", namedMetrics)
|
||||||
.add("qps", qps)
|
.add("qps", qps)
|
||||||
.add("eps", eps)
|
.add("eps", eps)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ public class CallMetricRecorderTest {
|
||||||
recorder.recordRequestCostMetric("cost1", 37465.12);
|
recorder.recordRequestCostMetric("cost1", 37465.12);
|
||||||
recorder.recordRequestCostMetric("cost2", 10293.0);
|
recorder.recordRequestCostMetric("cost2", 10293.0);
|
||||||
recorder.recordRequestCostMetric("cost3", 1.0);
|
recorder.recordRequestCostMetric("cost3", 1.0);
|
||||||
|
recorder.recordNamedMetric("named1", 0.2233);
|
||||||
|
recorder.recordNamedMetric("named2", -1.618);
|
||||||
|
recorder.recordNamedMetric("named3", 3.1415926535);
|
||||||
recorder.recordCpuUtilizationMetric(0.1928);
|
recorder.recordCpuUtilizationMetric(0.1928);
|
||||||
recorder.recordApplicationUtilizationMetric(0.9987);
|
recorder.recordApplicationUtilizationMetric(0.9987);
|
||||||
recorder.recordMemoryUtilizationMetric(0.474);
|
recorder.recordMemoryUtilizationMetric(0.474);
|
||||||
|
|
@ -55,6 +58,8 @@ public class CallMetricRecorderTest {
|
||||||
.containsExactly("util1", 0.154353423, "util2", 0.1367, "util3", 0.143734);
|
.containsExactly("util1", 0.154353423, "util2", 0.1367, "util3", 0.143734);
|
||||||
Truth.assertThat(dump.getRequestCostMetrics())
|
Truth.assertThat(dump.getRequestCostMetrics())
|
||||||
.containsExactly("cost1", 37465.12, "cost2", 10293.0, "cost3", 1.0);
|
.containsExactly("cost1", 37465.12, "cost2", 10293.0, "cost3", 1.0);
|
||||||
|
Truth.assertThat(dump.getNamedMetrics())
|
||||||
|
.containsExactly("named1", 0.2233, "named2", -1.618, "named3", 3.1415926535);
|
||||||
Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0.1928);
|
Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0.1928);
|
||||||
Truth.assertThat(dump.getApplicationUtilization()).isEqualTo(0.9987);
|
Truth.assertThat(dump.getApplicationUtilization()).isEqualTo(0.9987);
|
||||||
Truth.assertThat(dump.getMemoryUtilization()).isEqualTo(0.474);
|
Truth.assertThat(dump.getMemoryUtilization()).isEqualTo(0.474);
|
||||||
|
|
@ -62,6 +67,9 @@ public class CallMetricRecorderTest {
|
||||||
Truth.assertThat(dump.getEps()).isEqualTo(1.618);
|
Truth.assertThat(dump.getEps()).isEqualTo(1.618);
|
||||||
Truth.assertThat(dump.toString()).contains("eps=1.618");
|
Truth.assertThat(dump.toString()).contains("eps=1.618");
|
||||||
Truth.assertThat(dump.toString()).contains("applicationUtilization=0.9987");
|
Truth.assertThat(dump.toString()).contains("applicationUtilization=0.9987");
|
||||||
|
Truth.assertThat(dump.toString()).contains("named1=0.2233");
|
||||||
|
Truth.assertThat(dump.toString()).contains("named2=-1.618");
|
||||||
|
Truth.assertThat(dump.toString()).contains("named3=3.1415926535");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -71,6 +79,7 @@ public class CallMetricRecorderTest {
|
||||||
recorder.recordUtilizationMetric("cost", 0.154353423);
|
recorder.recordUtilizationMetric("cost", 0.154353423);
|
||||||
recorder.recordQpsMetric(3.14159);
|
recorder.recordQpsMetric(3.14159);
|
||||||
recorder.recordEpsMetric(1.618);
|
recorder.recordEpsMetric(1.618);
|
||||||
|
recorder.recordNamedMetric("named1", 2.718);
|
||||||
assertThat(recorder.finalizeAndDump()).isEqualTo(initDump);
|
assertThat(recorder.finalizeAndDump()).isEqualTo(initDump);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +130,9 @@ public class CallMetricRecorderTest {
|
||||||
recorder.recordUtilizationMetric("util1", 0.2837421);
|
recorder.recordUtilizationMetric("util1", 0.2837421);
|
||||||
recorder.recordMemoryUtilizationMetric(0.93840);
|
recorder.recordMemoryUtilizationMetric(0.93840);
|
||||||
recorder.recordUtilizationMetric("util1", 0.843233);
|
recorder.recordUtilizationMetric("util1", 0.843233);
|
||||||
|
recorder.recordNamedMetric("named1", 0.2233);
|
||||||
|
recorder.recordNamedMetric("named2", 2.718);
|
||||||
|
recorder.recordNamedMetric("named1", 3.1415926535);
|
||||||
recorder.recordQpsMetric(1928.3);
|
recorder.recordQpsMetric(1928.3);
|
||||||
recorder.recordQpsMetric(100.8);
|
recorder.recordQpsMetric(100.8);
|
||||||
recorder.recordEpsMetric(3.14159);
|
recorder.recordEpsMetric(3.14159);
|
||||||
|
|
@ -133,6 +145,8 @@ public class CallMetricRecorderTest {
|
||||||
Truth.assertThat(dump.getMemoryUtilization()).isEqualTo(0.93840);
|
Truth.assertThat(dump.getMemoryUtilization()).isEqualTo(0.93840);
|
||||||
Truth.assertThat(dump.getUtilizationMetrics())
|
Truth.assertThat(dump.getUtilizationMetrics())
|
||||||
.containsExactly("util1", 0.843233);
|
.containsExactly("util1", 0.843233);
|
||||||
|
Truth.assertThat(dump.getNamedMetrics())
|
||||||
|
.containsExactly("named1", 3.1415926535, "named2", 2.718);
|
||||||
Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0);
|
Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0);
|
||||||
Truth.assertThat(dump.getQps()).isEqualTo(100.8);
|
Truth.assertThat(dump.getQps()).isEqualTo(100.8);
|
||||||
Truth.assertThat(dump.getEps()).isEqualTo(1.618);
|
Truth.assertThat(dump.getEps()).isEqualTo(1.618);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import io.grpc.Metadata;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.grpc.internal.ForwardingClientStreamTracer;
|
import io.grpc.internal.ForwardingClientStreamTracer;
|
||||||
import io.grpc.internal.ObjectPool;
|
import io.grpc.internal.ObjectPool;
|
||||||
|
import io.grpc.services.MetricReport;
|
||||||
import io.grpc.util.ForwardingLoadBalancerHelper;
|
import io.grpc.util.ForwardingLoadBalancerHelper;
|
||||||
import io.grpc.util.ForwardingSubchannel;
|
import io.grpc.util.ForwardingSubchannel;
|
||||||
import io.grpc.util.GracefulSwitchLoadBalancer;
|
import io.grpc.util.GracefulSwitchLoadBalancer;
|
||||||
|
|
@ -47,6 +48,8 @@ import io.grpc.xds.XdsLogger.XdsLogLevel;
|
||||||
import io.grpc.xds.XdsNameResolverProvider.CallCounterProvider;
|
import io.grpc.xds.XdsNameResolverProvider.CallCounterProvider;
|
||||||
import io.grpc.xds.XdsSubchannelPickers.ErrorPicker;
|
import io.grpc.xds.XdsSubchannelPickers.ErrorPicker;
|
||||||
import io.grpc.xds.internal.security.SslContextProviderSupplier;
|
import io.grpc.xds.internal.security.SslContextProviderSupplier;
|
||||||
|
import io.grpc.xds.orca.OrcaPerRequestUtil;
|
||||||
|
import io.grpc.xds.orca.OrcaPerRequestUtil.OrcaPerRequestReportListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -329,7 +332,9 @@ final class ClusterImplLoadBalancer extends LoadBalancer {
|
||||||
if (stats != null) {
|
if (stats != null) {
|
||||||
ClientStreamTracer.Factory tracerFactory = new CountingStreamTracerFactory(
|
ClientStreamTracer.Factory tracerFactory = new CountingStreamTracerFactory(
|
||||||
stats, inFlights, result.getStreamTracerFactory());
|
stats, inFlights, result.getStreamTracerFactory());
|
||||||
return PickResult.withSubchannel(result.getSubchannel(), tracerFactory);
|
ClientStreamTracer.Factory orcaTracerFactory = OrcaPerRequestUtil.getInstance()
|
||||||
|
.newOrcaClientStreamTracerFactory(tracerFactory, new OrcaPerRpcListener(stats));
|
||||||
|
return PickResult.withSubchannel(result.getSubchannel(), orcaTracerFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -386,4 +391,22 @@ final class ClusterImplLoadBalancer extends LoadBalancer {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class OrcaPerRpcListener implements OrcaPerRequestReportListener {
|
||||||
|
|
||||||
|
private final ClusterLocalityStats stats;
|
||||||
|
|
||||||
|
private OrcaPerRpcListener(ClusterLocalityStats stats) {
|
||||||
|
this.stats = checkNotNull(stats, "stats");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies {@link MetricReport#getNamedMetrics()} to {@link ClusterLocalityStats} such that it is
|
||||||
|
* included in the snapshot for the LRS report sent to the LRS server.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onLoadReport(MetricReport report) {
|
||||||
|
stats.recordBackendLoadMetricStats(report.getNamedMetrics());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -361,7 +362,16 @@ final class LoadReportClient {
|
||||||
.setTotalSuccessfulRequests(upstreamLocalityStats.totalSuccessfulRequests())
|
.setTotalSuccessfulRequests(upstreamLocalityStats.totalSuccessfulRequests())
|
||||||
.setTotalErrorRequests(upstreamLocalityStats.totalErrorRequests())
|
.setTotalErrorRequests(upstreamLocalityStats.totalErrorRequests())
|
||||||
.setTotalRequestsInProgress(upstreamLocalityStats.totalRequestsInProgress())
|
.setTotalRequestsInProgress(upstreamLocalityStats.totalRequestsInProgress())
|
||||||
.setTotalIssuedRequests(upstreamLocalityStats.totalIssuedRequests()));
|
.setTotalIssuedRequests(upstreamLocalityStats.totalIssuedRequests())
|
||||||
|
.addAllLoadMetricStats(
|
||||||
|
upstreamLocalityStats.loadMetricStatsMap().entrySet().stream().map(
|
||||||
|
e -> io.envoyproxy.envoy.config.endpoint.v3.EndpointLoadMetricStats.newBuilder()
|
||||||
|
.setMetricName(e.getKey())
|
||||||
|
.setNumRequestsFinishedWithMetric(
|
||||||
|
e.getValue().numRequestsFinishedWithMetric())
|
||||||
|
.setTotalMetricValue(e.getValue().totalMetricValue())
|
||||||
|
.build())
|
||||||
|
.collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
for (DroppedRequests droppedRequests : stats.droppedRequestsList()) {
|
for (DroppedRequests droppedRequests : stats.droppedRequestsList()) {
|
||||||
builder.addDroppedRequests(
|
builder.addDroppedRequests(
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import com.google.common.base.Stopwatch;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
|
import io.grpc.xds.Stats.BackendLoadMetricStats;
|
||||||
import io.grpc.xds.Stats.ClusterStats;
|
import io.grpc.xds.Stats.ClusterStats;
|
||||||
import io.grpc.xds.Stats.DroppedRequests;
|
import io.grpc.xds.Stats.DroppedRequests;
|
||||||
import io.grpc.xds.Stats.UpstreamLocalityStats;
|
import io.grpc.xds.Stats.UpstreamLocalityStats;
|
||||||
|
|
@ -197,7 +198,7 @@ final class LoadStatsManager2 {
|
||||||
}
|
}
|
||||||
UpstreamLocalityStats upstreamLocalityStats = UpstreamLocalityStats.create(
|
UpstreamLocalityStats upstreamLocalityStats = UpstreamLocalityStats.create(
|
||||||
locality, snapshot.callsIssued, snapshot.callsSucceeded, snapshot.callsFailed,
|
locality, snapshot.callsIssued, snapshot.callsSucceeded, snapshot.callsFailed,
|
||||||
snapshot.callsInProgress);
|
snapshot.callsInProgress, snapshot.loadMetricStatsMap);
|
||||||
builder.addUpstreamLocalityStats(upstreamLocalityStats);
|
builder.addUpstreamLocalityStats(upstreamLocalityStats);
|
||||||
// Use the max (drops/loads) recording interval as the overall interval for the
|
// Use the max (drops/loads) recording interval as the overall interval for the
|
||||||
// cluster's stats. In general, they should be mostly identical.
|
// cluster's stats. In general, they should be mostly identical.
|
||||||
|
|
@ -322,6 +323,7 @@ final class LoadStatsManager2 {
|
||||||
private final AtomicLong callsSucceeded = new AtomicLong();
|
private final AtomicLong callsSucceeded = new AtomicLong();
|
||||||
private final AtomicLong callsFailed = new AtomicLong();
|
private final AtomicLong callsFailed = new AtomicLong();
|
||||||
private final AtomicLong callsIssued = new AtomicLong();
|
private final AtomicLong callsIssued = new AtomicLong();
|
||||||
|
private Map<String, BackendLoadMetricStats> loadMetricStatsMap = new HashMap<>();
|
||||||
|
|
||||||
private ClusterLocalityStats(
|
private ClusterLocalityStats(
|
||||||
String clusterName, @Nullable String edsServiceName, Locality locality,
|
String clusterName, @Nullable String edsServiceName, Locality locality,
|
||||||
|
|
@ -353,6 +355,23 @@ final class LoadStatsManager2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records all custom named backend load metric stats for per-call load reporting. For each
|
||||||
|
* metric key {@code name}, creates a new {@link BackendLoadMetricStats} with a finished
|
||||||
|
* requests counter of 1 and the {@code value} if the key is not present in the map. Otherwise,
|
||||||
|
* increments the finished requests counter and adds the {@code value} to the existing
|
||||||
|
* {@link BackendLoadMetricStats}.
|
||||||
|
*/
|
||||||
|
synchronized void recordBackendLoadMetricStats(Map<String, Double> namedMetrics) {
|
||||||
|
namedMetrics.forEach((name, value) -> {
|
||||||
|
if (!loadMetricStatsMap.containsKey(name)) {
|
||||||
|
loadMetricStatsMap.put(name, new BackendLoadMetricStats(1, value));
|
||||||
|
} else {
|
||||||
|
loadMetricStatsMap.get(name).addMetricValueAndIncrementRequestsFinished(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the <i>hard</i> reference for this stats object (previously obtained via {@link
|
* Release the <i>hard</i> reference for this stats object (previously obtained via {@link
|
||||||
* LoadStatsManager2#getClusterLocalityStats}). The object may still be
|
* LoadStatsManager2#getClusterLocalityStats}). The object may still be
|
||||||
|
|
@ -367,8 +386,13 @@ final class LoadStatsManager2 {
|
||||||
private ClusterLocalityStatsSnapshot snapshot() {
|
private ClusterLocalityStatsSnapshot snapshot() {
|
||||||
long duration = stopwatch.elapsed(TimeUnit.NANOSECONDS);
|
long duration = stopwatch.elapsed(TimeUnit.NANOSECONDS);
|
||||||
stopwatch.reset().start();
|
stopwatch.reset().start();
|
||||||
|
Map<String, BackendLoadMetricStats> loadMetricStatsMapCopy;
|
||||||
|
synchronized (this) {
|
||||||
|
loadMetricStatsMapCopy = Collections.unmodifiableMap(loadMetricStatsMap);
|
||||||
|
loadMetricStatsMap = new HashMap<>();
|
||||||
|
}
|
||||||
return new ClusterLocalityStatsSnapshot(callsSucceeded.getAndSet(0), callsInProgress.get(),
|
return new ClusterLocalityStatsSnapshot(callsSucceeded.getAndSet(0), callsInProgress.get(),
|
||||||
callsFailed.getAndSet(0), callsIssued.getAndSet(0), duration);
|
callsFailed.getAndSet(0), callsIssued.getAndSet(0), duration, loadMetricStatsMapCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,15 +402,18 @@ final class LoadStatsManager2 {
|
||||||
private final long callsFailed;
|
private final long callsFailed;
|
||||||
private final long callsIssued;
|
private final long callsIssued;
|
||||||
private final long durationNano;
|
private final long durationNano;
|
||||||
|
private final Map<String, BackendLoadMetricStats> loadMetricStatsMap;
|
||||||
|
|
||||||
private ClusterLocalityStatsSnapshot(
|
private ClusterLocalityStatsSnapshot(
|
||||||
long callsSucceeded, long callsInProgress, long callsFailed, long callsIssued,
|
long callsSucceeded, long callsInProgress, long callsFailed, long callsIssued,
|
||||||
long durationNano) {
|
long durationNano, Map<String, BackendLoadMetricStats> loadMetricStatsMap) {
|
||||||
this.callsSucceeded = callsSucceeded;
|
this.callsSucceeded = callsSucceeded;
|
||||||
this.callsInProgress = callsInProgress;
|
this.callsInProgress = callsInProgress;
|
||||||
this.callsFailed = callsFailed;
|
this.callsFailed = callsFailed;
|
||||||
this.callsIssued = callsIssued;
|
this.callsIssued = callsIssued;
|
||||||
this.durationNano = durationNano;
|
this.durationNano = durationNano;
|
||||||
|
this.loadMetricStatsMap = Collections.unmodifiableMap(
|
||||||
|
checkNotNull(loadMetricStatsMap, "loadMetricStatsMap"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ package io.grpc.xds;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.util.Map;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/** Represents client load stats. */
|
/** Represents client load stats. */
|
||||||
|
|
@ -101,10 +103,45 @@ final class Stats {
|
||||||
|
|
||||||
abstract long totalRequestsInProgress();
|
abstract long totalRequestsInProgress();
|
||||||
|
|
||||||
|
abstract ImmutableMap<String, BackendLoadMetricStats> loadMetricStatsMap();
|
||||||
|
|
||||||
static UpstreamLocalityStats create(Locality locality, long totalIssuedRequests,
|
static UpstreamLocalityStats create(Locality locality, long totalIssuedRequests,
|
||||||
long totalSuccessfulRequests, long totalErrorRequests, long totalRequestsInProgress) {
|
long totalSuccessfulRequests, long totalErrorRequests, long totalRequestsInProgress,
|
||||||
|
Map<String, BackendLoadMetricStats> loadMetricStatsMap) {
|
||||||
return new AutoValue_Stats_UpstreamLocalityStats(locality, totalIssuedRequests,
|
return new AutoValue_Stats_UpstreamLocalityStats(locality, totalIssuedRequests,
|
||||||
totalSuccessfulRequests, totalErrorRequests, totalRequestsInProgress);
|
totalSuccessfulRequests, totalErrorRequests, totalRequestsInProgress,
|
||||||
|
ImmutableMap.copyOf(loadMetricStatsMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load metric stats for multi-dimensional load balancing.
|
||||||
|
*/
|
||||||
|
static final class BackendLoadMetricStats {
|
||||||
|
|
||||||
|
private long numRequestsFinishedWithMetric;
|
||||||
|
private double totalMetricValue;
|
||||||
|
|
||||||
|
BackendLoadMetricStats(long numRequestsFinishedWithMetric, double totalMetricValue) {
|
||||||
|
this.numRequestsFinishedWithMetric = numRequestsFinishedWithMetric;
|
||||||
|
this.totalMetricValue = totalMetricValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long numRequestsFinishedWithMetric() {
|
||||||
|
return numRequestsFinishedWithMetric;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double totalMetricValue() {
|
||||||
|
return totalMetricValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given {@code metricValue} and increments the number of requests finished counter for
|
||||||
|
* the existing {@link BackendLoadMetricStats}.
|
||||||
|
*/
|
||||||
|
public void addMetricValueAndIncrementRequestsFinished(double metricValue) {
|
||||||
|
numRequestsFinishedWithMetric += 1;
|
||||||
|
totalMetricValue += metricValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,8 @@ public final class OrcaMetricReportingServerInterceptor implements ServerInterce
|
||||||
.setRpsFractional(internalReport.getQps())
|
.setRpsFractional(internalReport.getQps())
|
||||||
.setEps(internalReport.getEps())
|
.setEps(internalReport.getEps())
|
||||||
.putAllUtilization(internalReport.getUtilizationMetrics())
|
.putAllUtilization(internalReport.getUtilizationMetrics())
|
||||||
.putAllRequestCost(internalReport.getRequestCostMetrics());
|
.putAllRequestCost(internalReport.getRequestCostMetrics())
|
||||||
|
.putAllNamedMetrics(internalReport.getNamedMetrics());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -133,7 +134,8 @@ public final class OrcaMetricReportingServerInterceptor implements ServerInterce
|
||||||
MetricReport callMetricRecorderReport
|
MetricReport callMetricRecorderReport
|
||||||
) {
|
) {
|
||||||
metricRecorderReportBuilder.putAllUtilization(callMetricRecorderReport.getUtilizationMetrics())
|
metricRecorderReportBuilder.putAllUtilization(callMetricRecorderReport.getUtilizationMetrics())
|
||||||
.putAllRequestCost(callMetricRecorderReport.getRequestCostMetrics());
|
.putAllRequestCost(callMetricRecorderReport.getRequestCostMetrics())
|
||||||
|
.putAllNamedMetrics(callMetricRecorderReport.getNamedMetrics());
|
||||||
// Overwrite only if the values from the given MetricReport for CallMetricRecorder are set
|
// Overwrite only if the values from the given MetricReport for CallMetricRecorder are set
|
||||||
double cpu = callMetricRecorderReport.getCpuUtilization();
|
double cpu = callMetricRecorderReport.getCpuUtilization();
|
||||||
if (isReportValueSet(cpu)) {
|
if (isReportValueSet(cpu)) {
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ public abstract class OrcaPerRequestUtil {
|
||||||
return InternalCallMetricRecorder.createMetricReport(loadReport.getCpuUtilization(),
|
return InternalCallMetricRecorder.createMetricReport(loadReport.getCpuUtilization(),
|
||||||
loadReport.getApplicationUtilization(), loadReport.getMemUtilization(),
|
loadReport.getApplicationUtilization(), loadReport.getMemUtilization(),
|
||||||
loadReport.getRpsFractional(), loadReport.getEps(), loadReport.getRequestCostMap(),
|
loadReport.getRpsFractional(), loadReport.getEps(), loadReport.getRequestCostMap(),
|
||||||
loadReport.getUtilizationMap());
|
loadReport.getUtilizationMap(), loadReport.getNamedMetricsMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.github.xds.data.orca.v3.OrcaLoadReport;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import io.grpc.Attributes;
|
import io.grpc.Attributes;
|
||||||
|
|
@ -45,6 +46,7 @@ import io.grpc.SynchronizationContext;
|
||||||
import io.grpc.internal.FakeClock;
|
import io.grpc.internal.FakeClock;
|
||||||
import io.grpc.internal.ObjectPool;
|
import io.grpc.internal.ObjectPool;
|
||||||
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
|
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
|
||||||
|
import io.grpc.protobuf.ProtoUtils;
|
||||||
import io.grpc.xds.Bootstrapper.ServerInfo;
|
import io.grpc.xds.Bootstrapper.ServerInfo;
|
||||||
import io.grpc.xds.ClusterImplLoadBalancerProvider.ClusterImplConfig;
|
import io.grpc.xds.ClusterImplLoadBalancerProvider.ClusterImplConfig;
|
||||||
import io.grpc.xds.Endpoints.DropOverload;
|
import io.grpc.xds.Endpoints.DropOverload;
|
||||||
|
|
@ -88,11 +90,16 @@ import org.mockito.junit.MockitoRule;
|
||||||
public class ClusterImplLoadBalancerTest {
|
public class ClusterImplLoadBalancerTest {
|
||||||
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
|
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
private static final double TOLERANCE = 1.0e-10;
|
||||||
private static final String AUTHORITY = "api.google.com";
|
private static final String AUTHORITY = "api.google.com";
|
||||||
private static final String CLUSTER = "cluster-foo.googleapis.com";
|
private static final String CLUSTER = "cluster-foo.googleapis.com";
|
||||||
private static final String EDS_SERVICE_NAME = "service.googleapis.com";
|
private static final String EDS_SERVICE_NAME = "service.googleapis.com";
|
||||||
private static final ServerInfo LRS_SERVER_INFO =
|
private static final ServerInfo LRS_SERVER_INFO =
|
||||||
ServerInfo.create("api.google.com", InsecureChannelCredentials.create());
|
ServerInfo.create("api.google.com", InsecureChannelCredentials.create());
|
||||||
|
private static final Metadata.Key<OrcaLoadReport> ORCA_ENDPOINT_LOAD_METRICS_KEY =
|
||||||
|
Metadata.Key.of(
|
||||||
|
"endpoint-load-metrics-bin",
|
||||||
|
ProtoUtils.metadataMarshaller(OrcaLoadReport.getDefaultInstance()));
|
||||||
private final SynchronizationContext syncContext = new SynchronizationContext(
|
private final SynchronizationContext syncContext = new SynchronizationContext(
|
||||||
new Thread.UncaughtExceptionHandler() {
|
new Thread.UncaughtExceptionHandler() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -255,7 +262,21 @@ public class ClusterImplLoadBalancerTest {
|
||||||
ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata()); // second RPC call
|
ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata()); // second RPC call
|
||||||
ClientStreamTracer streamTracer3 = result.getStreamTracerFactory().newClientStreamTracer(
|
ClientStreamTracer streamTracer3 = result.getStreamTracerFactory().newClientStreamTracer(
|
||||||
ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata()); // third RPC call
|
ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata()); // third RPC call
|
||||||
|
// When the trailer contains an ORCA report, the listener callback will be invoked.
|
||||||
|
Metadata trailersWithOrcaLoadReport1 = new Metadata();
|
||||||
|
trailersWithOrcaLoadReport1.put(ORCA_ENDPOINT_LOAD_METRICS_KEY,
|
||||||
|
OrcaLoadReport.newBuilder().setApplicationUtilization(1.414).setMemUtilization(0.034)
|
||||||
|
.setRpsFractional(1.414).putNamedMetrics("named1", 3.14159)
|
||||||
|
.putNamedMetrics("named2", -1.618).build());
|
||||||
|
streamTracer1.inboundTrailers(trailersWithOrcaLoadReport1);
|
||||||
streamTracer1.streamClosed(Status.OK);
|
streamTracer1.streamClosed(Status.OK);
|
||||||
|
Metadata trailersWithOrcaLoadReport2 = new Metadata();
|
||||||
|
trailersWithOrcaLoadReport2.put(ORCA_ENDPOINT_LOAD_METRICS_KEY,
|
||||||
|
OrcaLoadReport.newBuilder().setApplicationUtilization(0.99).setMemUtilization(0.123)
|
||||||
|
.setRpsFractional(0.905).putNamedMetrics("named1", 2.718)
|
||||||
|
.putNamedMetrics("named2", 1.414)
|
||||||
|
.putNamedMetrics("named3", 0.009).build());
|
||||||
|
streamTracer2.inboundTrailers(trailersWithOrcaLoadReport2);
|
||||||
streamTracer2.streamClosed(Status.UNAVAILABLE);
|
streamTracer2.streamClosed(Status.UNAVAILABLE);
|
||||||
ClusterStats clusterStats =
|
ClusterStats clusterStats =
|
||||||
Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
|
Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
|
||||||
|
|
@ -266,6 +287,24 @@ public class ClusterImplLoadBalancerTest {
|
||||||
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(1L);
|
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(1L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().containsKey("named1")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
localityStats.loadMetricStatsMap().get("named1").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
2L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().get("named1").totalMetricValue()).isWithin(
|
||||||
|
TOLERANCE).of(3.14159 + 2.718);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().containsKey("named2")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
localityStats.loadMetricStatsMap().get("named2").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
2L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().get("named2").totalMetricValue()).isWithin(
|
||||||
|
TOLERANCE).of(-1.618 + 1.414);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().containsKey("named3")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
localityStats.loadMetricStatsMap().get("named3").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
1L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().get("named3").totalMetricValue()).isWithin(
|
||||||
|
TOLERANCE).of(0.009);
|
||||||
|
|
||||||
streamTracer3.streamClosed(Status.OK);
|
streamTracer3.streamClosed(Status.OK);
|
||||||
subchannel.shutdown(); // stats recorder released
|
subchannel.shutdown(); // stats recorder released
|
||||||
|
|
@ -278,6 +317,7 @@ public class ClusterImplLoadBalancerTest {
|
||||||
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(0L);
|
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(0L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().isEmpty()).isTrue();
|
||||||
|
|
||||||
clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
|
clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
|
||||||
assertThat(clusterStats.upstreamLocalityStatsList()).isEmpty(); // no longer reported
|
assertThat(clusterStats.upstreamLocalityStatsList()).isEmpty(); // no longer reported
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import com.google.protobuf.Value;
|
||||||
import com.google.protobuf.util.Durations;
|
import com.google.protobuf.util.Durations;
|
||||||
import io.envoyproxy.envoy.config.core.v3.Node;
|
import io.envoyproxy.envoy.config.core.v3.Node;
|
||||||
import io.envoyproxy.envoy.config.endpoint.v3.ClusterStats;
|
import io.envoyproxy.envoy.config.endpoint.v3.ClusterStats;
|
||||||
|
import io.envoyproxy.envoy.config.endpoint.v3.EndpointLoadMetricStats;
|
||||||
import io.envoyproxy.envoy.config.endpoint.v3.UpstreamLocalityStats;
|
import io.envoyproxy.envoy.config.endpoint.v3.UpstreamLocalityStats;
|
||||||
import io.envoyproxy.envoy.service.load_stats.v3.LoadReportingServiceGrpc;
|
import io.envoyproxy.envoy.service.load_stats.v3.LoadReportingServiceGrpc;
|
||||||
import io.envoyproxy.envoy.service.load_stats.v3.LoadStatsRequest;
|
import io.envoyproxy.envoy.service.load_stats.v3.LoadStatsRequest;
|
||||||
|
|
@ -198,11 +199,15 @@ public class LoadReportClientTest {
|
||||||
for (int i = 0; i < 31; i++) {
|
for (int i = 0; i < 31; i++) {
|
||||||
localityStats1.recordCallStarted();
|
localityStats1.recordCallStarted();
|
||||||
}
|
}
|
||||||
|
localityStats1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 3.14159));
|
||||||
|
localityStats1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 1.618));
|
||||||
|
localityStats1.recordBackendLoadMetricStats(ImmutableMap.of("named1", -2.718));
|
||||||
ClusterLocalityStats localityStats2 =
|
ClusterLocalityStats localityStats2 =
|
||||||
loadStatsManager.getClusterLocalityStats(CLUSTER2, EDS_SERVICE_NAME2, LOCALITY2);
|
loadStatsManager.getClusterLocalityStats(CLUSTER2, EDS_SERVICE_NAME2, LOCALITY2);
|
||||||
for (int i = 0; i < 45; i++) {
|
for (int i = 0; i < 45; i++) {
|
||||||
localityStats2.recordCallStarted();
|
localityStats2.recordCallStarted();
|
||||||
}
|
}
|
||||||
|
localityStats2.recordBackendLoadMetricStats(ImmutableMap.of("named2", 1.414));
|
||||||
localityStats2.recordCallFinished(Status.OK);
|
localityStats2.recordCallFinished(Status.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,6 +250,12 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
||||||
|
assertThat(localityStats.getLoadMetricStatsCount()).isEqualTo(1);
|
||||||
|
EndpointLoadMetricStats loadMetricStats = Iterables.getOnlyElement(
|
||||||
|
localityStats.getLoadMetricStatsList());
|
||||||
|
assertThat(loadMetricStats.getMetricName()).isEqualTo("named1");
|
||||||
|
assertThat(loadMetricStats.getNumRequestsFinishedWithMetric()).isEqualTo(3L);
|
||||||
|
assertThat(loadMetricStats.getTotalMetricValue()).isEqualTo(3.14159 + 1.618 - 2.718);
|
||||||
|
|
||||||
fakeClock.forwardTime(10L, TimeUnit.SECONDS);
|
fakeClock.forwardTime(10L, TimeUnit.SECONDS);
|
||||||
verify(requestObserver, times(3)).onNext(requestCaptor.capture());
|
verify(requestObserver, times(3)).onNext(requestCaptor.capture());
|
||||||
|
|
@ -263,6 +274,7 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
||||||
|
assertThat(localityStats.getLoadMetricStatsList()).isEmpty();
|
||||||
|
|
||||||
// Management server updates the interval of sending load reports, while still asking for
|
// Management server updates the interval of sending load reports, while still asking for
|
||||||
// loads to cluster1 only.
|
// loads to cluster1 only.
|
||||||
|
|
@ -287,6 +299,7 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
||||||
|
assertThat(localityStats.getLoadMetricStatsList()).isEmpty();
|
||||||
|
|
||||||
// Management server asks to report loads for all clusters.
|
// Management server asks to report loads for all clusters.
|
||||||
responseObserver.onNext(LoadStatsResponse.newBuilder().setSendAllClusters(true)
|
responseObserver.onNext(LoadStatsResponse.newBuilder().setSendAllClusters(true)
|
||||||
|
|
@ -309,6 +322,7 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats1.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats1.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats1.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats1.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats1.getTotalRequestsInProgress()).isEqualTo(31L);
|
assertThat(localityStats1.getTotalRequestsInProgress()).isEqualTo(31L);
|
||||||
|
assertThat(localityStats1.getLoadMetricStatsList()).isEmpty();
|
||||||
ClusterStats clusterStats2 = findClusterStats(request.getClusterStatsList(), CLUSTER2);
|
ClusterStats clusterStats2 = findClusterStats(request.getClusterStatsList(), CLUSTER2);
|
||||||
assertThat(Durations.toSeconds(clusterStats2.getLoadReportInterval()))
|
assertThat(Durations.toSeconds(clusterStats2.getLoadReportInterval()))
|
||||||
.isEqualTo(10L + 10L + 20L + 20L);
|
.isEqualTo(10L + 10L + 20L + 20L);
|
||||||
|
|
@ -326,6 +340,12 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats2.getTotalSuccessfulRequests()).isEqualTo(1L);
|
assertThat(localityStats2.getTotalSuccessfulRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats2.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats2.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats2.getTotalRequestsInProgress()).isEqualTo(45L - 1L);
|
assertThat(localityStats2.getTotalRequestsInProgress()).isEqualTo(45L - 1L);
|
||||||
|
assertThat(localityStats2.getLoadMetricStatsCount()).isEqualTo(1);
|
||||||
|
EndpointLoadMetricStats loadMetricStats2 = Iterables.getOnlyElement(
|
||||||
|
localityStats2.getLoadMetricStatsList());
|
||||||
|
assertThat(loadMetricStats2.getMetricName()).isEqualTo("named2");
|
||||||
|
assertThat(loadMetricStats2.getNumRequestsFinishedWithMetric()).isEqualTo(1L);
|
||||||
|
assertThat(loadMetricStats2.getTotalMetricValue()).isEqualTo(1.414);
|
||||||
|
|
||||||
// Load reports for cluster1 is no longer wanted.
|
// Load reports for cluster1 is no longer wanted.
|
||||||
responseObserver.onNext(LoadStatsResponse.newBuilder().addClusters(CLUSTER2)
|
responseObserver.onNext(LoadStatsResponse.newBuilder().addClusters(CLUSTER2)
|
||||||
|
|
@ -348,6 +368,7 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(44L);
|
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(44L);
|
||||||
|
assertThat(localityStats.getLoadMetricStatsList()).isEmpty();
|
||||||
|
|
||||||
fakeClock.forwardTime(10L, TimeUnit.SECONDS);
|
fakeClock.forwardTime(10L, TimeUnit.SECONDS);
|
||||||
verify(requestObserver, times(7)).onNext(requestCaptor.capture());
|
verify(requestObserver, times(7)).onNext(requestCaptor.capture());
|
||||||
|
|
@ -366,6 +387,7 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(44L);
|
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(44L);
|
||||||
|
assertThat(localityStats.getLoadMetricStatsList()).isEmpty();
|
||||||
|
|
||||||
// Management server asks loads for a cluster that client has no load data.
|
// Management server asks loads for a cluster that client has no load data.
|
||||||
responseObserver.onNext(LoadStatsResponse.newBuilder().addClusters("unknown.googleapis.com")
|
responseObserver.onNext(LoadStatsResponse.newBuilder().addClusters("unknown.googleapis.com")
|
||||||
|
|
@ -495,6 +517,12 @@ public class LoadReportClientTest {
|
||||||
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.getTotalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
assertThat(localityStats.getTotalRequestsInProgress()).isEqualTo(31L);
|
||||||
|
assertThat(localityStats.getLoadMetricStatsCount()).isEqualTo(1);
|
||||||
|
EndpointLoadMetricStats loadMetricStats = Iterables.getOnlyElement(
|
||||||
|
localityStats.getLoadMetricStatsList());
|
||||||
|
assertThat(loadMetricStats.getMetricName()).isEqualTo("named1");
|
||||||
|
assertThat(loadMetricStats.getNumRequestsFinishedWithMetric()).isEqualTo(3L);
|
||||||
|
assertThat(loadMetricStats.getTotalMetricValue()).isEqualTo(3.14159 + 1.618 - 2.718);
|
||||||
|
|
||||||
// Wrapping up
|
// Wrapping up
|
||||||
verify(backoffPolicyProvider, times(2)).get();
|
verify(backoffPolicyProvider, times(2)).get();
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package io.grpc.xds;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.grpc.internal.FakeClock;
|
import io.grpc.internal.FakeClock;
|
||||||
|
|
@ -39,6 +40,7 @@ import org.junit.runners.JUnit4;
|
||||||
*/
|
*/
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class LoadStatsManager2Test {
|
public class LoadStatsManager2Test {
|
||||||
|
private static final double TOLERANCE = 1.0e-10;
|
||||||
private static final String CLUSTER_NAME1 = "cluster-foo.googleapis.com";
|
private static final String CLUSTER_NAME1 = "cluster-foo.googleapis.com";
|
||||||
private static final String CLUSTER_NAME2 = "cluster-bar.googleapis.com";
|
private static final String CLUSTER_NAME2 = "cluster-bar.googleapis.com";
|
||||||
private static final String EDS_SERVICE_NAME1 = "backend-service-foo.googleapis.com";
|
private static final String EDS_SERVICE_NAME1 = "backend-service-foo.googleapis.com";
|
||||||
|
|
@ -71,12 +73,17 @@ public class LoadStatsManager2Test {
|
||||||
for (int i = 0; i < 19; i++) {
|
for (int i = 0; i < 19; i++) {
|
||||||
loadCounter1.recordCallStarted();
|
loadCounter1.recordCallStarted();
|
||||||
}
|
}
|
||||||
|
loadCounter1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 3.14159));
|
||||||
|
loadCounter1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 1.618));
|
||||||
|
loadCounter1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 99.0));
|
||||||
|
loadCounter1.recordBackendLoadMetricStats(ImmutableMap.of("named1", -97.23, "named2", -2.718));
|
||||||
fakeClock.forwardTime(5L, TimeUnit.SECONDS);
|
fakeClock.forwardTime(5L, TimeUnit.SECONDS);
|
||||||
dropCounter2.recordDroppedRequest();
|
dropCounter2.recordDroppedRequest();
|
||||||
loadCounter1.recordCallFinished(Status.OK);
|
loadCounter1.recordCallFinished(Status.OK);
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
loadCounter2.recordCallStarted();
|
loadCounter2.recordCallStarted();
|
||||||
}
|
}
|
||||||
|
loadCounter2.recordBackendLoadMetricStats(ImmutableMap.of("named3", 0.0009));
|
||||||
loadCounter2.recordCallFinished(Status.UNAVAILABLE);
|
loadCounter2.recordCallFinished(Status.UNAVAILABLE);
|
||||||
fakeClock.forwardTime(10L, TimeUnit.SECONDS);
|
fakeClock.forwardTime(10L, TimeUnit.SECONDS);
|
||||||
loadCounter3.recordCallStarted();
|
loadCounter3.recordCallStarted();
|
||||||
|
|
@ -96,6 +103,18 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(loadStats1.totalSuccessfulRequests()).isEqualTo(1L);
|
assertThat(loadStats1.totalSuccessfulRequests()).isEqualTo(1L);
|
||||||
assertThat(loadStats1.totalErrorRequests()).isEqualTo(0L);
|
assertThat(loadStats1.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats1.totalRequestsInProgress()).isEqualTo(19L - 1L);
|
assertThat(loadStats1.totalRequestsInProgress()).isEqualTo(19L - 1L);
|
||||||
|
assertThat(loadStats1.loadMetricStatsMap().containsKey("named1")).isTrue();
|
||||||
|
assertThat(loadStats1.loadMetricStatsMap().containsKey("named2")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
loadStats1.loadMetricStatsMap().get("named1").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
4L);
|
||||||
|
assertThat(loadStats1.loadMetricStatsMap().get("named1").totalMetricValue()).isWithin(TOLERANCE)
|
||||||
|
.of(3.14159 + 1.618 + 99 - 97.23);
|
||||||
|
assertThat(
|
||||||
|
loadStats1.loadMetricStatsMap().get("named2").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
1L);
|
||||||
|
assertThat(loadStats1.loadMetricStatsMap().get("named2").totalMetricValue()).isWithin(TOLERANCE)
|
||||||
|
.of(-2.718);
|
||||||
|
|
||||||
UpstreamLocalityStats loadStats2 =
|
UpstreamLocalityStats loadStats2 =
|
||||||
findLocalityStats(stats1.upstreamLocalityStatsList(), LOCALITY2);
|
findLocalityStats(stats1.upstreamLocalityStatsList(), LOCALITY2);
|
||||||
|
|
@ -103,6 +122,12 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(loadStats2.totalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(loadStats2.totalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats2.totalErrorRequests()).isEqualTo(1L);
|
assertThat(loadStats2.totalErrorRequests()).isEqualTo(1L);
|
||||||
assertThat(loadStats2.totalRequestsInProgress()).isEqualTo(9L - 1L);
|
assertThat(loadStats2.totalRequestsInProgress()).isEqualTo(9L - 1L);
|
||||||
|
assertThat(loadStats2.loadMetricStatsMap().containsKey("named3")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
loadStats2.loadMetricStatsMap().get("named3").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
1L);
|
||||||
|
assertThat(loadStats2.loadMetricStatsMap().get("named3").totalMetricValue()).isWithin(TOLERANCE)
|
||||||
|
.of(0.0009);
|
||||||
|
|
||||||
ClusterStats stats2 = findClusterStats(allStats, CLUSTER_NAME1, EDS_SERVICE_NAME2);
|
ClusterStats stats2 = findClusterStats(allStats, CLUSTER_NAME1, EDS_SERVICE_NAME2);
|
||||||
assertThat(stats2.loadReportIntervalNano()).isEqualTo(TimeUnit.SECONDS.toNanos(5L + 10L));
|
assertThat(stats2.loadReportIntervalNano()).isEqualTo(TimeUnit.SECONDS.toNanos(5L + 10L));
|
||||||
|
|
@ -121,6 +146,7 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(loadStats3.totalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(loadStats3.totalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats3.totalErrorRequests()).isEqualTo(0L);
|
assertThat(loadStats3.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats3.totalRequestsInProgress()).isEqualTo(1L);
|
assertThat(loadStats3.totalRequestsInProgress()).isEqualTo(1L);
|
||||||
|
assertThat(loadStats3.loadMetricStatsMap()).isEmpty();
|
||||||
|
|
||||||
fakeClock.forwardTime(3L, TimeUnit.SECONDS);
|
fakeClock.forwardTime(3L, TimeUnit.SECONDS);
|
||||||
List<ClusterStats> clusterStatsList = loadStatsManager.getClusterStatsReports(CLUSTER_NAME1);
|
List<ClusterStats> clusterStatsList = loadStatsManager.getClusterStatsReports(CLUSTER_NAME1);
|
||||||
|
|
@ -135,11 +161,13 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(loadStats1.totalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(loadStats1.totalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats1.totalErrorRequests()).isEqualTo(0L);
|
assertThat(loadStats1.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats1.totalRequestsInProgress()).isEqualTo(18L); // still in-progress
|
assertThat(loadStats1.totalRequestsInProgress()).isEqualTo(18L); // still in-progress
|
||||||
|
assertThat(loadStats1.loadMetricStatsMap()).isEmpty();
|
||||||
loadStats2 = findLocalityStats(stats1.upstreamLocalityStatsList(), LOCALITY2);
|
loadStats2 = findLocalityStats(stats1.upstreamLocalityStatsList(), LOCALITY2);
|
||||||
assertThat(loadStats2.totalIssuedRequests()).isEqualTo(0L);
|
assertThat(loadStats2.totalIssuedRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats2.totalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(loadStats2.totalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats2.totalErrorRequests()).isEqualTo(0L);
|
assertThat(loadStats2.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(loadStats2.totalRequestsInProgress()).isEqualTo(8L); // still in-progress
|
assertThat(loadStats2.totalRequestsInProgress()).isEqualTo(8L); // still in-progress
|
||||||
|
assertThat(loadStats2.loadMetricStatsMap()).isEmpty();
|
||||||
|
|
||||||
stats2 = findClusterStats(clusterStatsList, CLUSTER_NAME1, EDS_SERVICE_NAME2);
|
stats2 = findClusterStats(clusterStatsList, CLUSTER_NAME1, EDS_SERVICE_NAME2);
|
||||||
assertThat(stats2.loadReportIntervalNano()).isEqualTo(TimeUnit.SECONDS.toNanos(3L));
|
assertThat(stats2.loadReportIntervalNano()).isEqualTo(TimeUnit.SECONDS.toNanos(3L));
|
||||||
|
|
@ -194,9 +222,12 @@ public class LoadStatsManager2Test {
|
||||||
ClusterLocalityStats ref2 = loadStatsManager.getClusterLocalityStats(
|
ClusterLocalityStats ref2 = loadStatsManager.getClusterLocalityStats(
|
||||||
CLUSTER_NAME1, EDS_SERVICE_NAME1, LOCALITY1);
|
CLUSTER_NAME1, EDS_SERVICE_NAME1, LOCALITY1);
|
||||||
ref1.recordCallStarted();
|
ref1.recordCallStarted();
|
||||||
|
ref1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 1.618));
|
||||||
|
ref1.recordBackendLoadMetricStats(ImmutableMap.of("named1", 3.14159));
|
||||||
ref1.recordCallFinished(Status.OK);
|
ref1.recordCallFinished(Status.OK);
|
||||||
ref2.recordCallStarted();
|
ref2.recordCallStarted();
|
||||||
ref2.recordCallStarted();
|
ref2.recordCallStarted();
|
||||||
|
ref2.recordBackendLoadMetricStats(ImmutableMap.of("named1", -1.0, "named2", 2.718));
|
||||||
ref2.recordCallFinished(Status.UNAVAILABLE);
|
ref2.recordCallFinished(Status.UNAVAILABLE);
|
||||||
|
|
||||||
ClusterStats stats = Iterables.getOnlyElement(
|
ClusterStats stats = Iterables.getOnlyElement(
|
||||||
|
|
@ -207,6 +238,18 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(1L + 2L - 1L - 1L);
|
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(1L + 2L - 1L - 1L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().containsKey("named1")).isTrue();
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().containsKey("named2")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
localityStats.loadMetricStatsMap().get("named1").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
3L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().get("named1").totalMetricValue()).isWithin(
|
||||||
|
TOLERANCE).of(1.618 + 3.14159 - 1);
|
||||||
|
assertThat(
|
||||||
|
localityStats.loadMetricStatsMap().get("named2").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
1L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().get("named2").totalMetricValue()).isEqualTo(
|
||||||
|
2.718);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -215,6 +258,8 @@ public class LoadStatsManager2Test {
|
||||||
CLUSTER_NAME1, EDS_SERVICE_NAME1, LOCALITY1);
|
CLUSTER_NAME1, EDS_SERVICE_NAME1, LOCALITY1);
|
||||||
counter.recordCallStarted();
|
counter.recordCallStarted();
|
||||||
counter.recordCallStarted();
|
counter.recordCallStarted();
|
||||||
|
counter.recordBackendLoadMetricStats(ImmutableMap.of("named1", 2.718));
|
||||||
|
counter.recordBackendLoadMetricStats(ImmutableMap.of("named1", 1.414));
|
||||||
|
|
||||||
ClusterStats stats = Iterables.getOnlyElement(
|
ClusterStats stats = Iterables.getOnlyElement(
|
||||||
loadStatsManager.getClusterStatsReports(CLUSTER_NAME1));
|
loadStatsManager.getClusterStatsReports(CLUSTER_NAME1));
|
||||||
|
|
@ -224,6 +269,12 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(0L);
|
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(2L);
|
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(2L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().containsKey("named1")).isTrue();
|
||||||
|
assertThat(
|
||||||
|
localityStats.loadMetricStatsMap().get("named1").numRequestsFinishedWithMetric()).isEqualTo(
|
||||||
|
2L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().get("named1").totalMetricValue()).isEqualTo(
|
||||||
|
2.718 + 1.414);
|
||||||
|
|
||||||
// release the counter, but requests still in-flight
|
// release the counter, but requests still in-flight
|
||||||
counter.release();
|
counter.release();
|
||||||
|
|
@ -234,6 +285,7 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
|
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
|
||||||
assertThat(localityStats.totalRequestsInProgress())
|
assertThat(localityStats.totalRequestsInProgress())
|
||||||
.isEqualTo(2L); // retained by in-flight calls
|
.isEqualTo(2L); // retained by in-flight calls
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().isEmpty()).isTrue();
|
||||||
|
|
||||||
counter.recordCallFinished(Status.OK);
|
counter.recordCallFinished(Status.OK);
|
||||||
counter.recordCallFinished(Status.UNAVAILABLE);
|
counter.recordCallFinished(Status.UNAVAILABLE);
|
||||||
|
|
@ -243,6 +295,7 @@ public class LoadStatsManager2Test {
|
||||||
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
|
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
|
||||||
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(0L);
|
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(0L);
|
||||||
|
assertThat(localityStats.loadMetricStatsMap().isEmpty()).isTrue();
|
||||||
|
|
||||||
assertThat(loadStatsManager.getClusterStatsReports(CLUSTER_NAME1)).isEmpty();
|
assertThat(loadStatsManager.getClusterStatsReports(CLUSTER_NAME1)).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -214,10 +214,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||||
assertThat(weightedPicker.pickSubchannel(mockArgs)
|
assertThat(weightedPicker.pickSubchannel(mockArgs)
|
||||||
.getSubchannel()).isEqualTo(weightedSubchannel1);
|
.getSubchannel()).isEqualTo(weightedSubchannel1);
|
||||||
|
|
@ -260,10 +260,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.9, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.9, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||||
PickResult pickResult = weightedPicker.pickSubchannel(mockArgs);
|
PickResult pickResult = weightedPicker.pickSubchannel(mockArgs);
|
||||||
assertThat(pickResult.getSubchannel()).isEqualTo(weightedSubchannel1);
|
assertThat(pickResult.getSubchannel()).isEqualTo(weightedSubchannel1);
|
||||||
|
|
@ -340,11 +340,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
@Test
|
@Test
|
||||||
public void pickByWeight_largeWeight() {
|
public void pickByWeight_largeWeight() {
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 999, 0, new HashMap<>(), new HashMap<>());
|
0.1, 0, 0.1, 999, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.9, 0, 0.1, 2, 0, new HashMap<>(), new HashMap<>());
|
0.9, 0, 0.1, 2, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.86, 0, 0.1, 100, 0, new HashMap<>(), new HashMap<>());
|
0.86, 0, 0.1, 100, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double totalWeight = 999 / 0.1 + 2 / 0.9 + 100 / 0.86;
|
double totalWeight = 999 / 0.1 + 2 / 0.9 + 100 / 0.86;
|
||||||
|
|
||||||
pickByWeight(report1, report2, report3, 999 / 0.1 / totalWeight, 2 / 0.9 / totalWeight,
|
pickByWeight(report1, report2, report3, 999 / 0.1 / totalWeight, 2 / 0.9 / totalWeight,
|
||||||
|
|
@ -354,11 +354,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
@Test
|
@Test
|
||||||
public void pickByWeight_largeWeight_useApplicationUtilization() {
|
public void pickByWeight_largeWeight_useApplicationUtilization() {
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.44, 0.1, 0.1, 999, 0, new HashMap<>(), new HashMap<>());
|
0.44, 0.1, 0.1, 999, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.12, 0.9, 0.1, 2, 0, new HashMap<>(), new HashMap<>());
|
0.12, 0.9, 0.1, 2, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.33, 0.86, 0.1, 100, 0, new HashMap<>(), new HashMap<>());
|
0.33, 0.86, 0.1, 100, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double totalWeight = 999 / 0.1 + 2 / 0.9 + 100 / 0.86;
|
double totalWeight = 999 / 0.1 + 2 / 0.9 + 100 / 0.86;
|
||||||
|
|
||||||
pickByWeight(report1, report2, report3, 999 / 0.1 / totalWeight, 2 / 0.9 / totalWeight,
|
pickByWeight(report1, report2, report3, 999 / 0.1 / totalWeight, 2 / 0.9 / totalWeight,
|
||||||
|
|
@ -368,11 +368,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
@Test
|
@Test
|
||||||
public void pickByWeight_largeWeight_withEps_defaultErrorUtilizationPenalty() {
|
public void pickByWeight_largeWeight_withEps_defaultErrorUtilizationPenalty() {
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 999, 13, new HashMap<>(), new HashMap<>());
|
0.1, 0, 0.1, 999, 13, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.9, 0, 0.1, 2, 1.8, new HashMap<>(), new HashMap<>());
|
0.9, 0, 0.1, 2, 1.8, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.86, 0, 0.1, 100, 3, new HashMap<>(), new HashMap<>());
|
0.86, 0, 0.1, 100, 3, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double weight1 = 999 / (0.1 + 13 / 999F * weightedConfig.errorUtilizationPenalty);
|
double weight1 = 999 / (0.1 + 13 / 999F * weightedConfig.errorUtilizationPenalty);
|
||||||
double weight2 = 2 / (0.9 + 1.8 / 2F * weightedConfig.errorUtilizationPenalty);
|
double weight2 = 2 / (0.9 + 1.8 / 2F * weightedConfig.errorUtilizationPenalty);
|
||||||
double weight3 = 100 / (0.86 + 3 / 100F * weightedConfig.errorUtilizationPenalty);
|
double weight3 = 100 / (0.86 + 3 / 100F * weightedConfig.errorUtilizationPenalty);
|
||||||
|
|
@ -385,11 +385,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
@Test
|
@Test
|
||||||
public void pickByWeight_normalWeight() {
|
public void pickByWeight_normalWeight() {
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.12, 0, 0.1, 22, 0, new HashMap<>(), new HashMap<>());
|
0.12, 0, 0.1, 22, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.28, 0, 0.1, 40, 0, new HashMap<>(), new HashMap<>());
|
0.28, 0, 0.1, 40, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.86, 0, 0.1, 100, 0, new HashMap<>(), new HashMap<>());
|
0.86, 0, 0.1, 100, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double totalWeight = 22 / 0.12 + 40 / 0.28 + 100 / 0.86;
|
double totalWeight = 22 / 0.12 + 40 / 0.28 + 100 / 0.86;
|
||||||
pickByWeight(report1, report2, report3, 22 / 0.12 / totalWeight,
|
pickByWeight(report1, report2, report3, 22 / 0.12 / totalWeight,
|
||||||
40 / 0.28 / totalWeight, 100 / 0.86 / totalWeight
|
40 / 0.28 / totalWeight, 100 / 0.86 / totalWeight
|
||||||
|
|
@ -399,11 +399,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
@Test
|
@Test
|
||||||
public void pickByWeight_normalWeight_useApplicationUtilization() {
|
public void pickByWeight_normalWeight_useApplicationUtilization() {
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.72, 0.12, 0.1, 22, 0, new HashMap<>(), new HashMap<>());
|
0.72, 0.12, 0.1, 22, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.98, 0.28, 0.1, 40, 0, new HashMap<>(), new HashMap<>());
|
0.98, 0.28, 0.1, 40, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.99, 0.86, 0.1, 100, 0, new HashMap<>(), new HashMap<>());
|
0.99, 0.86, 0.1, 100, 0, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double totalWeight = 22 / 0.12 + 40 / 0.28 + 100 / 0.86;
|
double totalWeight = 22 / 0.12 + 40 / 0.28 + 100 / 0.86;
|
||||||
pickByWeight(report1, report2, report3, 22 / 0.12 / totalWeight,
|
pickByWeight(report1, report2, report3, 22 / 0.12 / totalWeight,
|
||||||
40 / 0.28 / totalWeight, 100 / 0.86 / totalWeight
|
40 / 0.28 / totalWeight, 100 / 0.86 / totalWeight
|
||||||
|
|
@ -413,11 +413,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
@Test
|
@Test
|
||||||
public void pickByWeight_normalWeight_withEps_defaultErrorUtilizationPenalty() {
|
public void pickByWeight_normalWeight_withEps_defaultErrorUtilizationPenalty() {
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.12, 0, 0.1, 22, 19.7, new HashMap<>(), new HashMap<>());
|
0.12, 0, 0.1, 22, 19.7, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.28, 0, 0.1, 40, 0.998, new HashMap<>(), new HashMap<>());
|
0.28, 0, 0.1, 40, 0.998, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.86, 0, 0.1, 100, 3.14159, new HashMap<>(), new HashMap<>());
|
0.86, 0, 0.1, 100, 3.14159, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double weight1 = 22 / (0.12 + 19.7 / 22F * weightedConfig.errorUtilizationPenalty);
|
double weight1 = 22 / (0.12 + 19.7 / 22F * weightedConfig.errorUtilizationPenalty);
|
||||||
double weight2 = 40 / (0.28 + 0.998 / 40F * weightedConfig.errorUtilizationPenalty);
|
double weight2 = 40 / (0.28 + 0.998 / 40F * weightedConfig.errorUtilizationPenalty);
|
||||||
double weight3 = 100 / (0.86 + 3.14159 / 100F * weightedConfig.errorUtilizationPenalty);
|
double weight3 = 100 / (0.86 + 3.14159 / 100F * weightedConfig.errorUtilizationPenalty);
|
||||||
|
|
@ -433,11 +433,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
.setErrorUtilizationPenalty(1.75F).build();
|
.setErrorUtilizationPenalty(1.75F).build();
|
||||||
|
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.12, 0, 0.1, 22, 19.7, new HashMap<>(), new HashMap<>());
|
0.12, 0, 0.1, 22, 19.7, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.28, 0, 0.1, 40, 0.998, new HashMap<>(), new HashMap<>());
|
0.28, 0, 0.1, 40, 0.998, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0.86, 0, 0.1, 100, 3.14159, new HashMap<>(), new HashMap<>());
|
0.86, 0, 0.1, 100, 3.14159, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double weight1 = 22 / (0.12 + 19.7 / 22F * weightedConfig.errorUtilizationPenalty);
|
double weight1 = 22 / (0.12 + 19.7 / 22F * weightedConfig.errorUtilizationPenalty);
|
||||||
double weight2 = 40 / (0.28 + 0.998 / 40F * weightedConfig.errorUtilizationPenalty);
|
double weight2 = 40 / (0.28 + 0.998 / 40F * weightedConfig.errorUtilizationPenalty);
|
||||||
double weight3 = 100 / (0.86 + 3.14159 / 100F * weightedConfig.errorUtilizationPenalty);
|
double weight3 = 100 / (0.86 + 3.14159 / 100F * weightedConfig.errorUtilizationPenalty);
|
||||||
|
|
@ -453,11 +453,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
.setErrorUtilizationPenalty(1.75F).build();
|
.setErrorUtilizationPenalty(1.75F).build();
|
||||||
|
|
||||||
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report1 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0, 0, 0.1, 22, 19.7, new HashMap<>(), new HashMap<>());
|
0, 0, 0.1, 22, 19.7, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report2 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0, 0, 0.1, 40, 0.998, new HashMap<>(), new HashMap<>());
|
0, 0, 0.1, 40, 0.998, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
MetricReport report3 = InternalCallMetricRecorder.createMetricReport(
|
||||||
0, 0, 0.1, 100, 3.14159, new HashMap<>(), new HashMap<>());
|
0, 0, 0.1, 100, 3.14159, new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
double avgSubchannelPickRatio = 1.0 / 3;
|
double avgSubchannelPickRatio = 1.0 / 3;
|
||||||
|
|
||||||
pickByWeight(report1, report2, report3, avgSubchannelPickRatio, avgSubchannelPickRatio,
|
pickByWeight(report1, report2, report3, avgSubchannelPickRatio, avgSubchannelPickRatio,
|
||||||
|
|
@ -508,10 +508,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
assertThat(fakeClock.forwardTime(5, TimeUnit.SECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(5, TimeUnit.SECONDS)).isEqualTo(1);
|
||||||
Map<Subchannel, Integer> pickCount = new HashMap<>();
|
Map<Subchannel, Integer> pickCount = new HashMap<>();
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
|
@ -568,10 +568,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||||
assertThat(weightedPicker.pickSubchannel(mockArgs)
|
assertThat(weightedPicker.pickSubchannel(mockArgs)
|
||||||
.getSubchannel()).isEqualTo(weightedSubchannel1);
|
.getSubchannel()).isEqualTo(weightedSubchannel1);
|
||||||
|
|
@ -585,10 +585,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
//timer fires, new weight updated
|
//timer fires, new weight updated
|
||||||
assertThat(fakeClock.forwardTime(500, TimeUnit.MILLISECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(500, TimeUnit.MILLISECONDS)).isEqualTo(1);
|
||||||
assertThat(weightedPicker.pickSubchannel(mockArgs)
|
assertThat(weightedPicker.pickSubchannel(mockArgs)
|
||||||
|
|
@ -620,10 +620,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
||||||
Map<Subchannel, Integer> pickCount = new HashMap<>();
|
Map<Subchannel, Integer> pickCount = new HashMap<>();
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
|
@ -685,7 +685,7 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
subchannel.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
subchannel.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, qpsByChannel.get(subchannel), 0,
|
0.1, 0, 0.1, qpsByChannel.get(subchannel), 0,
|
||||||
new HashMap<>(), new HashMap<>()));
|
new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
}
|
}
|
||||||
assertThat(Math.abs(pickCount.get(weightedSubchannel1) / 1000.0 - 1.0 / 2))
|
assertThat(Math.abs(pickCount.get(weightedSubchannel1) / 1000.0 - 1.0 / 2))
|
||||||
.isAtMost(0.1);
|
.isAtMost(0.1);
|
||||||
|
|
@ -701,7 +701,7 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
subchannel.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
subchannel.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, qpsByChannel.get(subchannel), 0,
|
0.1, 0, 0.1, qpsByChannel.get(subchannel), 0,
|
||||||
new HashMap<>(), new HashMap<>()));
|
new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
fakeClock.forwardTime(50, TimeUnit.MILLISECONDS);
|
fakeClock.forwardTime(50, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
assertThat(pickCount.size()).isEqualTo(2);
|
assertThat(pickCount.size()).isEqualTo(2);
|
||||||
|
|
@ -739,10 +739,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel3 = (WrrSubchannel) weightedPicker.getList().get(2);
|
WrrSubchannel weightedSubchannel3 = (WrrSubchannel) weightedPicker.getList().get(2);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
||||||
Map<Subchannel, Integer> pickCount = new HashMap<>();
|
Map<Subchannel, Integer> pickCount = new HashMap<>();
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
|
@ -783,10 +783,10 @@ public class WeightedRoundRobinLoadBalancerTest {
|
||||||
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
WrrSubchannel weightedSubchannel2 = (WrrSubchannel) weightedPicker.getList().get(1);
|
||||||
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
weightedSubchannel2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||||
InternalCallMetricRecorder.createMetricReport(
|
InternalCallMetricRecorder.createMetricReport(
|
||||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>()));
|
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||||
CyclicBarrier barrier = new CyclicBarrier(2);
|
CyclicBarrier barrier = new CyclicBarrier(2);
|
||||||
Map<Subchannel, AtomicInteger> pickCount = new ConcurrentHashMap<>();
|
Map<Subchannel, AtomicInteger> pickCount = new ConcurrentHashMap<>();
|
||||||
pickCount.put(weightedSubchannel1, new AtomicInteger(0));
|
pickCount.put(weightedSubchannel1, new AtomicInteger(0));
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ public class OrcaMetricReportingServerInterceptorTest {
|
||||||
|
|
||||||
private final Map<String, Double> applicationUtilizationMetricsMap = new HashMap<>();
|
private final Map<String, Double> applicationUtilizationMetricsMap = new HashMap<>();
|
||||||
private final Map<String, Double> applicationCostMetrics = new HashMap<>();
|
private final Map<String, Double> applicationCostMetrics = new HashMap<>();
|
||||||
|
private final Map<String, Double> applicationNamedMetrics = new HashMap<>();
|
||||||
private double cpuUtilizationMetrics = 0;
|
private double cpuUtilizationMetrics = 0;
|
||||||
private double applicationUtilizationMetrics = 0;
|
private double applicationUtilizationMetrics = 0;
|
||||||
private double memoryUtilizationMetrics = 0;
|
private double memoryUtilizationMetrics = 0;
|
||||||
|
|
@ -98,6 +99,9 @@ public class OrcaMetricReportingServerInterceptorTest {
|
||||||
CallMetricRecorder.getCurrent().recordRequestCostMetric(entry.getKey(),
|
CallMetricRecorder.getCurrent().recordRequestCostMetric(entry.getKey(),
|
||||||
entry.getValue());
|
entry.getValue());
|
||||||
}
|
}
|
||||||
|
for (Map.Entry<String, Double> entry : applicationNamedMetrics.entrySet()) {
|
||||||
|
CallMetricRecorder.getCurrent().recordNamedMetric(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
CallMetricRecorder.getCurrent().recordCpuUtilizationMetric(cpuUtilizationMetrics);
|
CallMetricRecorder.getCurrent().recordCpuUtilizationMetric(cpuUtilizationMetrics);
|
||||||
CallMetricRecorder.getCurrent()
|
CallMetricRecorder.getCurrent()
|
||||||
.recordApplicationUtilizationMetric(applicationUtilizationMetrics);
|
.recordApplicationUtilizationMetric(applicationUtilizationMetrics);
|
||||||
|
|
@ -196,6 +200,9 @@ public class OrcaMetricReportingServerInterceptorTest {
|
||||||
applicationUtilizationMetricsMap.put("util1", 0.1082);
|
applicationUtilizationMetricsMap.put("util1", 0.1082);
|
||||||
applicationUtilizationMetricsMap.put("util2", 0.4936);
|
applicationUtilizationMetricsMap.put("util2", 0.4936);
|
||||||
applicationUtilizationMetricsMap.put("util3", 0.5342);
|
applicationUtilizationMetricsMap.put("util3", 0.5342);
|
||||||
|
applicationNamedMetrics.put("named1", 0.777);
|
||||||
|
applicationNamedMetrics.put("named2", 737.747);
|
||||||
|
applicationNamedMetrics.put("named3", -0.380);
|
||||||
cpuUtilizationMetrics = 0.3465;
|
cpuUtilizationMetrics = 0.3465;
|
||||||
applicationUtilizationMetrics = 0.99887;
|
applicationUtilizationMetrics = 0.99887;
|
||||||
memoryUtilizationMetrics = 0.764;
|
memoryUtilizationMetrics = 0.764;
|
||||||
|
|
@ -209,6 +216,8 @@ public class OrcaMetricReportingServerInterceptorTest {
|
||||||
.containsExactly("util1", 0.1082, "util2", 0.4936, "util3", 0.5342);
|
.containsExactly("util1", 0.1082, "util2", 0.4936, "util3", 0.5342);
|
||||||
assertThat(report.getRequestCostMap())
|
assertThat(report.getRequestCostMap())
|
||||||
.containsExactly("cost1", 1231.4543, "cost2", 0.1367, "cost3", 7614.145);
|
.containsExactly("cost1", 1231.4543, "cost2", 0.1367, "cost3", 7614.145);
|
||||||
|
assertThat(report.getNamedMetricsMap())
|
||||||
|
.containsExactly("named1", 0.777, "named2", 737.747, "named3", -0.380);
|
||||||
assertThat(report.getCpuUtilization()).isEqualTo(0.3465);
|
assertThat(report.getCpuUtilization()).isEqualTo(0.3465);
|
||||||
assertThat(report.getApplicationUtilization()).isEqualTo(0.99887);
|
assertThat(report.getApplicationUtilization()).isEqualTo(0.99887);
|
||||||
assertThat(report.getMemUtilization()).isEqualTo(0.764);
|
assertThat(report.getMemUtilization()).isEqualTo(0.764);
|
||||||
|
|
@ -221,6 +230,9 @@ public class OrcaMetricReportingServerInterceptorTest {
|
||||||
applicationUtilizationMetricsMap.put("util1", 0.1482);
|
applicationUtilizationMetricsMap.put("util1", 0.1482);
|
||||||
applicationUtilizationMetricsMap.put("util2", 0.4036);
|
applicationUtilizationMetricsMap.put("util2", 0.4036);
|
||||||
applicationUtilizationMetricsMap.put("util3", 0.5742);
|
applicationUtilizationMetricsMap.put("util3", 0.5742);
|
||||||
|
applicationNamedMetrics.put("named1", 0.777);
|
||||||
|
applicationNamedMetrics.put("named2", 737.747);
|
||||||
|
applicationNamedMetrics.put("named3", -0.380);
|
||||||
cpuUtilizationMetrics = 0.3465;
|
cpuUtilizationMetrics = 0.3465;
|
||||||
memoryUtilizationMetrics = 0.967;
|
memoryUtilizationMetrics = 0.967;
|
||||||
metricRecorder.setApplicationUtilizationMetric(2.718);
|
metricRecorder.setApplicationUtilizationMetric(2.718);
|
||||||
|
|
@ -240,6 +252,8 @@ public class OrcaMetricReportingServerInterceptorTest {
|
||||||
assertThat(report.getUtilizationMap())
|
assertThat(report.getUtilizationMap())
|
||||||
.containsExactly("util1", 0.1482, "util2", 0.4036, "util3", 0.5742, "serverUtil1", 0.7467,
|
.containsExactly("util1", 0.1482, "util2", 0.4036, "util3", 0.5742, "serverUtil1", 0.7467,
|
||||||
"serverUtil2", 0.2233);
|
"serverUtil2", 0.2233);
|
||||||
|
assertThat(report.getNamedMetricsMap())
|
||||||
|
.containsExactly("named1", 0.777, "named2", 737.747, "named3", -0.380);
|
||||||
assertThat(report.getRequestCostMap()).isEmpty();
|
assertThat(report.getRequestCostMap()).isEmpty();
|
||||||
assertThat(report.getCpuUtilization()).isEqualTo(0.3465);
|
assertThat(report.getCpuUtilization()).isEqualTo(0.3465);
|
||||||
assertThat(report.getApplicationUtilization()).isEqualTo(2.718);
|
assertThat(report.getApplicationUtilization()).isEqualTo(2.718);
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,8 @@ public class OrcaPerRequestUtilTest {
|
||||||
&& a.getQps() == b.getQps()
|
&& a.getQps() == b.getQps()
|
||||||
&& a.getEps() == b.getEps()
|
&& a.getEps() == b.getEps()
|
||||||
&& Objects.equal(a.getRequestCostMetrics(), b.getRequestCostMetrics())
|
&& Objects.equal(a.getRequestCostMetrics(), b.getRequestCostMetrics())
|
||||||
&& Objects.equal(a.getUtilizationMetrics(), b.getUtilizationMetrics());
|
&& Objects.equal(a.getUtilizationMetrics(), b.getUtilizationMetrics())
|
||||||
|
&& Objects.equal(a.getNamedMetrics(), b.getNamedMetrics());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue