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

xds: allow "*" to indicate a wildcard subscription #16861

Merged
merged 4 commits into from
Jun 11, 2021

Conversation

markdroth
Copy link
Contributor

@markdroth markdroth commented Jun 7, 2021

Signed-off-by: Mark D. Roth [email protected]

Commit Message: xds: allow * to indicate a wildcard subscription
Additional Description: Update xDS spec to say that * indicates a wildcard subscription and the existing behavior of specifying no resource names to subscribe to is just a syntactic alias for subscribing to *.
Risk Level: Low
Testing: N/A
Docs Changes: Included in PR
Release Notes: N/A
Platform Specific Features: N/A

Alternative doc proposal for #16855. CC @krnowak

The incremental protocol also provides a mechanism for lazy loading of resources. For details on
the incremental protocol, see :ref:`Incremental xDS <xds_protocol_delta>` below.
interested in with each request, and the server must return all resources the client has
subscribed to in each request (in LDS/CDS). This means that if the client is already subscribing
Copy link
Contributor

Choose a reason for hiding this comment

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

I think (in LDS/CDS) part makes the sentence confusing. Perhaps it's worth clarifying that in LDS/CDS there could be multiple resources in a reply, while for RDS/EDS it's always one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be clear, even in RDS and EDS, it's totally valid to have multiple resources per reply; for example, if the client is subscribed to 5 EDS resources and 2 of those resources change, the server can send a response including those two resources. The thing that's special about LDS and CDS is that the server is required to send all resources that the client is subscribed to in every response, even the ones that haven't changed. So if a client is subscribed to 5 LDS resources and 2 of them change, the server must send a response that includes all 5 resources. (This is because the SotW protocol doesn't provide a way for the server to explicitly indicate to the client that a resource has been removed, so the only way to remove an LDS or CDS resource is by not including it in a response. And the removal criteria for RDS and EDS resources is even messier; see the "Deleting Resources" section below.)

Anyway, I've attempted to reword this a bit to clarify it, but I haven't changed the phraseology about the condition this is discussing, because that was already correct.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the rewording, I think it's much clearer now.

To be clear, even in RDS and EDS, it's totally valid to have multiple resources per reply

