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

Open
wants to merge 3 commits into
base: master
Choose a base branch
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

}

// 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.

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

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.

@@ -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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Requires Reporter Clarification Type: Feature New features or improvements in behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants