Skip to content

ringhash: implement gRFC A76 #8159

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

Merged
merged 12 commits into from
Apr 8, 2025
Merged

ringhash: implement gRFC A76 #8159

merged 12 commits into from
Apr 8, 2025

Conversation

atollena
Copy link
Collaborator

@atollena atollena commented Mar 11, 2025

Fixes #8147, #7990.

  • Add the ability to set the request hash key, to extract the hash from a header. This allows using ring hash without xDS.

  • Add the ability to specify the location of endpoints on the ring, and a default implementation based on EDS metadata that matches Envoy behavior.

See https://github.com/grpc/proposal/blob/master/A76-ring-hash-improvements.md for details.

RELEASE NOTES:

  • ringhash: implement gRFC A76.

@atollena atollena requested a review from arjan-bal March 11, 2025 09:27
@atollena atollena added P1 Type: Feature New features or improvements in behavior Area: xDS Includes everything xDS related, including LB policies used with xDS. Area: Resolvers/Balancers Includes LB policy & NR APIs, resolver/balancer/picker wrappers, LB policy impls and utilities. labels Mar 11, 2025
@atollena atollena added this to the 1.72 Release milestone Mar 11, 2025
Copy link

codecov bot commented Mar 11, 2025

Codecov Report

Attention: Patch coverage is 97.45223% with 4 lines in your changes missing coverage. Please review.

Project coverage is 81.97%. Comparing base (a51009d) to head (8816ae5).
Report is 13 commits behind head on master.

Files with missing lines Patch % Lines
internal/testutils/xds/e2e/clientresources.go 75.00% 1 Missing and 1 partial ⚠️
xds/internal/balancer/ringhash/picker.go 96.42% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8159      +/-   ##
==========================================
+ Coverage   81.91%   81.97%   +0.06%     
==========================================
  Files         410      412       +2     
  Lines       40216    40498     +282     
==========================================
+ Hits        32942    33198     +256     
- Misses       5894     5912      +18     
- Partials     1380     1388       +8     
Files with missing lines Coverage Δ
internal/envconfig/envconfig.go 100.00% <ø> (ø)
internal/metadata/metadata.go 82.08% <100.00%> (+1.44%) ⬆️
internal/testutils/envconfig.go 100.00% <100.00%> (ø)
resolver/ringhash/attr.go 100.00% <100.00%> (ø)
...internal/balancer/clusterresolver/configbuilder.go 91.22% <100.00%> (+0.05%) ⬆️
xds/internal/balancer/ringhash/config.go 92.10% <100.00%> (+3.21%) ⬆️
xds/internal/balancer/ringhash/ring.go 100.00% <100.00%> (ø)
xds/internal/balancer/ringhash/ringhash.go 94.22% <100.00%> (+0.35%) ⬆️
xds/internal/balancer/ringhash/util.go 100.00% <100.00%> (ø)
xds/internal/resolver/serviceconfig.go 85.71% <100.00%> (ø)
... and 3 more

... and 37 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Add the ability to set the request hash header. This allows using ring hash
  without xDS.

- Add the ability to specify the location of endpoints on the ring, and a
  default implementation based on EDS metadata that matches Envoy behavior.

See https://github.com/grpc/proposal/blob/master/A76-ring-hash-improvements.md
for details.

Release Notes:

- ringhash: implement gRFC A76.
Copy link
Contributor

@danielzhaotongliu danielzhaotongliu left a comment

Choose a reason for hiding this comment

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

Perhaps @easwars or @dfawley should also take a pass at the review if they have time.

