A75: Implement the new LB policy topology for the non-aggregate cluster - #9234
A75: Implement the new LB policy topology for the non-aggregate cluster#9234mswierq wants to merge 13 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #9234 +/- ##
==========================================
+ Coverage 83.20% 83.25% +0.04%
==========================================
Files 423 423
Lines 35321 35208 -113
==========================================
- Hits 29389 29311 -78
+ Misses 4425 4402 -23
+ Partials 1507 1495 -12
🚀 New features to boost your workflow:
|
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the CDS balancer to support the gRFC A75 topology for single (non-aggregate) clusters, routing them through an outlier detection policy instead of a priority policy. The changes include updating the configuration builder to construct the new balancer tree (outlier_detection -> cluster_impl -> priority -> wrr_locality -> round_robin) and updating corresponding tests. The review feedback highlights several critical areas in the new code paths where missing configuration data (such as nil cluster configs, endpoint configs, or empty priorities) could lead to nil pointer dereferences or out-of-bounds panics, and suggests adding defensive checks to ensure robustness.
| parser, ok := builder.(balancer.ConfigParser) | ||
| if !ok { | ||
| return nil, nil, fmt.Errorf("xds: balancer builder for %v does not implement ConfigParser", name) | ||
| } |
There was a problem hiding this comment.
Since you have added the logic to retrieve the childConfigParser here, we can remove it from `Build()``.
There was a problem hiding this comment.
this has been removed as a result of using gracefulswitch.Balancer
There was a problem hiding this comment.
setting childConfigParser in Build has been removed
| newChildBalancer = func(name string, cc balancer.ClientConn, opts balancer.BuildOptions) (balancer.Balancer, balancer.ConfigParser, error) { | ||
| builder := balancer.Get(name) |
There was a problem hiding this comment.
Can we use gracefulswitch.Balancer here and make cdsBalancer.childLB of type *gracefulswitch.Balancer?
There was a problem hiding this comment.
newChildBalancer function and its output have been removed as gracefulswitch.Balancer and gracefulswitch.ParseConfig implementation already covers the same functionality
There was a problem hiding this comment.
I wanted to start a discussion on this before making any change and want to hear your thoughts on this.
Now based on my offline discussions with @easwars, We don't need to use gracefulSwitch here because it is very rare that the type of cluster get changed.
Could you please revert back the changes you made to use gracefulSwitch.
There was a problem hiding this comment.
I see, I have reverted it
| if len(b.priorities) == 0 { | ||
| return fmt.Errorf("no priorities configured for non-aggregate cluster %q", clusterName) | ||
| } |
There was a problem hiding this comment.
why do we need this check here?
There was a problem hiding this comment.
I think we can directly pass b.priorities instead of passing its first element in buildSingleClusterConfigJSON.
I also think handleClusterUpdate() will never set b.priorities to nil.
There was a problem hiding this comment.
reverted + getting the first element is inside ConfigJSON function
This reverts commit fbed93a.
…b-policy-tree-refactoring
| // management server sends two updates for the same leaf cluster resource. The | ||
| // test verifies that the load balancing configuration pushed to the priority LB | ||
| // policy contains the expected discovery mechanism corresponding to the leaf | ||
| // test verifies that the load balancing configuration pushed to the top-level LB |
There was a problem hiding this comment.
Wrap the comment in 80 column.
| // the priority LB policy contains the discovery mechanisms for both child | ||
| // clusters. The test then updates the root cluster resource requested by the | ||
| // cds LB policy to a leaf cluster of type EDS and verifies the load balancing | ||
| // configuration pushed to the priority LB policy contains a single discovery | ||
| // mechanism. | ||
| // configuration pushed to the outlier detection LB policy contains the leaf cluster config. |
There was a problem hiding this comment.
Same here, please wrap the comment in 80 column. Here and elsewhere.
| if isAggregate { | ||
| childCfgBytes, endpoints, err = buildAggregateClusterConfigJSON(b.priorities, &b.xdsLBPolicy) | ||
| } else { | ||
| childCfgBytes, endpoints, err = buildLeafClusterConfigJSON(b.priorities, &b.xdsLBPolicy) | ||
| } |
There was a problem hiding this comment.
I think the variable topLBName can be set here only instead of setting it in another if-else block.
There was a problem hiding this comment.
after reverting gracefulswitch this actually has to stay that way, because we need to check first if the top policy type has changed due to update (e.g. update from non-aggregate to aggregate cluster)
| select { | ||
| case <-exitIdleCh: | ||
| default: |
There was a problem hiding this comment.
Why do we need this here?
There was a problem hiding this comment.
This might be called more than once in test cases where balancers are being reconfigured, e.g. transition from non-aggregate to aggregate cluster (TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate).
However, those channels are not used in the mentioned aggregate test case. We may consider having these exitIdleCh and closeCh channels configurable and remove this default option. WDYT?
| select { | ||
| case <-closeCh: |
There was a problem hiding this comment.
Same here, Close() will not going to be called more that once for a balancer.
| func (s) TestBuildAggregateClusterConfigJSON(t *testing.T) { | ||
| testLRSServerConfig, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{ |
There was a problem hiding this comment.
You have added a similar test for leaf cluster TestBuildLeafClusterConfigJSON. I think we can merge both in a table-driven test.
There was a problem hiding this comment.
merged into a table-driven test case
| return retEndpoint | ||
| } | ||
|
|
||
| func (s) TestBuildLeafClusterConfigJSON(t *testing.T) { |
There was a problem hiding this comment.
Add a docstring about what the test is doing. Here and elsewhere.
…b-policy-tree-refactoring
This reverts commit 51e986e.
Implements A75 for the non-aggregate cluster.
This change implements the new LB policy topology for the non-aggregate clusters only, the aggregate cluster uses the legacy approach. Refactoring of the new topology for the aggregate cluster case will be delivered in a follow-up PR. This change does not break non-aggregate to aggregate (and vice versa) switch.
RELEASE NOTES: