use of io.grpc.xds.Stats.ClusterStats in project grpc-java by grpc.
the class ClusterImplLoadBalancerTest method subtest_maxConcurrentRequests_appliedWithDefaultValue.
private void subtest_maxConcurrentRequests_appliedWithDefaultValue(boolean enableCircuitBreaking) {
LoadBalancerProvider weightedTargetProvider = new WeightedTargetLoadBalancerProvider();
WeightedTargetConfig weightedTargetConfig = buildWeightedTargetConfig(ImmutableMap.of(locality, 10));
ClusterImplConfig config = new ClusterImplConfig(CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_INFO, null, Collections.<DropOverload>emptyList(), new PolicySelection(weightedTargetProvider, weightedTargetConfig), null);
EquivalentAddressGroup endpoint = makeAddress("endpoint-addr", locality);
deliverAddressesAndConfig(Collections.singletonList(endpoint), config);
// one leaf balancer
assertThat(downstreamBalancers).hasSize(1);
FakeLoadBalancer leafBalancer = Iterables.getOnlyElement(downstreamBalancers);
assertThat(leafBalancer.name).isEqualTo("round_robin");
assertThat(Iterables.getOnlyElement(leafBalancer.addresses).getAddresses()).isEqualTo(endpoint.getAddresses());
Subchannel subchannel = leafBalancer.helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(leafBalancer.addresses).build());
leafBalancer.deliverSubchannelState(subchannel, ConnectivityState.READY);
assertThat(currentState).isEqualTo(ConnectivityState.READY);
for (int i = 0; i < ClusterImplLoadBalancer.DEFAULT_PER_CLUSTER_MAX_CONCURRENT_REQUESTS; i++) {
PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isTrue();
ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory();
streamTracerFactory.newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata());
}
ClusterStats clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
assertThat(clusterStats.clusterServiceName()).isEqualTo(EDS_SERVICE_NAME);
assertThat(clusterStats.totalDroppedRequests()).isEqualTo(0L);
PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
assertThat(clusterStats.clusterServiceName()).isEqualTo(EDS_SERVICE_NAME);
if (enableCircuitBreaking) {
assertThat(result.getStatus().isOk()).isFalse();
assertThat(result.getStatus().getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(result.getStatus().getDescription()).isEqualTo("Cluster max concurrent requests limit exceeded");
assertThat(clusterStats.totalDroppedRequests()).isEqualTo(1L);
} else {
assertThat(result.getStatus().isOk()).isTrue();
assertThat(clusterStats.totalDroppedRequests()).isEqualTo(0L);
}
}
use of io.grpc.xds.Stats.ClusterStats in project grpc-java by grpc.
the class ClusterImplLoadBalancerTest method recordLoadStats.
@Test
public void recordLoadStats() {
LoadBalancerProvider weightedTargetProvider = new WeightedTargetLoadBalancerProvider();
WeightedTargetConfig weightedTargetConfig = buildWeightedTargetConfig(ImmutableMap.of(locality, 10));
ClusterImplConfig config = new ClusterImplConfig(CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_INFO, null, Collections.<DropOverload>emptyList(), new PolicySelection(weightedTargetProvider, weightedTargetConfig), null);
EquivalentAddressGroup endpoint = makeAddress("endpoint-addr", locality);
deliverAddressesAndConfig(Collections.singletonList(endpoint), config);
FakeLoadBalancer leafBalancer = Iterables.getOnlyElement(downstreamBalancers);
Subchannel subchannel = leafBalancer.helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(leafBalancer.addresses).build());
leafBalancer.deliverSubchannelState(subchannel, ConnectivityState.READY);
assertThat(currentState).isEqualTo(ConnectivityState.READY);
PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isTrue();
ClientStreamTracer streamTracer1 = result.getStreamTracerFactory().newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), // first RPC call
new Metadata());
ClientStreamTracer streamTracer2 = result.getStreamTracerFactory().newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), // second RPC call
new Metadata());
ClientStreamTracer streamTracer3 = result.getStreamTracerFactory().newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), // third RPC call
new Metadata());
streamTracer1.streamClosed(Status.OK);
streamTracer2.streamClosed(Status.UNAVAILABLE);
ClusterStats clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
UpstreamLocalityStats localityStats = Iterables.getOnlyElement(clusterStats.upstreamLocalityStatsList());
assertThat(localityStats.locality()).isEqualTo(locality);
assertThat(localityStats.totalIssuedRequests()).isEqualTo(3L);
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
assertThat(localityStats.totalErrorRequests()).isEqualTo(1L);
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(1L);
streamTracer3.streamClosed(Status.OK);
// stats recorder released
subchannel.shutdown();
clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
// Locality load is reported for one last time in case of loads occurred since the previous
// load report.
localityStats = Iterables.getOnlyElement(clusterStats.upstreamLocalityStatsList());
assertThat(localityStats.locality()).isEqualTo(locality);
assertThat(localityStats.totalIssuedRequests()).isEqualTo(0L);
assertThat(localityStats.totalSuccessfulRequests()).isEqualTo(1L);
assertThat(localityStats.totalErrorRequests()).isEqualTo(0L);
assertThat(localityStats.totalRequestsInProgress()).isEqualTo(0L);
clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
// no longer reported
assertThat(clusterStats.upstreamLocalityStatsList()).isEmpty();
}
use of io.grpc.xds.Stats.ClusterStats in project grpc-java by grpc.
the class ClusterImplLoadBalancerTest method dropRpcsWithRespectToLbConfigDropCategories.
@Test
public void dropRpcsWithRespectToLbConfigDropCategories() {
LoadBalancerProvider weightedTargetProvider = new WeightedTargetLoadBalancerProvider();
WeightedTargetConfig weightedTargetConfig = buildWeightedTargetConfig(ImmutableMap.of(locality, 10));
ClusterImplConfig config = new ClusterImplConfig(CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_INFO, null, Collections.singletonList(DropOverload.create("throttle", 500_000)), new PolicySelection(weightedTargetProvider, weightedTargetConfig), null);
EquivalentAddressGroup endpoint = makeAddress("endpoint-addr", locality);
deliverAddressesAndConfig(Collections.singletonList(endpoint), config);
when(mockRandom.nextInt(anyInt())).thenReturn(499_999, 999_999, 1_000_000);
// one leaf balancer
assertThat(downstreamBalancers).hasSize(1);
FakeLoadBalancer leafBalancer = Iterables.getOnlyElement(downstreamBalancers);
assertThat(leafBalancer.name).isEqualTo("round_robin");
assertThat(Iterables.getOnlyElement(leafBalancer.addresses).getAddresses()).isEqualTo(endpoint.getAddresses());
Subchannel subchannel = leafBalancer.helper.createSubchannel(CreateSubchannelArgs.newBuilder().setAddresses(leafBalancer.addresses).build());
leafBalancer.deliverSubchannelState(subchannel, ConnectivityState.READY);
assertThat(currentState).isEqualTo(ConnectivityState.READY);
PickResult result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isFalse();
assertThat(result.getStatus().getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(result.getStatus().getDescription()).isEqualTo("Dropped: throttle");
ClusterStats clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
assertThat(clusterStats.clusterServiceName()).isEqualTo(EDS_SERVICE_NAME);
assertThat(Iterables.getOnlyElement(clusterStats.droppedRequestsList()).category()).isEqualTo("throttle");
assertThat(Iterables.getOnlyElement(clusterStats.droppedRequestsList()).droppedCount()).isEqualTo(1L);
assertThat(clusterStats.totalDroppedRequests()).isEqualTo(1L);
// Config update updates drop policies.
config = new ClusterImplConfig(CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_INFO, null, Collections.singletonList(DropOverload.create("lb", 1_000_000)), new PolicySelection(weightedTargetProvider, weightedTargetConfig), null);
loadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder().setAddresses(Collections.singletonList(endpoint)).setAttributes(Attributes.newBuilder().set(InternalXdsAttributes.XDS_CLIENT_POOL, xdsClientPool).build()).setLoadBalancingPolicyConfig(config).build());
result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isFalse();
assertThat(result.getStatus().getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(result.getStatus().getDescription()).isEqualTo("Dropped: lb");
clusterStats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER));
assertThat(clusterStats.clusterServiceName()).isEqualTo(EDS_SERVICE_NAME);
assertThat(Iterables.getOnlyElement(clusterStats.droppedRequestsList()).category()).isEqualTo("lb");
assertThat(Iterables.getOnlyElement(clusterStats.droppedRequestsList()).droppedCount()).isEqualTo(1L);
assertThat(clusterStats.totalDroppedRequests()).isEqualTo(1L);
result = currentPicker.pickSubchannel(mock(PickSubchannelArgs.class));
assertThat(result.getStatus().isOk()).isTrue();
}
use of io.grpc.xds.Stats.ClusterStats in project grpc-java by grpc.
the class LoadStatsManager2Test method sharedDropCounterStatsAggregation.
@Test
public void sharedDropCounterStatsAggregation() {
ClusterDropStats ref1 = loadStatsManager.getClusterDropStats(CLUSTER_NAME1, EDS_SERVICE_NAME1);
ClusterDropStats ref2 = loadStatsManager.getClusterDropStats(CLUSTER_NAME1, EDS_SERVICE_NAME1);
ref1.recordDroppedRequest("lb");
ref2.recordDroppedRequest("throttle");
ref1.recordDroppedRequest();
ref2.recordDroppedRequest();
ClusterStats stats = Iterables.getOnlyElement(loadStatsManager.getClusterStatsReports(CLUSTER_NAME1));
assertThat(stats.droppedRequestsList()).hasSize(2);
assertThat(findDroppedRequestCount(stats.droppedRequestsList(), "lb")).isEqualTo(1L);
assertThat(findDroppedRequestCount(stats.droppedRequestsList(), "throttle")).isEqualTo(1L);
// 2 cagetorized + 2 uncategoized
assertThat(stats.totalDroppedRequests()).isEqualTo(4L);
}
use of io.grpc.xds.Stats.ClusterStats in project grpc-java by grpc.
the class LoadStatsManager2 method getClusterStatsReports.
/**
* Gets the traffic stats (drops and loads) as a list of {@link ClusterStats} recorded for the
* specified cluster since the previous call of this method or {@link
* #getAllClusterStatsReports}. A {@link ClusterStats} includes stats for a specific cluster with
* edsServiceName.
*/
synchronized List<ClusterStats> getClusterStatsReports(String cluster) {
if (!allDropStats.containsKey(cluster) && !allLoadStats.containsKey(cluster)) {
return Collections.emptyList();
}
Map<String, ReferenceCounted<ClusterDropStats>> clusterDropStats = allDropStats.get(cluster);
Map<String, Map<Locality, ReferenceCounted<ClusterLocalityStats>>> clusterLoadStats = allLoadStats.get(cluster);
Map<String, ClusterStats.Builder> statsReportBuilders = new HashMap<>();
// Populate drop stats.
if (clusterDropStats != null) {
Set<String> toDiscard = new HashSet<>();
for (String edsServiceName : clusterDropStats.keySet()) {
ClusterStats.Builder builder = ClusterStats.newBuilder().clusterName(cluster);
if (edsServiceName != null) {
builder.clusterServiceName(edsServiceName);
}
ReferenceCounted<ClusterDropStats> ref = clusterDropStats.get(edsServiceName);
if (ref.getReferenceCount() == 0) {
// stats object no longer needed after snapshot
toDiscard.add(edsServiceName);
}
ClusterDropStatsSnapshot dropStatsSnapshot = ref.get().snapshot();
long totalCategorizedDrops = 0L;
for (Map.Entry<String, Long> entry : dropStatsSnapshot.categorizedDrops.entrySet()) {
builder.addDroppedRequests(DroppedRequests.create(entry.getKey(), entry.getValue()));
totalCategorizedDrops += entry.getValue();
}
builder.totalDroppedRequests(totalCategorizedDrops + dropStatsSnapshot.uncategorizedDrops);
builder.loadReportIntervalNano(dropStatsSnapshot.durationNano);
statsReportBuilders.put(edsServiceName, builder);
}
clusterDropStats.keySet().removeAll(toDiscard);
}
// Populate load stats for all localities in the cluster.
if (clusterLoadStats != null) {
Set<String> toDiscard = new HashSet<>();
for (String edsServiceName : clusterLoadStats.keySet()) {
ClusterStats.Builder builder = statsReportBuilders.get(edsServiceName);
if (builder == null) {
builder = ClusterStats.newBuilder().clusterName(cluster);
if (edsServiceName != null) {
builder.clusterServiceName(edsServiceName);
}
statsReportBuilders.put(edsServiceName, builder);
}
Map<Locality, ReferenceCounted<ClusterLocalityStats>> localityStats = clusterLoadStats.get(edsServiceName);
Set<Locality> localitiesToDiscard = new HashSet<>();
for (Locality locality : localityStats.keySet()) {
ReferenceCounted<ClusterLocalityStats> ref = localityStats.get(locality);
ClusterLocalityStatsSnapshot snapshot = ref.get().snapshot();
// Only discard stats object after all in-flight calls under recording had finished.
if (ref.getReferenceCount() == 0 && snapshot.callsInProgress == 0) {
localitiesToDiscard.add(locality);
}
UpstreamLocalityStats upstreamLocalityStats = UpstreamLocalityStats.create(locality, snapshot.callsIssued, snapshot.callsSucceeded, snapshot.callsFailed, snapshot.callsInProgress);
builder.addUpstreamLocalityStats(upstreamLocalityStats);
// Use the max (drops/loads) recording interval as the overall interval for the
// cluster's stats. In general, they should be mostly identical.
builder.loadReportIntervalNano(Math.max(builder.loadReportIntervalNano(), snapshot.durationNano));
}
localityStats.keySet().removeAll(localitiesToDiscard);
if (localityStats.isEmpty()) {
toDiscard.add(edsServiceName);
}
}
clusterLoadStats.keySet().removeAll(toDiscard);
}
List<ClusterStats> res = new ArrayList<>();
for (ClusterStats.Builder builder : statsReportBuilders.values()) {
res.add(builder.build());
}
return Collections.unmodifiableList(res);
}
Aggregations