-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Implementation of A68 random_subsetting LB policy. #8650
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
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: marek-szews <szews@google.com>
|
@marek-szews : Could you please get the tests to pass. Thanks. |
| SubsetSize uint64 `json:"subset_size,omitempty"` | ||
|
|
||
| ChildPolicy *iserviceconfig.BalancerConfig `json:"child_policy,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We generally use camelCase for the json annotations since the protobuf library uses that when marshalling protobuf messages to JSON. So, please change these to use camelCase. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I have changed the name of variable to lower case I've got:
--- FAIL: Test (0.00s)
--- FAIL: Test/ParseConfig (0.00s)
--- FAIL: Test/ParseConfig/happy-case-default (0.00s)
panic: cannot handle unexported field at {*randomsubsetting.LBConfig}.subsetSize:
"google.golang.org/grpc/balancer/randomsubsetting".LBConfig
consider using cmpopts.EquateComparable to compare comparable Go types [recovered]
panic: cannot handle unexported field at {*randomsubsetting.LBConfig}.subsetSize:
"google.golang.org/grpc/balancer/randomsubsetting".LBConfig
consider using cmpopts.EquateComparable to compare comparable Go types
| return b | ||
| } | ||
|
|
||
| // LBConfig is the config for the outlier detection balancer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment needs to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| } | ||
|
|
||
| // LBConfig is the config for the outlier detection balancer. | ||
| type LBConfig struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for this type to be exported. I don't see a reason here. So, if there is no reason, please unexport it. The fields can remain exported since you might want that for JSON marshal/unmarshal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we need to use this type in the test function.
| // Default top layer values. | ||
| SubsetSize: 10, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this default value specified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the previous proposal of config I have found somthing like this (PROP-423):
message RandomSubsettingLbConfig {
// subset_size indicates how many backends every client will be connected to.
// Default is 20.
google.protobuf.UInt32Value subset_size = 1;
But I saw in the most current version (PROTO-157) that this information has been removed. My suggestion is to set subsetSize to 2 by default, because 1 should suggest to use pick_first instead.
| } | ||
|
|
||
| // if someonw needs subsetSize == 1, he should use pick_first instead | ||
| if lbCfg.SubsetSize < 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gRFC only says the following:
// The value is required and must be greater than 0.
Is the condition that the size be at least 2 specified somewhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the discussion at line 86
| return addressesSet[i].hash < addressesSet[j].hash | ||
| }) | ||
|
|
||
| b.logger.Infof("resulting subset: %v", addressesSet[:b.cfg.SubsetSize]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please guard this log line with a verbosity check of 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
|
||
| // implements the subsetting algorithm, as described in A68: https://github.com/grpc/proposal/pull/423 | ||
| func (b *subsettingBalancer) prepareChildResolverState(s resolver.State) resolver.State { | ||
| addresses := s.Addresses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be using the Endpoints field in resolver.State for everything here (except for computing the hash where we use the first address inside of the endpoint).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| // Convert back to resolver.addresses | ||
| addressesSubset := make([]resolver.Address, b.cfg.SubsetSize) | ||
| for _, eh := range addressesSet[:b.cfg.SubsetSize] { | ||
| addressesSubset = append(addressesSubset, eh.addr) | ||
| } | ||
|
|
||
| return resolver.State{ | ||
| Addresses: addressesSubset, | ||
| ServiceConfig: s.ServiceConfig, | ||
| Attributes: s.Attributes, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of this should deal with endpoints and not addresses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| func (b *subsettingBalancer) ResolverError(err error) { | ||
| b.child.ResolverError(err) | ||
| } | ||
|
|
||
| func (b *subsettingBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { | ||
| b.child.UpdateSubConnState(sc, state) | ||
| } | ||
|
|
||
| func (b *subsettingBalancer) Close() { | ||
| b.child.Close() | ||
| } | ||
|
|
||
| func (b *subsettingBalancer) ExitIdle() { | ||
| b.child.ExitIdle() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we embed the gracefulswitch.Balancer in the subsettingBalancer, and thereby get rid of all these forwarding methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How we can do this ?
| ChildPolicy *iserviceconfig.BalancerConfig `json:"child_policy,omitempty"` | ||
| } | ||
|
|
||
| func (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to add unit tests for this method. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
This PR is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed. |
|
Hi @marek-szews - I think we're waiting on you to make some updates so we can continue the review. We can discuss Friday but I wanted to ping this in part to prevent the stale bot from closing it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rework done, tests passed
| SubsetSize uint64 `json:"subset_size,omitempty"` | ||
|
|
||
| ChildPolicy *iserviceconfig.BalancerConfig `json:"child_policy,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I have changed the name of variable to lower case I've got:
--- FAIL: Test (0.00s)
--- FAIL: Test/ParseConfig (0.00s)
--- FAIL: Test/ParseConfig/happy-case-default (0.00s)
panic: cannot handle unexported field at {*randomsubsetting.LBConfig}.subsetSize:
"google.golang.org/grpc/balancer/randomsubsetting".LBConfig
consider using cmpopts.EquateComparable to compare comparable Go types [recovered]
panic: cannot handle unexported field at {*randomsubsetting.LBConfig}.subsetSize:
"google.golang.org/grpc/balancer/randomsubsetting".LBConfig
consider using cmpopts.EquateComparable to compare comparable Go types
| // Default top layer values. | ||
| SubsetSize: 10, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the previous proposal of config I have found somthing like this (PROP-423):
message RandomSubsettingLbConfig {
// subset_size indicates how many backends every client will be connected to.
// Default is 20.
google.protobuf.UInt32Value subset_size = 1;
But I saw in the most current version (PROTO-157) that this information has been removed. My suggestion is to set subsetSize to 2 by default, because 1 should suggest to use pick_first instead.
| ChildPolicy *iserviceconfig.BalancerConfig `json:"child_policy,omitempty"` | ||
| } | ||
|
|
||
| func (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| } | ||
|
|
||
| if err := json.Unmarshal(s, lbCfg); err != nil { // Validates child config if present as well. | ||
| return nil, fmt.Errorf("subsetting: unable to unmarshal LBconfig: %s, error: %v", string(s), err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| SubsetSize: 10, | ||
| } | ||
|
|
||
| if err := json.Unmarshal(s, lbCfg); err != nil { // Validates child config if present as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
|
||
| // implements the subsetting algorithm, as described in A68: https://github.com/grpc/proposal/pull/423 | ||
| func (b *subsettingBalancer) prepareChildResolverState(s resolver.State) resolver.State { | ||
| addresses := s.Addresses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| addressesSet := make([]AddressWithHash, backendCount) | ||
| // calculate hash for each endpoint | ||
| for i, endpoint := range addresses { | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| return addressesSet[i].hash < addressesSet[j].hash | ||
| }) | ||
|
|
||
| b.logger.Infof("resulting subset: %v", addressesSet[:b.cfg.SubsetSize]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| // Convert back to resolver.addresses | ||
| addressesSubset := make([]resolver.Address, b.cfg.SubsetSize) | ||
| for _, eh := range addressesSet[:b.cfg.SubsetSize] { | ||
| addressesSubset = append(addressesSubset, eh.addr) | ||
| } | ||
|
|
||
| return resolver.State{ | ||
| Addresses: addressesSubset, | ||
| ServiceConfig: s.ServiceConfig, | ||
| Attributes: s.Attributes, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| func (b *subsettingBalancer) ResolverError(err error) { | ||
| b.child.ResolverError(err) | ||
| } | ||
|
|
||
| func (b *subsettingBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { | ||
| b.child.UpdateSubConnState(sc, state) | ||
| } | ||
|
|
||
| func (b *subsettingBalancer) Close() { | ||
| b.child.Close() | ||
| } | ||
|
|
||
| func (b *subsettingBalancer) ExitIdle() { | ||
| b.child.ExitIdle() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How we can do this ?
Introduce a new LB policy,
random_subsetting. This policy selects a subset of addresses and passes them to the child LB policy to correct the resulting server-side load balancing.