xds: equally weight endpoints within locality if endpoint-level weight unspecified (#8245)

Use a multiplier of 1 for endpoints with endpoint-level load balancing weight unspecified when computing weights for mixing-locality load balancing. Therefore, if a locality has endpoints without endpoint-level load balancing weight, they are weighted equally within the locality.
This commit is contained in:
Chengyuan Zhang 2021-06-09 12:04:17 -07:00 committed by GitHub
parent b7f3fddc76
commit d41094944c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 14 deletions

View File

@ -387,13 +387,17 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
for (LbEndpoint endpoint : localityLbInfo.endpoints()) { for (LbEndpoint endpoint : localityLbInfo.endpoints()) {
if (endpoint.isHealthy()) { if (endpoint.isHealthy()) {
discard = false; discard = false;
long weight = long weight = localityLbInfo.localityWeight();
(long) localityLbInfo.localityWeight() * endpoint.loadBalancingWeight(); if (endpoint.loadBalancingWeight() != 0) {
Attributes attr = endpoint.eag().getAttributes().toBuilder() weight *= endpoint.loadBalancingWeight();
.set(InternalXdsAttributes.ATTR_LOCALITY, locality) }
.set(InternalXdsAttributes.ATTR_SERVER_WEIGHT, weight).build(); Attributes attr =
EquivalentAddressGroup eag = endpoint.eag().getAttributes().toBuilder()
new EquivalentAddressGroup(endpoint.eag().getAddresses(), attr); .set(InternalXdsAttributes.ATTR_LOCALITY, locality)
.set(InternalXdsAttributes.ATTR_SERVER_WEIGHT, weight)
.build();
EquivalentAddressGroup eag = new EquivalentAddressGroup(
endpoint.eag().getAddresses(), attr);
eag = AddressFilter.setPathFilter( eag = AddressFilter.setPathFilter(
eag, Arrays.asList(priorityName, localityName(locality))); eag, Arrays.asList(priorityName, localityName(locality)));
addresses.add(eag); addresses.add(eag);

View File

@ -16,6 +16,8 @@
package io.grpc.xds; package io.grpc.xds;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -33,7 +35,7 @@ final class Endpoints {
// Endpoints to be load balanced. // Endpoints to be load balanced.
abstract ImmutableList<LbEndpoint> endpoints(); abstract ImmutableList<LbEndpoint> endpoints();
// Locality's weight for inter-locality load balancing. // Locality's weight for inter-locality load balancing. Guaranteed to be greater than 0.
abstract int localityWeight(); abstract int localityWeight();
// Locality's priority level. // Locality's priority level.
@ -41,6 +43,7 @@ final class Endpoints {
static LocalityLbEndpoints create(List<LbEndpoint> endpoints, int localityWeight, static LocalityLbEndpoints create(List<LbEndpoint> endpoints, int localityWeight,
int priority) { int priority) {
checkArgument(localityWeight > 0, "localityWeight must be greater than 0");
return new AutoValue_Endpoints_LocalityLbEndpoints( return new AutoValue_Endpoints_LocalityLbEndpoints(
ImmutableList.copyOf(endpoints), localityWeight, priority); ImmutableList.copyOf(endpoints), localityWeight, priority);
} }
@ -52,7 +55,7 @@ final class Endpoints {
// The endpoint address to be connected to. // The endpoint address to be connected to.
abstract EquivalentAddressGroup eag(); abstract EquivalentAddressGroup eag();
// Endpoint's wight for load balancing. // Endpoint's weight for load balancing. If unspecified, value of 0 is returned.
abstract int loadBalancingWeight(); abstract int loadBalancingWeight();
// Whether the endpoint is healthy. // Whether the endpoint is healthy.

View File

@ -217,29 +217,37 @@ public class ClusterResolverLoadBalancerTest {
// One priority with two localities of different weights. // One priority with two localities of different weights.
EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1");
EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2");
EquivalentAddressGroup endpoint3 = makeAddress("endpoint-addr-3");
LocalityLbEndpoints localityLbEndpoints1 = LocalityLbEndpoints localityLbEndpoints1 =
LocalityLbEndpoints.create( LocalityLbEndpoints.create(
Collections.singletonList( Arrays.asList(
LbEndpoint.create(endpoint1, 100 /* loadBalancingWeight */, true)), LbEndpoint.create(endpoint1, 0 /* loadBalancingWeight */, true),
LbEndpoint.create(endpoint2, 0 /* loadBalancingWeight */, true)),
10 /* localityWeight */, 1 /* priority */); 10 /* localityWeight */, 1 /* priority */);
LocalityLbEndpoints localityLbEndpoints2 = LocalityLbEndpoints localityLbEndpoints2 =
LocalityLbEndpoints.create( LocalityLbEndpoints.create(
Collections.singletonList( Collections.singletonList(
LbEndpoint.create(endpoint2, 60 /* loadBalancingWeight */, true)), LbEndpoint.create(endpoint3, 60 /* loadBalancingWeight */, true)),
50 /* localityWeight */, 1 /* priority */); 50 /* localityWeight */, 1 /* priority */);
xdsClient.deliverClusterLoadAssignment( xdsClient.deliverClusterLoadAssignment(
EDS_SERVICE_NAME1, EDS_SERVICE_NAME1,
ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2));
assertThat(childBalancers).hasSize(1); assertThat(childBalancers).hasSize(1);
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
assertThat(childBalancer.addresses).hasSize(2); assertThat(childBalancer.addresses).hasSize(3);
EquivalentAddressGroup addr1 = childBalancer.addresses.get(0); EquivalentAddressGroup addr1 = childBalancer.addresses.get(0);
EquivalentAddressGroup addr2 = childBalancer.addresses.get(1); EquivalentAddressGroup addr2 = childBalancer.addresses.get(1);
EquivalentAddressGroup addr3 = childBalancer.addresses.get(2);
// Endpoints in locality1 have no endpoint-level weight specified, so all endpoints within
// locality1 are equally weighted.
assertThat(addr1.getAddresses()).isEqualTo(endpoint1.getAddresses()); assertThat(addr1.getAddresses()).isEqualTo(endpoint1.getAddresses());
assertThat(addr1.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT)) assertThat(addr1.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT))
.isEqualTo(10 * 100); .isEqualTo(10);
assertThat(addr2.getAddresses()).isEqualTo(endpoint2.getAddresses()); assertThat(addr2.getAddresses()).isEqualTo(endpoint2.getAddresses());
assertThat(addr2.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT)) assertThat(addr2.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT))
.isEqualTo(10);
assertThat(addr3.getAddresses()).isEqualTo(endpoint3.getAddresses());
assertThat(addr3.getAttributes().get(InternalXdsAttributes.ATTR_SERVER_WEIGHT))
.isEqualTo(50 * 60); .isEqualTo(50 * 60);
assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME); assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME);
PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config; PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config;