-
Notifications
You must be signed in to change notification settings - Fork 935
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
Support STRICT_DNS
, HealthCheck
for XdsEndpointGroup
(xDS-endpoint pt 3)
#5503
Conversation
c980e73
to
9ff1c74
Compare
STRICT_DNS
, HealthCheck
for XdsEndpointGroup
((xDS-endpoint pt 3)STRICT_DNS
, HealthCheck
for XdsEndpointGroup
(xDS-endpoint pt 3)
07f880a
to
874016a
Compare
874016a
to
2ff20b5
Compare
2ff20b5
to
d39ec69
Compare
Ready for review 😄 |
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.
Overall looks good. Left minor comments.
endpoint = Endpoint.of(hostname) | ||
.withIpAddr(socketAddress.getAddress()) | ||
.withAttr(XdsAttributesKeys.LB_ENDPOINT_KEY, lbEndpoint) | ||
.withAttr(XdsAttributesKeys.LOCALITY_LB_ENDPOINTS_KEY, localityLbEndpoints); |
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.
Q) Should we also set weight
for this 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.
🤦
|
||
static int endpointWeight(LbEndpoint lbEndpoint) { | ||
return lbEndpoint.hasLoadBalancingWeight() ? | ||
Math.max(1, lbEndpoint.getLoadBalancingWeight().getValue()) : 1; |
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.
Envoy uses 1 as the default weight if unspecified.
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/endpoint/v3/endpoint_components.proto
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointGroup.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterManager.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterManager.java
Outdated
Show resolved
Hide resolved
this.endpoints = ImmutableList.copyOf(endpoints); | ||
} | ||
|
||
ClusterLoadAssignment clusterLoadAssignment() { |
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 code is unused. Did you add it for the future usage?
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 eventually will, but I'm committed to splitting PRs so let me remove it 😄
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterManager.java
Show resolved
Hide resolved
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5503 +/- ##
============================================
+ Coverage 74.05% 74.07% +0.01%
- Complexity 20854 20923 +69
============================================
Files 1807 1815 +8
Lines 76757 77010 +253
Branches 9792 9823 +31
============================================
+ Hits 56842 57044 +202
- Misses 15292 15319 +27
- Partials 4623 4647 +24 ☔ View full report in Codecov by Sentry. |
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.
Nice work! 🚀🚀
endpointGroup.removeListener(this); | ||
endpointGroup.removeListener(clusterManager); | ||
return endpointGroup.closeAsync(); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
endpointGroup.close(); |
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.
Q) Is endpointGroup.removeListener(...)
unnecessary for close()
?
private State state() { | ||
final Map<ClusterSnapshot, ClusterEntry> clusterEntries = this.clusterEntries; | ||
if (clusterEntries.isEmpty()) { | ||
return new State(listenerSnapshot, Collections.emptyList()); |
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.
To avoid additional object allocations. EmptyList
in JDK creates an empty array when .toArray()
is called. In addition, the call path inside ImmutableList.copyOf()
is shorter.
return new State(listenerSnapshot, Collections.emptyList()); | |
return new State(listenerSnapshot, ImmutableList.of()); |
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.
Left only minor suggestion.
Looks great!
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterEntry.java
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterManager.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/SubsetLoadBalancer.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterManager.java
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointGroup.java
Outdated
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointGroup.java
Show resolved
Hide resolved
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointSelector.java
Show resolved
Hide resolved
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.
Looks great! 💯 💯 💯
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/ClusterManager.java
Outdated
Show resolved
Hide resolved
…sterManager.java Co-authored-by: minux <[email protected]>
public void accept(List<Endpoint> endpoints) { | ||
final List<Endpoint> mappedEndpoints = | ||
endpoints.stream() | ||
.map(endpoint -> endpoint.withAttr(LB_ENDPOINT_KEY, lbEndpoint) | ||
.withAttr(LOCALITY_LB_ENDPOINTS_KEY, localityLbEndpoints) | ||
.withWeight(XdsEndpointUtil.endpointWeight(lbEndpoint))) | ||
.collect(Collectors.toList()); | ||
setEndpoints(mappedEndpoints); | ||
} |
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.
@jrhee17 Is this method necessary?
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 believe so.
The objective of XdsAttributeAssigningEndpointGroup
is to add attributes to Endpoint
s from the delegate.
For this reason, the delegate is listened to:
Line 43 in 01f2c6f
delegate.addListener(this, true); |
and then setEndpoints
is called.
Line 54 in 01f2c6f
setEndpoints(mappedEndpoints); |
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.
Having said this, if you believe this method is unnecessary you're more than welcome to try to remove it and upload a patch
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.
Ah, it's just that I couldn't find where the accept is called. 😓 Thanks for the explanation.
This PR attempts to support
DNS
, Health Checked clusters. This is done by convertingClusterSnapshot
to anEndpointGroup
viaXdsEndpointUtil#convertEndpoints
. The rest of the changes are simply refactoring.Motivation:
There are three major points of change:
XdsEndpointUtil#convertEndpointGroup
has been introduced which converts aClusterSnapshot
into anEndpointGroup
.This method essentially converts a
ClusterSnapshot
into aDnsAddressEndpointGroup
or aHealthCheckedEndpointGroup
. Note that only basic functionality is supported at this stage.During this implementation, I found it convenient to refer to a
LbEndpoint
orLocalityLbEndpoints
for a particularEndpoint
. For this reason,XdsAttributeKeys
,XdsAttributeAssigningEndpointGroup
has been introduced so that xDS resource information can be retrieved easily. This is useful later as well, in order to fetch the locality, priority, health, etc. of a particular endpoint.Some include:
LoadBalancer
: https://github.com/envoyproxy/envoy/blob/d5bfc06f110647127edc5ddc3bd6cfda78f2760b/source/common/upstream/load_balancer_impl.h#L83ClusterManager
: https://github.com/envoyproxy/envoy/blob/d5bfc06f110647127edc5ddc3bd6cfda78f2760b/source/common/upstream/cluster_manager_impl.h#L245ClusterEntry
: https://github.com/envoyproxy/envoy/blob/d5bfc06f110647127edc5ddc3bd6cfda78f2760b/source/common/upstream/cluster_manager_impl.h#L578PrioritySet
: https://github.com/envoyproxy/envoy/blob/d5bfc06f110647127edc5ddc3bd6cfda78f2760b/envoy/upstream/upstream.h#L533SubsetLoadBalancer
: https://github.com/envoyproxy/envoy/blob/d5bfc06f110647127edc5ddc3bd6cfda78f2760b/source/extensions/load_balancing_policies/subset/subset_lb.h#L135The nuances are slightly different due to a difference in existing APIs, difference in threading model and lifecycles. However, an effort has been made to keep the implementation relatively similarly looking.
Note that the logic inside
SubsetLoadBalancer
is changed minimally to keep the changeset small.XdsEndpointGroup
.ClusterManager
now receives updates on theListenerSnapshot
by listening to the providedListenerRoot
. On each snapshot update, aClusterEntry
is created for eachClusterSnapshot
.ClusterEntry
constructs theEndpointGroup
based on the providedClusterSnapshot
and endpoint updates (dns/health checkedEndpointGroup
s may update multiple times).Whenever 1) A
ClusterEntry#endpointGroup
's endpoints are updated or 2)ListenerSnapshot
is updated, thenClusterManager#notifyListeners
callsXdsEndpointGroup#setEndpoints
. This will eventually triggerXdsEndpointSelector#selectNow
. This will subsequently triggerClusterManager#selectNow
andLoadBalancer#selectNow
.Miscellaneous changes
XdsEndpointGroup
implementsEndpointGroup
directly since custom comparison logic is required forXdsEndpointGroup#updateState
Endpoint
into an interface, and supported various types of endpoints (e.g.HealthCheckedEndpoint
,XdsEndpoint
, etc..). For now, I propose to use attributes for simplicity.ClusterManager#notifyListeners
is called for any update (i.e. update to the snapshot,DnsAddressEndpointGroup
updates, etc..) there is a good chance that empty endpoints will be set. This isn't ideal based on the normal use case where users usually wait for initial endpoints viaEndpointGroup#whenComplete
. I've setallowEmptyEndpoints = false
to be the default.POC: #5450
Modifications:
XdsEndpointUtil#convertEndpointGroup
, which creates anEndpointGroup
based on theClusterSnapshot
.DNS
,HealthCheck
capabilities are partially supported.LoadBalancer
,ClusterManager
,ClusterEntry
,PrioritySet
,SubsetLoadBalancer
are newly introduced.ClusterManager
listens for any updates regardingEndpoint
s orSnapshot
s and notifiesEndpointGroup
if there are any changes. Every time this occurs,LoadBalancer#selectNow
is called.Result:
XdsEndpointGroup
now partially supports DNS and health check.