-
Notifications
You must be signed in to change notification settings - Fork 10.1k
feat(client/v3/naming): add Attributes into Endpoint and deprecate Metadata #19785
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: main
Are you sure you want to change the base?
feat(client/v3/naming): add Attributes into Endpoint and deprecate Metadata #19785
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: amosehiguese The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Hi @amosehiguese. Thanks for your PR. I'm waiting for a etcd-io member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
r.cc.UpdateState(gresolver.State{Endpoints: eps}) | ||
} | ||
} | ||
} | ||
|
||
func convertToGRPCEndpoint(ups map[string]*endpoints.Update) []gresolver.Endpoint { | ||
func convertToGRPCEndpoint(lg *zap.Logger, ups map[string]*endpoints.Update) []gresolver.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.
suggest not to change the signature of the function. We don't know how users use the resovler, it may generate huge number of warning message.
func convertToGRPCEndpoint(lg *zap.Logger, ups map[string]*endpoints.Update) []gresolver.Endpoint { | |
func convertToGRPCEndpoint(ups map[string]*endpoints.Update) []gresolver.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.
I was thinking since it is a private function and only called within the watch function(in the entire etcd repo), it wouldn't have much impact.
That said, do i revert or leave it as is?
I could take another approach though
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 revert this change.
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.
usually it isn't a good pattern to print log in a lower level or utility package
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.
I will revert then. Thank you for the feedback
please squash the commits. We also need to update the doc https://etcd.io/docs/v3.5/dev-guide/grpc_naming/
|
Alright. I'll do just that. |
0c64765
to
cbf86a8
Compare
let's update this first together with this PR.
we will discuss & resolve this separately. |
/ok-to-test |
Metadata: up.Endpoint.Metadata, | ||
Addr: up.Endpoint.Addr, | ||
Metadata: up.Endpoint.Metadata, | ||
Attributes: up.Endpoint.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.
Probably eventually we might want to use Endpoint.Attributes instead of Address.Attributes, as we only care about the LB policy?
Currently we assume each endpoint has only one address, but actually it may contain multiple addresses (we won't change the behavior for now).
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.
Yeah, I saw it and then realised that the attributes field in the Endpoint was specific to LB-Policy which is the usecase for etcd and wondered why that wasn't used instead. But I have clarity on that now. 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.
Probably eventually we might want to use Endpoint.Attributes instead of Address.Attributes, as we only care about the LB policy?
It seems that this comment hasn't been resolved yet.
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'll have to wait on @dfawley, I guess
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 attributes on the address are passed to our code that creates and manages the connection to that address. This means if there are two Addresses
between name resolver updates with the same IP address but non-equal attributes, we will consider them different and reconnect.
The attributes on the endpoint are for anything else you might want to do. gRPC won't look at your attributes.
One important thing that is still not clear to me: what is your use case for attributes? Why are you adding them into gRPC endpoints/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.
One important thing that is still not clear to me: what is your use case for attributes? Why are you adding them into gRPC endpoints/addresses?
This is a good question, which I am not 100% sure either. But I believe the concept should be tightly coupled with gprc-go.
In the first place, we (previous maintainer) added Metadata (see below), which was passed to grpc-go's Address.Metadata. Based on the comment, it's used for load balancing decision.
etcd/client/v3/naming/endpoints/endpoints.go
Lines 32 to 35 in f5dbde1
// Metadata is the information associated with Addr, which may be used | |
// to make load balancing decision. | |
// Since etcd 3.1 | |
Metadata any |
This means if there are two
Addresses
between name resolver updates with the same IP address but non-equal attributes, we will consider them different and reconnect.
It seems the only usage of the Address.Attribute is to differentiate two addresses with the same IP address? I originally thought grpc-go would transparently pass through any data users attach—Attributes—to the server.
Actually based on current implementation, each endpoint has only one address inside.
The attributes on the endpoint are for anything else you might want to do. gRPC won't look at your attributes.
In that case, then I don't think we should use it if users do not use it either. Would grpc-go transparently pass through the endpoint Attributes—to the server?
Codecov ReportAttention: Patch coverage is
Additional details and impacted files
... and 16 files with indirect coverage changes @@ Coverage Diff @@
## main #19785 +/- ##
=======================================
Coverage 68.81% 68.81%
=======================================
Files 421 421
Lines 35863 35894 +31
=======================================
+ Hits 24678 24701 +23
- Misses 9754 9764 +10
+ Partials 1431 1429 -2 Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
You also need to persist the new added attributes (line 41 in internal/update.go), and read it back in List, etcd/client/v3/naming/endpoints/endpoints_impl.go Lines 175 to 192 in 8f933a5
|
Alright.
I'm on standby.
I will hold off on this then |
You might also need to update grpcproxy etcd/server/proxy/grpcproxy/register.go Line 75 in 8f933a5
|
Got it. |
Pretty much adjust every other usage of the endpoint struct to account for the new Attributes field. Will do that. |
cbf86a8
to
da7ba13
Compare
Two files may also need adjustments but I thought to run it by you first. 👉 endpoints_test.go [integration tests]
👉 cluster.go [grpc-proxy] etcd/server/proxy/grpcproxy/cluster.go Line 146 in 8f933a5
What would you have me do to these files? |
I think
|
Alright then. |
I just mark this as a priority/important-soon task. As mentioned above #19785 (comment), I think we need to backport this PR to release-3.6 and release-3.5, of course we will evaluate the impact. The goal is to get it included in 3.6.0, so that we can remove it in 3.7; otherwise, we will have to completely get rid of the deprecated Metadata field in 3.8 (~6 years later based on current cadence) |
also cc grpc-go tech-lead @dfawley, thx for all the help so far. |
@ahrtr ...and those tests take quite a bit of time to run |
I will be done with this from my end once I'm able to resolve whether or not flaky tests are expected in the e2e suite |
You need to ensure the test failures are not caused by your changes. |
I think I’ll have to run it against the main branch a couple of times to be sure. |
What do you reckon I do? push? cc: @ahrtr |
Windows is only tier 3 support, please try to test it on a linux platform.
Pushing to your dev branch won't break anything. Please review your PR yourself first to ensure it's the best you can deliver. |
Oh, I am actually working on a linux machine running on Azure cloud. This is just my backup pc, so I am forced to doing everything on the cloud.
I definitely will. Thanks for the feedback |
Just a bit of clarification in your docs. This line to be precise. Is this meant to be, "Is it impossible..." or "It is impossible"? cc: @ahrtr |
da7ba13
to
524789c
Compare
Attempting to do this would break these test cases. 👇
👇
Mostly because of the design decision by grpc on the Attributes type to make it impossible to unmarshal attributes from a JSON representation cc: @ahrtr |
// Attributes contains arbitrary data about this address intended for | ||
// consumption by the SubConn. | ||
// Since etcd 3.5 | ||
Attributes *attributes.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.
We can assign this map to attributes.Attributes using the utilities New
and WithValue
Attributes *attributes.Attributes | |
Attributes map[string]any |
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.
Unfortunately the the grpc attributes package is also Experimental
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 approach will solve the JSON problem for sure. I will adjust it now. Meanwhile, you also mentioned the grpc attributes package is also Experimental
. I mean we've already decided to take this direction so, things like this should be expected. Except you have something else in mind, of course. Are you having second thoughts?
cc: @ahrtr
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.
Are you having second thoughts?
The alternative is to support generic type (a comparable type), so that the key of the map doesn't have to be a string. But let's keep it simple for now, as we are playing with grpc-go's experimental feature/packages.
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.
+1 you should not use any experimental APIs in your own APIs, unless you want to declare them as experimental and your users are aware that you reserve the right to break them in the future.
You also need that disclaimer on any package that internally uses experimental APIs. But if you refrain from exposing it in your own APIs, then there should be some path forward that doesn't require changes to the user's code, too.
524789c
to
3ad2fb6
Compare
…tadata This implementation adds the new Attributes *attributes.Attributes into Endpoint and deprecate Metadata accordingly. The metadata field is still supported for backward compatibility Signed-off-by: amosehiguese <[email protected]>
3ad2fb6
to
1264be5
Compare
if attr != nil { | ||
attr = attr.WithValue(k, v) | ||
} else { | ||
attr = attributes.New(k, v) |
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.
WithValue
already does this, so you can simplify by deleting the else
here.
@@ -49,4 +49,11 @@ type Update struct { | |||
// Metadata is not required for a custom naming implementation. | |||
// Since etcd 3.1. | |||
Metadata any | |||
|
|||
// Attributes is for storing and retrieving generic key/value pairs. | |||
// Keys must be hashable, and users should define their own types for keys. |
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.
Keys must be hashable
This needs to be updated with the change to map
.
// Attributes contains arbitrary data about this address intended for | ||
// consumption by the SubConn. | ||
// Since etcd 3.5 | ||
Attributes *attributes.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.
+1 you should not use any experimental APIs in your own APIs, unless you want to declare them as experimental and your users are aware that you reserve the right to break them in the future.
You also need that disclaimer on any package that internally uses experimental APIs. But if you refrain from exposing it in your own APIs, then there should be some path forward that doesn't require changes to the user's code, too.
This implementation adds the new Attributes *attributes.Attributes into Endpoint and deprecate Metadata accordingly. The metadata field is still supported for backward compatibility
Fixes #19706
cc: @ahrtr @siyuanfoundation
Please read https://github.com/etcd-io/etcd/blob/main/CONTRIBUTING.md#contribution-flow.