Hmm, not according to the implementation (rds: https://github.com/envoyproxy/envoy/blob/main/source/common/router/rds_impl.cc#L227, eds: https://github.com/envoyproxy/envoy/blob/main/source/common/upstream/eds.cc#L166): updates with more than resource will be dropped.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that Envoy currently creates a separate stream for each resource when using non-aggregated EDS, as per #2943, and the same may be true of RDS. However, this is a limitation of Envoy's implementation, not of the xDS protocol. There is no protocol-level reason why there cannot be more than one resource send per response for any resource type.

Note that when using ADS, Envoy does support multiple resources per response for EDS and RDS. But nothing about that functionality is actually tied to ADS; the exact same thing could be done in non-aggregated streams.

subscribed to in each request (in LDS/CDS). This means that if the client is already subscribing
to 99 resources and wants to add an additional one, it must send a request with all 100 resource
names, rather than just the one new one. And the server must then respond by sending all 100
resources, even if the 99 that were already subscribed to have not changed (in LDS/CDS). This
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto here re: (in LDS/CDS).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated wording here too.

@dmitri-d
Copy link
Contributor

dmitri-d commented Jun 7, 2021

lgtm, other than a small nit: re LDS/CDS clarification.

@krnowak
Copy link
Contributor

krnowak commented Jun 8, 2021

The wording sounds better than mine, thanks. Should the change get an entry in docs/root/version_history/current.rst?

@markdroth
Copy link
Contributor Author

The wording sounds better than mine, thanks. Should the change get an entry in docs/root/version_history/current.rst?

I don't think it needs one, since it's not an implementation change, just a spec change.

krnowak
krnowak previously approved these changes Jun 8, 2021
Copy link
Contributor

@krnowak krnowak left a comment

Choose a reason for hiding this comment

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

LGTM.

@dmitri-d
Copy link
Contributor

dmitri-d commented Jun 8, 2021

lgtm.

dmitri-d
dmitri-d previously approved these changes Jun 8, 2021
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

Awesome, sorry for the delayed review.
/wait


For historical reasons, if the initial request on the stream for a given resource type contains no
resource names, the server should treat that as a subscription to "*". A client may later
unsubscribe to "*", or it may later add a subscription to an additional resource name.
Copy link
Member

Choose a reason for hiding this comment

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

Note that we are going to break any existing setup that names a singleton resource *. Seems a bit far fetched, but technically a breaking change. If we instead used something like xds_internal://* here as a name (or something unlikely to collide), we might stand a lower chance of collision but don't feel super strong on this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that no matter what name we pick here, collisions are possible. I'd rather keep the name short and intuitive.

that once a stream has entered wildcard mode for a given resource type, there is no way to change
the stream out of wildcard mode; resource names specified in any subsequent request on the stream
will be ignored.
types, there is also a "wildcard" subscription, which is triggered when subscribing to the special
Copy link
Member

Choose a reason for hiding this comment

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

Do we cover how * and on-demand work together in a SotW request in this spec?

Copy link
Member

Choose a reason for hiding this comment

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

Also how non-explicit * and explicit * subscriptions can be converted or used interchangeably? E.g. can I subscribe to {} but unsubscribe from *?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change isn't really about on-demand; it's just about how to represent a wildcard subscription as a discrete name that can coexist with other subscriptions for the same resource type on the same stream. This mechanism is a prerequisite for on-demand CDS, but it's not actually part of the same feature.

I've made some changes in the next paragraph to attempt to clarify the semantics, and I've added some examples to help illustrate.

docs/root/api-docs/xds_protocol.rst Outdated Show resolved Hide resolved
Signed-off-by: Mark D. Roth <[email protected]>
@markdroth markdroth dismissed stale reviews from dmitri-d and krnowak via 6c0d5e4 June 10, 2021 15:48
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

LGTM; needs CI docs fix though. Thanks!

@markdroth
Copy link
Contributor Author

The CI failure looks unrelated to this PR. Is there a way to retry it?

@dmitri-d
Copy link
Contributor

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #16861 (comment) was created by @dmitri-d.

see: more, trace.

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@htuch htuch merged commit b164962 into envoyproxy:main Jun 11, 2021
@markdroth markdroth deleted the xds_wildcard branch September 20, 2021 15:10
explicitly subscribed to "*". However, once the client does explicitly subscribe to a resource
name (whether it be "*" or any other name), then this legacy semantic is no longer available; at
that point, clearing the list of subscribed resources is interpretted as an unsubscription (see
:ref:`Unsubscribing From Resources<xds_protocol_unsubscribing>`) rather than as a subscription
Copy link
Contributor

Choose a reason for hiding this comment

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

there is a case this is not true:

  1. client subscribes A, B, C
  2. client unsubs A, B, C, connection broke, reconnection happens
  3. on reconnection, client send empty init_resource_versions and subscribes, it's treated as wildcard client now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the client is no longer subscribed to any resources of a given resource type, then it will not send any request for that resource type when it reconnects, so that's not an issue.

- Client sends a request with :ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_subscribe>` unset. Server interprets this as a subscription to "*".
- Client sends a request with :ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_subscribe>` set to "A". Server interprets this as continuing the existing subscription to "*" and adding a new subscription to "A".
- Client sends a request with :ref:`resource_names_unsubscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_unsubscribe>` set to "*". Server interprets this as unsubscribing to "*" and continuing the existing subscription to "A".
- Client sends a request with :ref:`resource_names_unsubscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_unsubscribe>` set to "A". Server interprets this as unsubscribing to "A" (i.e., the client has now unsubscribed to all resources). Although the set of subscribed resources is now empty, just as it was after the initial request, it is not interpreted as a wildcard subscription, because there has previously been a request on this stream for this resource type that set the :ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.DeltaDiscoveryRequest.resource_names_subscribe>` field.
Copy link
Contributor

Choose a reason for hiding this comment

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

reconnection will make things messy here if we dont explicitly say it's wildcard or not.

Could you clarify on this more?
Consider this case:

  1. Client subscribes: A, *
  2. Server sends: A, B, C, D
  3. Client removes: *
  4. Server has update for B, C, -D, and new resource E, now does it send (update B, C, remove D) to the client or not?

Also noteworthy that reconnection for the above scenario would become tricky:

  1. reconnect happens, now client has A, B, C, D in the intial_resource_versions, Server will keep sending updates for A, B, C, D to the client.

Copy link
Contributor

Choose a reason for hiding this comment

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

reconnection will make things messy here if we dont explicitly say it's wildcard or not.

Could you clarify on this more?
Consider this case:

1. Client subscribes: A, *

2. Server sends: A, B, C, D

3. Client removes: *

4. Server has update for B, C, -D, and new resource E, now does it send (update B, C, remove D) to the client or not?

I'm not sure. I would say that either "server sends (remove B, C and D)" or "server sends (remove *)" and client takes care of dropping wildcard resources from its cache.

Also noteworthy that reconnection for the above scenario would become tricky:

1. reconnect happens, now client has A, B, C, D in the intial_resource_versions, Server will keep sending updates for A, B, C, D to the client.

I'd say that once client unsubscribes from wildcard, it should drop the wildcard resources it has, so if reconnect happens, only A should be in initial resources.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consider this case:

  1. Client subscribes: A, *
  2. Server sends: A, B, C, D
  3. Client removes: *
  4. Server has update for B, C, -D, and new resource E, now does it send (update B, C, remove D) to the client or not?

As per the clarification I added in #17983, the server does not need to send anything for B, C, D, or E in this case.

Also noteworthy that reconnection for the above scenario would become tricky:

  1. reconnect happens, now client has A, B, C, D in the intial_resource_versions, Server will keep sending updates for A, B, C, D to the client.

Once the client reconnects, it sends only A in resource_names_subscribe, so this is not an issue. Even if the other resources were somehow present in initial_resource_versions, that field does not affect the set of resources that the client is actually subscribed to.

subscribed to is determined by the server instead of the client, so there is no mechanism
for the client to unsubscribe from resources.
subscribed to is determined by the server instead of the client, so the client cannot unsubscribe
from those resources individually; it can only unsubscribe from the wildcard as a whole.
Copy link
Contributor

Choose a reason for hiding this comment

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

could you elaborate how to effectively unsubscribe resources that are "included " in the "wildcard subscription" when the client unsubscribes "*"?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say that the client should be more or less able to track which resources are from wildcard subscription, so it should be able to drop them from its caches when unsubscribing from *.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, @krnowak is correct. The client already knows which specific non-wildcard resources it is subscribed to, so when it unsubscribes from *, it can immediately drop all other resources from its cache.

leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
Update xDS spec to say that * indicates a wildcard subscription and the existing behavior of specifying no resource names to subscribe to is just a syntactic alias for subscribing to *.

Signed-off-by: Mark D. Roth <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants