Skip to content
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

ringhash: allow setting request hash key explicitly #7170

Closed
wants to merge 5 commits into from

Conversation

atollena
Copy link
Collaborator

@atollena atollena commented Apr 26, 2024

Implement part 1 of A76: the ability to set the request hash key, to extract the hash from a header. This allows using ring hash without xDS.

RELEASE NOTES:

  • ringhash: Allow setting request hash key explicitly using request_metadata_key load balancing config field (gRFC A76).

Implement part 1 of A76: the ability to set the request hash key, to extract the
hash from a header. This allows using ring hash without xDS.
@atollena
Copy link
Collaborator Author

Ready to review, will wait for A76 to be merged before merging this.

@atollena atollena added the Type: Feature New features or improvements in behavior label Apr 26, 2024
@atollena atollena added this to the 1.64 Release milestone Apr 26, 2024
@arvindbr8
Copy link
Member

Sure, will take a look.

@ginayeh ginayeh requested a review from arvindbr8 April 30, 2024 16:10
@atollena atollena marked this pull request as ready for review April 30, 2024 16:14
Copy link
Member

@arvindbr8 arvindbr8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

took a first pass at it, and had a few comments/questions. Please take a look @atollena

@@ -66,5 +69,10 @@ func parseConfig(c json.RawMessage) (*LBConfig, error) {
if cfg.MaxRingSize > envconfig.RingHashCap {
cfg.MaxRingSize = envconfig.RingHashCap
}
if cfg.RequestMetadataKey != "" {
if err := metadata.ValidatePair(cfg.RequestMetadataKey, ""); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per A76:

If the request_hash_header refers to a binary header (suffixed with -bin), the configuration is also rejected.

Something's off here, ValidatePair currently does not err for keys suffixed with -bin. Should we add that additional validation here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: Also, for readability could we maybe split ValidatePair to md.ValidateKey and md.ValidateValue methods and call just ValidateKey from here so that we dont pass in a "" here?

},
{
name: "invalid request metadata keys",
js: `{"request_metadata_key": "!invalid"}`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a case rejecting key referencing a binary header please

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

// nextReadySubConn returns the first entry after e that has its
// subconn in READY state. If no such entry is found, a PickResult with a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems incomplete. Did you mean?

Suggested change
// subconn in READY state. If no such entry is found, a PickResult with a
// subconn in READY state. If no such entry is found, returns nil.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, fixed.

Comment on lines 185 to 191
for i := range p.ring.items {
e := p.ring.items[(e.idx+i)%len(p.ring.items)]
if e.sc.state == connectivity.Ready {
return e.sc.sc
}
}
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we follow a similar pattern and do something like that:

Suggested change
for i := range p.ring.items {
e := p.ring.items[(e.idx+i)%len(p.ring.items)]
if e.sc.state == connectivity.Ready {
return e.sc.sc
}
}
return nil
for next := p.ring.next(e); next != e; next = ring.next(next) {
if next.sc.state == connectivity.Ready {
return next.sc.sc
}
}
return nil

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that works. I changed the code following your suggestion.

Comment on lines 53 to 56
// handleRICSResult is the return type of handleRICS. It's needed to wrap the
// returned error from Pick() in a struct. With this, if the return values are
// `balancer.PickResult, error, bool`, linter complains because error is not the
// last return value.
// returned error from Pick() in a struct and whether we triggered a connection
// attempt. Without this, the return values would be `balancer.PickResult, bool, error, bool`,
// and linter would complain because error is not the last return value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line wrap please :)

Suggested change
// handleRICSResult is the return type of handleRICS. It's needed to wrap the
// returned error from Pick() in a struct. With this, if the return values are
// `balancer.PickResult, error, bool`, linter complains because error is not the
// last return value.
// returned error from Pick() in a struct and whether we triggered a connection
// attempt. Without this, the return values would be `balancer.PickResult, bool, error, bool`,
// and linter would complain because error is not the last return value.
// handleRICSResult is the return type of handleRICS. It's needed to wrap the
// returned error from Pick() in a struct and whether we triggered a connection
// attempt. Without this, the return values would be `balancer.PickResult, bool,
// error, bool`, and linter would complain because error is not the last return
// value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -84,23 +93,45 @@ func (p *picker) handleRICS(e *ringEntry) (handleRICSResult, bool) {
}

func (p *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
e := p.ring.pick(getRequestHash(info.Ctx))
h, usingRandomHash := getRequestHash(info.Ctx, p.requestHashKey)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the name usesRandomHash

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if getRequestHash is made a method with the pointer receiver, then you could actually merge the logic to assign h = p.randunit64 inside getRequestHash? wdyt?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the name usesRandomHash

I took your suggestion, but I was trying to follow Mark's suggested wording from the gRFC. I don't think there's ambiguity so I'm fine either way.

Also if getRequestHash is made a method with the pointer receiver, then you could actually merge the logic to assign h = p.randunit64 inside getRequestHash? wdyt?

I also took this suggestion. I removed the "ForTesting" suffix from GetXDSRequestHash, since it's now used inside picker.getRequestHash. It doesn't seem like a big deal, since all those APIs are within xds/internal.

Copy link

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.

@atollena
Copy link
Collaborator Author

You can hold on reviewing while I investigate making pick first the leaf policy for ring hash, as suggested in grpc/proposal#412 (comment).

@atollena atollena closed this May 28, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Type: Feature New features or improvements in behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants