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

Introduce xDS module and SotW stream #5342

Merged
merged 7 commits into from Dec 27, 2023

Conversation

jrhee17
Copy link
Contributor

@jrhee17 jrhee17 commented Dec 12, 2023

Motivation:

We would like to introduce a xDS integration module.
In order to fetch resources from xDS module, I would like to introduce a Stream object which represents a single persistent connection to a remote control plane server. The Stream will query a SubscriberStorage to check which resources are subscribed and update the request accordingly.

Once a response is recieved, the type will be used to fetch a ResourceParser which will later parse the response. Afterwards, the parameters will be sent over to a ResponseHandler which will handle the response and send either an ackResponse or nackResponse to keep the feedback loop open. Also, a resourcesUpdated can be sent to indicate the subscribed resources have been changed.

Modifications:

  • Introduced a SotwXdsStream which represents a persistent connection to a control plane server
  • Introduced a ResourceParser which will be responsible for parsing a response in a format readily sendable in a nack response
  • Introduced a XdsStreamSubscriber and SubscriberStorage which represent the currently subscribed resources

Result:

@jrhee17 jrhee17 marked this pull request as ready for review December 12, 2023 04:27
@jrhee17 jrhee17 added this to the 1.27.0 milestone Dec 12, 2023
Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Looks pretty good so far. 👍
Left style comments and some questions. 😉


import com.linecorp.armeria.common.util.SafeCloseable;

class XdsStreamSubscriber implements SafeCloseable {
Copy link
Member

Choose a reason for hiding this comment

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

So the purpose of this class is to keep the reference?
Are there any other features to be added to this class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Later, I imagine class will be responsible for:

  • Scheduling timeouts
  • Caching values
  • Notifying the watcher storage of updates

ref: https://github.com/line/armeria/blob/90a93499de29ffac1b27084aba07eeead3c716e7/xds/src/main/java/com/linecorp/armeria/xds/XdsStreamSubscriber.java
docs:

Whenever a subscribed resource is updated in the remote control plane server, a notification is
sent to the client over the `Stream`. The `Stream` then parses the resources and passes the
data to the `Subscriber`. Eventually, the subscriber will notify the subscribed `Watcher`s of this resource.

interface XdsResponseHandler {

<T extends Message> void handleResponse(
ResourceParser<T> resourceParser, DiscoveryResponse value, SotwXdsStream sender);
Copy link
Member

Choose a reason for hiding this comment

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

Is resourceParser necessary? DiscoveryResponse has the type in it so we can use the type to get the corresponding ResourceParser.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean there is no need to pass the resourceParser and we can re-run XdsResourceParserUtil.fromTypeUrl?

We could, but what would be the advantage of doing so?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my mind, the Stream layer will do all the heavy lifting to ensure communication with the control plane is maintained and up-to-date.
For this reason I would rather keep nonceMap, versionsMap in the XdsStream layer.

noncesMap.put(resourceParser.type(), value.getNonce());

In order to do so, I think it makes sense that the ResourceType (or ResourceParser) is determined inside SotwXdsStream. I didn't see a need to re-compute this so I just passed it via parameter. I'd rather keep this the way it is, but let me know if you feel strongly about this 😄

Copy link
Member

Choose a reason for hiding this comment

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

Understood. That makes sense. 👍

<T extends Message> void handleResponse(
ResourceParser<T> resourceParser, DiscoveryResponse value, SotwXdsStream sender);

void handleReset(XdsStream sender);
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain the definition of reset? 🤔

Copy link
Contributor Author

@jrhee17 jrhee17 Dec 20, 2023

Choose a reason for hiding this comment

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

Whenever the stream thinks its SubscriberStorage may not be synchronized with the control plane, then a reset is done. This can be the case if a connection is closed unexpectedly, or if a stream is doing a cold start.

When a reset is performed, all of the currently watched types and resources are sent to the control plane server. Note that this is a package-private interface, and is exposed for testing purposes.

ref:

public void handleReset(XdsStream sender) {
storage.allSubscribers().keySet().forEach(sender::resourcesUpdated);
}

Copy link

codecov bot commented Dec 20, 2023

Codecov Report

Attention: 37 lines in your changes are missing coverage. Please review.

Comparison is base (6a5f3ad) 73.93% compared to head (a1be5ac) 73.96%.
Report is 11 commits behind head on main.

❗ Current head a1be5ac differs from pull request most recent head 18444c8. Consider uploading reports for the commit 18444c8 to get more accurate results

Files Patch % Lines
...n/java/com/linecorp/armeria/xds/SotwXdsStream.java 89.62% 7 Missing and 4 partials ⚠️
...m/linecorp/armeria/xds/EndpointResourceParser.java 16.66% 5 Missing ⚠️
...m/linecorp/armeria/xds/ListenerResourceParser.java 16.66% 5 Missing ⚠️
.../com/linecorp/armeria/xds/RouteResourceParser.java 16.66% 5 Missing ⚠️
...va/com/linecorp/armeria/xds/SubscriberStorage.java 83.87% 2 Missing and 3 partials ⚠️
...om/linecorp/armeria/xds/ClusterResourceParser.java 33.33% 4 Missing ⚠️
.../java/com/linecorp/armeria/xds/ResourceParser.java 50.00% 1 Missing ⚠️
.../com/linecorp/armeria/xds/XdsStreamSubscriber.java 90.90% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5342      +/-   ##
============================================
+ Coverage     73.93%   73.96%   +0.03%     
- Complexity    20098    20159      +61     
============================================
  Files          1730     1741      +11     
  Lines         74142    74353     +211     
  Branches       9461     9481      +20     
============================================
+ Hits          54815    54998     +183     
- Misses        14852    14869      +17     
- Partials       4475     4486      +11     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Looks good so far. 👍
Let's get to the next one. 😉

Comment on lines 137 to 138
Thread.sleep(100);
assertThat(responseHandler.getResponses()).isEmpty();
Copy link
Member

Choose a reason for hiding this comment

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

Global comment: Could we use Awaitility?

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

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

�Let's start xDS. Let me review in detail on #5336. 🙇‍♂️🙇‍♂️

import com.google.common.base.MoreObjects;
import com.google.protobuf.Message;

abstract class ResourceParser<T extends Message> {
Copy link
Contributor

@ikhoon ikhoon Dec 26, 2023

Choose a reason for hiding this comment

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

I'm not sure the generic type parameter provides type safety in xDS implementation.
As the input is dynamically determined by typeUrl at runtime, the compile time constrain does not seem to work.
https://github.com/line/armeria/pull/5342/files#diff-463524dcc65fabda54bb06752b0e248879c7bc1e5b367d0e8885bfbd23aa785bR209

What do you think of removing <T extends Message> and checking the type with XdsType only?

@jrhee17 jrhee17 merged commit 02cbc34 into line:main Dec 27, 2023
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants