-
Notifications
You must be signed in to change notification settings - Fork 3.9k
A75 Aggregate cluster fixes #12186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A75 Aggregate cluster fixes #12186
Changes from all commits
ed5072e
c8be933
63997fd
5140beb
029db63
f472436
459208c
6cddc61
f038f4c
ad9b1b3
d92902d
60fae37
6f0a920
d816b8e
c8eca59
4b92066
3867cc7
c4bfaa5
400b776
fa21404
084c51c
f2bfa63
7abbc4a
7c16de8
f6afb63
e2a7382
ecb6b03
8c1199d
24910d8
6c75018
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,10 +18,10 @@ | |
|
||
import static com.google.common.base.Preconditions.checkNotNull; | ||
import static io.grpc.ConnectivityState.TRANSIENT_FAILURE; | ||
import static io.grpc.xds.XdsLbPolicies.CDS_POLICY_NAME; | ||
import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; | ||
import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; | ||
|
||
import com.google.common.annotations.VisibleForTesting; | ||
import com.google.common.collect.ImmutableList; | ||
import com.google.errorprone.annotations.CheckReturnValue; | ||
import io.grpc.InternalLogId; | ||
import io.grpc.LoadBalancer; | ||
|
@@ -33,6 +33,7 @@ | |
import io.grpc.xds.CdsLoadBalancerProvider.CdsConfig; | ||
import io.grpc.xds.ClusterResolverLoadBalancerProvider.ClusterResolverConfig; | ||
import io.grpc.xds.ClusterResolverLoadBalancerProvider.ClusterResolverConfig.DiscoveryMechanism; | ||
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig; | ||
import io.grpc.xds.XdsClusterResource.CdsUpdate; | ||
import io.grpc.xds.XdsClusterResource.CdsUpdate.ClusterType; | ||
import io.grpc.xds.XdsConfig.Subscription; | ||
|
@@ -41,10 +42,11 @@ | |
import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; | ||
import io.grpc.xds.client.XdsLogger; | ||
import io.grpc.xds.client.XdsLogger.XdsLogLevel; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
/** | ||
* Load balancer for cds_experimental LB policy. One instance per top-level cluster. | ||
|
@@ -55,19 +57,15 @@ final class CdsLoadBalancer2 extends LoadBalancer { | |
private final XdsLogger logger; | ||
private final Helper helper; | ||
private final LoadBalancerRegistry lbRegistry; | ||
private GracefulSwitchLoadBalancer delegate; | ||
// Following fields are effectively final. | ||
private String clusterName; | ||
private Subscription clusterSubscription; | ||
private LoadBalancer childLb; | ||
|
||
CdsLoadBalancer2(Helper helper) { | ||
this(helper, LoadBalancerRegistry.getDefaultRegistry()); | ||
} | ||
|
||
@VisibleForTesting | ||
CdsLoadBalancer2(Helper helper, LoadBalancerRegistry lbRegistry) { | ||
this.helper = checkNotNull(helper, "helper"); | ||
this.lbRegistry = checkNotNull(lbRegistry, "lbRegistry"); | ||
this.delegate = new GracefulSwitchLoadBalancer(helper); | ||
logger = XdsLogger.withLogId(InternalLogId.allocate("cds-lb", helper.getAuthority())); | ||
logger.log(XdsLogLevel.INFO, "Created"); | ||
} | ||
|
@@ -91,7 +89,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { | |
if (clusterSubscription == null) { | ||
// Should be impossible, because XdsDependencyManager wouldn't have generated this | ||
return fail(Status.INTERNAL.withDescription( | ||
errorPrefix() + "Unable to find non-dynamic root cluster")); | ||
errorPrefix() + "Unable to find non-dynamic cluster")); | ||
} | ||
// The dynamic cluster must not have loaded yet | ||
return Status.OK; | ||
|
@@ -100,42 +98,25 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { | |
return fail(clusterConfigOr.getStatus()); | ||
} | ||
XdsClusterConfig clusterConfig = clusterConfigOr.getValue(); | ||
List<String> leafNames; | ||
if (clusterConfig.getChildren() instanceof AggregateConfig) { | ||
leafNames = ((AggregateConfig) clusterConfig.getChildren()).getLeafNames(); | ||
} else if (clusterConfig.getChildren() instanceof EndpointConfig) { | ||
leafNames = ImmutableList.of(clusterName); | ||
} else { | ||
return fail(Status.INTERNAL.withDescription( | ||
errorPrefix() + "Unexpected cluster children type: " | ||
+ clusterConfig.getChildren().getClass())); | ||
} | ||
if (leafNames.isEmpty()) { | ||
// Should be impossible, because XdsClusterResource validated this | ||
return fail(Status.UNAVAILABLE.withDescription( | ||
errorPrefix() + "Zero leaf clusters for root cluster " + clusterName)); | ||
} | ||
|
||
Status noneFoundError = Status.INTERNAL | ||
.withDescription(errorPrefix() + "No leaves and no error; this is a bug"); | ||
List<DiscoveryMechanism> instances = new ArrayList<>(); | ||
for (String leafName : leafNames) { | ||
StatusOr<XdsClusterConfig> leafConfigOr = xdsConfig.getClusters().get(leafName); | ||
if (!leafConfigOr.hasValue()) { | ||
noneFoundError = leafConfigOr.getStatus(); | ||
continue; | ||
} | ||
if (!(leafConfigOr.getValue().getChildren() instanceof EndpointConfig)) { | ||
noneFoundError = Status.INTERNAL.withDescription( | ||
errorPrefix() + "Unexpected child " + leafName + " cluster children type: " | ||
+ leafConfigOr.getValue().getChildren().getClass()); | ||
continue; | ||
NameResolver.ConfigOrError configOrError; | ||
Object gracefulConfig; | ||
if (clusterConfig.getChildren() instanceof EndpointConfig) { | ||
// The LB policy config is provided in service_config.proto/JSON format. | ||
configOrError = | ||
GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig( | ||
Arrays.asList(clusterConfig.getClusterResource().lbPolicyConfig()), | ||
lbRegistry); | ||
if (configOrError.getError() != null) { | ||
// Should be impossible, because XdsClusterResource validated this | ||
return fail(Status.INTERNAL.withDescription( | ||
errorPrefix() + "Unable to parse the LB config: " + configOrError.getError())); | ||
} | ||
CdsUpdate result = leafConfigOr.getValue().getClusterResource(); | ||
CdsUpdate result = clusterConfig.getClusterResource(); | ||
DiscoveryMechanism instance; | ||
if (result.clusterType() == ClusterType.EDS) { | ||
instance = DiscoveryMechanism.forEds( | ||
leafName, | ||
clusterName, | ||
result.edsServiceName(), | ||
result.lrsServerInfo(), | ||
result.maxConcurrentRequests(), | ||
|
@@ -144,45 +125,49 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { | |
result.outlierDetection()); | ||
} else { | ||
instance = DiscoveryMechanism.forLogicalDns( | ||
leafName, | ||
clusterName, | ||
result.dnsHostName(), | ||
result.lrsServerInfo(), | ||
result.maxConcurrentRequests(), | ||
result.upstreamTlsContext(), | ||
result.filterMetadata()); | ||
} | ||
instances.add(instance); | ||
} | ||
if (instances.isEmpty()) { | ||
return fail(noneFoundError); | ||
} | ||
|
||
// The LB policy config is provided in service_config.proto/JSON format. | ||
NameResolver.ConfigOrError configOrError = | ||
GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig( | ||
Arrays.asList(clusterConfig.getClusterResource().lbPolicyConfig()), lbRegistry); | ||
if (configOrError.getError() != null) { | ||
// Should be impossible, because XdsClusterResource validated this | ||
gracefulConfig = GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( | ||
lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME), | ||
new ClusterResolverConfig( | ||
instance, | ||
configOrError.getConfig(), | ||
clusterConfig.getClusterResource().isHttp11ProxyAvailable())); | ||
} else if (clusterConfig.getChildren() instanceof AggregateConfig) { | ||
Map<String, PriorityChildConfig> priorityChildConfigs = new HashMap<>(); | ||
List<String> leafClusters = ((AggregateConfig) clusterConfig.getChildren()).getLeafNames(); | ||
for (String childCluster: leafClusters) { | ||
priorityChildConfigs.put(childCluster, | ||
new PriorityChildConfig( | ||
GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( | ||
lbRegistry.getProvider(CDS_POLICY_NAME), | ||
new CdsConfig(childCluster)), | ||
false)); | ||
} | ||
gracefulConfig = GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( | ||
lbRegistry.getProvider(PRIORITY_POLICY_NAME), | ||
new PriorityLoadBalancerProvider.PriorityLbConfig( | ||
Collections.unmodifiableMap(priorityChildConfigs), leafClusters)); | ||
} else { | ||
return fail(Status.INTERNAL.withDescription( | ||
errorPrefix() + "Unable to parse the LB config: " + configOrError.getError())); | ||
errorPrefix() + "Unexpected cluster children type: " | ||
+ clusterConfig.getChildren().getClass())); | ||
} | ||
|
||
ClusterResolverConfig config = new ClusterResolverConfig( | ||
Collections.unmodifiableList(instances), | ||
configOrError.getConfig(), | ||
clusterConfig.getClusterResource().isHttp11ProxyAvailable()); | ||
if (childLb == null) { | ||
childLb = lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME).newLoadBalancer(helper); | ||
} | ||
return childLb.acceptResolvedAddresses( | ||
resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(config).build()); | ||
return delegate.acceptResolvedAddresses( | ||
resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(gracefulConfig).build()); | ||
} | ||
|
||
@Override | ||
public void handleNameResolutionError(Status error) { | ||
logger.log(XdsLogLevel.WARNING, "Received name resolution error: {0}", error); | ||
if (childLb != null) { | ||
childLb.handleNameResolutionError(error); | ||
if (delegate != null) { | ||
delegate.handleNameResolutionError(error); | ||
} else { | ||
helper.updateBalancingState( | ||
TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(error))); | ||
|
@@ -192,10 +177,8 @@ public void handleNameResolutionError(Status error) { | |
@Override | ||
public void shutdown() { | ||
logger.log(XdsLogLevel.INFO, "Shutdown"); | ||
if (childLb != null) { | ||
childLb.shutdown(); | ||
childLb = null; | ||
} | ||
delegate.shutdown(); | ||
delegate = new GracefulSwitchLoadBalancer(helper); | ||
if (clusterSubscription != null) { | ||
clusterSubscription.close(); | ||
clusterSubscription = null; | ||
|
@@ -204,10 +187,7 @@ public void shutdown() { | |
|
||
@CheckReturnValue // don't forget to return up the stack after the fail call | ||
private Status fail(Status error) { | ||
if (childLb != null) { | ||
childLb.shutdown(); | ||
childLb = null; | ||
} | ||
delegate.shutdown(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this will break the child, as once it is shut down it shouldn't be called further. And it won't be re-created when things become good again. If we shut this down, we need to replace delegate with a new instance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. I see ClusterResolverLoadBalancerPolicy also uses a non-null delegate of Graceful switch LB but doesn't reinstantiate it in its shutdown. Shouldn't we do this change there too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The delegate (GracefulSwitchLoadBalancer) even if it not reinstantiated in the CdsLoadbalancer2 shutdown, if CdsLoadbalancer2 acceptResolvedAddresses is called again after shutdown, the delegate's acceptResolvedAddresses works just fine. |
||
helper.updateBalancingState( | ||
TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(error))); | ||
return Status.OK; // XdsNameResolver isn't a polling NR, so this value doesn't matter | ||
|
Uh oh!
There was an error while loading. Please reload this page.