@@ -94,6 +98,27 @@ func (s) TestParseConfig(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "request metadata key set",
Copy link
Contributor

Choose a reason for hiding this comment

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

there should be a test case for when there are multiple header values from the gRFC A76

If the header contains multiple values, then values are joined with a comma , character before hashing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The behavior joining headers with a coma is for header values. Using multiple headers is not supported. I added a picker test case for this, and took the opportunity to make the picker test a bit more robust by distributing endpoints on the ring, and removing unnecessary setting of the request hash in existing tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have a test for the case where the env var is set to false and the JSON config contains a value for the request_hash_header and we check that the parsed internal representation does not have the corresponding field set?

Copy link
Contributor

Choose a reason for hiding this comment

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

The behavior joining headers with a coma is for header values. Using multiple headers is not supported. I added a picker test case for this

Ack. Thanks for adding this test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

can we have a test for the case where the env var is set to false and the JSON config contains a value for the request_hash_header and we check that the parsed internal representation does not have the corresponding field set?

Added.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Since we have multiple env vars in the context of ring_hash config parsing, could we please rename the field something more specific. Maybe requestHeaderEnvVar?

@atollena
Copy link
Collaborator Author

Thanks for the review @danielzhaotongliu . I took your feedback into consideration.

There is a failing test which I think may be flaky? (it's Test/End2End in the advancedtls module which seems unrelated).
Also the code coverage report didn't run because of a missing token, not sure if that's expected.

@arjan-bal arjan-bal self-assigned this Mar 25, 2025
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
// later release.
func SetEndpointHashKey(ep resolver.Endpoint, hashKey string) resolver.Endpoint {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: We can remove Endpoint from the function name since the function argument type conveys this information.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: s/hash key attribute of addr/hash key attribute of endpoint/

@arjan-bal arjan-bal assigned atollena and unassigned arjan-bal Mar 25, 2025
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
// later release.
func SetEndpointHashKey(ep resolver.Endpoint, hashKey string) resolver.Endpoint {
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

@@ -94,6 +98,27 @@ func (s) TestParseConfig(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "request metadata key set",
Copy link
Contributor

Choose a reason for hiding this comment

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

The behavior joining headers with a coma is for header values. Using multiple headers is not supported. I added a picker test case for this

Ack. Thanks for adding this test.

@atollena
Copy link
Collaborator Author

I also fixed the configuration to use camelCase instead of snake_case: requestHashHeader instead of request_hash_header, since this is the convention for service config (it's somewhat hidden in the spec since it relies on protojson conventions).

@arjan-bal
Copy link
Contributor

There is a race in a ringhash test caught by CI: https://github.com/grpc/grpc-go/actions/runs/14220675758/job/39847655816?pr=8159

@atollena
Copy link
Collaborator Author

atollena commented Apr 3, 2025

There is a race in a ringhash test caught by CI: https://github.com/grpc/grpc-go/actions/runs/14220675758/job/39847655816?pr=8159

Yep, that was just the err variable local to the test. Fixed in the latest commit.

@atollena
Copy link
Collaborator Author

atollena commented Apr 3, 2025

I also opened grpc/proposal#489 to clarify some of the behaviors I discovered during the implementation. It also answers the concern from @arjan-bal regarding duplicate hash keys.

@atollena atollena assigned easwars and arjan-bal and unassigned atollena Apr 4, 2025
Copy link
Contributor

@arjan-bal arjan-bal left a comment

Choose a reason for hiding this comment

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

LGTM!

@arjan-bal arjan-bal removed their assignment Apr 4, 2025
Copy link
Contributor

@danielzhaotongliu danielzhaotongliu left a comment

Choose a reason for hiding this comment

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

LGTM!

@easwars easwars assigned atollena and unassigned easwars Apr 7, 2025
@arjan-bal arjan-bal merged commit 25c7509 into grpc:master Apr 8, 2025
14 of 15 checks passed
yousukseung added a commit to yousukseung/grpc-go that referenced this pull request Apr 11, 2025
With gRFC A76 (grpc#8159), when requestHashHeader is specified from the
service config it fails the validation since MD keys with uppercase
letters are normalized to lowercase. We should normalize the parsed
value before validation.
yousukseung added a commit to yousukseung/grpc-go that referenced this pull request Apr 11, 2025
With gRFC A76 (grpc#8159), when requestHashHeader is specified from the
service config it fails the validation since MD keys with uppercase
letters are normalized to lowercase. We should normalize the parsed
value before validation.
yousukseung added a commit to yousukseung/grpc-go that referenced this pull request Apr 11, 2025
With gRFC A76 (grpc#8159), when requestHashHeader is specified from the
service config it fails the validation since MD keys with uppercase
letters are normalized to lowercase. We should normalize the parsed
value before validation.
purnesh42H pushed a commit to purnesh42H/grpc-go that referenced this pull request Apr 13, 2025
purnesh42H pushed a commit to purnesh42H/grpc-go that referenced this pull request Apr 16, 2025
purnesh42H added a commit that referenced this pull request Apr 16, 2025
janardhanvissa pushed a commit to janardhanvissa/grpc-go that referenced this pull request Apr 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Resolvers/Balancers Includes LB policy & NR APIs, resolver/balancer/picker wrappers, LB policy impls and utilities. Area: xDS Includes everything xDS related, including LB policies used with xDS. P1 Type: Feature New features or improvements in behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement A76: Improvements to the Ring Hash LB Policy
6 participants