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

discovery: refactor configuration ingestion. #11638

Merged
merged 15 commits into from
Jul 1, 2020

Conversation

htuch
Copy link
Member

@htuch htuch commented Jun 18, 2020

Previously, the gRPC muxes required decoding an opaque resource to
obtain its name, then dispatch to the relevant subscription, which would
again decode the opaque resource. This is pretty horrible efficiency
wise, in particular when upgrading from v2 -> v3.

In this patch, we introduce a DecodedResource wrapper and
OpaqueResourceDecoder. The config ingestion module, e.g. GrpcMuxImpl,
uses the OpaqueResourceDecoder to produce a typed DecodedResource,
performing the decode once. This DecodedResource is then dispatched
to the watching subscription.

This provides > 20% speedup on the v2 -> v3 tax for eds_speed_test,
decreasing from an overhead of 3.2x to 2.5x. It's also likely to unlock
further optimizations as we now have a wrapper resource and simplifies
subscription implementations, as they no longer need to deal with delta
vs. SotW resource decoding in different ways.

Risk level: Medium (configuration ingestion path changes).
Testing: New unit tests for
DecodedResourceImpl/OpaqueResourceDecoderImpl, updated existing unit
tests to work with new interfaces.

Partial solution to #11362

Signed-off-by: Harvey Tuch htuch@google.com

Previously, the gRPC muxes required that decoding an opaque resource to
obtain its name, then dispatch to the relevant subscription, which would
again decode the opaque resource. This is pretty horrible efficiency
wise, in particular when upgrading from v2 -> v3.

In this patch, we introduce a DecodedResource wrapper and
OpaqueResourceDecoder. The config ingestion module, e.g. GrpcMuxImpl,
uses the OpaqueResourceDecoder to produce a typed DecodedResource,
performing the decode once. This DecodedResource is then dispatched
to the watching subscription.

This provides > 20% speedup on the v2 -> v3 tax for eds_speed_test,
decreasing from an overhead of 3.2x to 2.5x. It's also likely to unlock
further optimizations as we now have a wrapper resource and simplifies
subscription implementations, as they no longer need to deal with delta
vs. SotW resource decoding in different ways.

Risk level: Medium (configuration ingestion path changes).
Testing: New unit tests for
  DecodedResourceImpl/OpaqueResourceDecoderImpl, updated existing unit
  tests to work with new interfaces.

Partial solution to envoyproxy#11362

Signed-off-by: Harvey Tuch <htuch@google.com>
@htuch
Copy link
Member Author

htuch commented Jun 19, 2020

@pgenera FYI, this PR reduces v3 conversion overhead by 20-25%.

/**
* Invoked when raw config received from xDS wire.
*/
class UntypedConfigUpdateCallbacks {

Choose a reason for hiding this comment

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

is there a reason this interface must still be maintained? Is it possible to make all callbacks use 'DecodedResource'

Copy link
Member Author

@htuch htuch Jun 23, 2020

Choose a reason for hiding this comment

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

It's used on the WatchMap interface, prior to any resource decoding.

* @return SubscriptionPtr subscription object corresponding for config and type_url.
*/
virtual SubscriptionPtr
subscriptionFromConfigSource(const envoy::config::core::v3::ConfigSource& config,
absl::string_view type_url, Stats::Scope& scope,
SubscriptionCallbacks& callbacks) PURE;
SubscriptionCallbacks& callbacks,
OpaqueResourceDecoder& resource_decoder) PURE;

Choose a reason for hiding this comment

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

Are different decoders used for different subscriptions? If not, would it be better for the SubscriptionFactory implementation to be constructed with the decoder?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, each resource decoder effectively capture the Any conversion for the subscription type, so it has to be part of the args here.

Choose a reason for hiding this comment

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

ok

SubscriptionCallbacks& callbacks) {
auto watch = std::make_unique<GrpcMuxWatchImpl>(resources, callbacks, type_url, *this);
SubscriptionCallbacks& callbacks,
OpaqueResourceDecoder& resource_decoder) {

Choose a reason for hiding this comment

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

if the grpc_mux_impl uses the same resource_decoder to decode all resources, I think it makes sense to make it a member of the class

Copy link
Member Author

Choose a reason for hiding this comment

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

As above, since this has the type-specific Any conversion internally, we need to supply the resource decoder on each watch when muxing across types, i.e. ADS.

Choose a reason for hiding this comment

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

got it

source/common/config/http_subscription_impl.cc Outdated Show resolved Hide resolved
source/common/config/watch_map.cc Show resolved Hide resolved
source/common/config/filesystem_subscription_impl.cc Outdated Show resolved Hide resolved
@htuch
Copy link
Member Author

htuch commented Jun 25, 2020

@wgallagher could you take another look, review feedback should be addressed, thanks.

Signed-off-by: Harvey Tuch <htuch@google.com>
@htuch
Copy link
Member Author

htuch commented Jun 26, 2020

Also adding @mattklein123 as reviewer for maintainer approval.

@wgallagher
Copy link

+1 lgtm

mattklein123
mattklein123 previously approved these changes Jun 30, 2020
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Nice, very cool. Some optional comments from my skim through.

Comment on lines +50 to +59
/**
* @return const Protobuf::Message& resource message reference. If hasResource() is false, this
* will be the empty message.
*/
virtual const Protobuf::Message& resource() const PURE;

/**
* @return bool does the xDS discovery response have a set resource payload?
*/
virtual bool hasResource() const PURE;
Copy link
Member

Choose a reason for hiding this comment

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

From an interface perspective you might consider just returning an optional reference from resource() and then I think you can do away with hasResource()?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I tried that initially, but it's cleaner to do it this way, since some sites still want a resource (the empty resource) even if hasResource() is false.

source/common/config/grpc_mux_impl.cc Outdated Show resolved Hide resolved
Signed-off-by: Harvey Tuch <htuch@google.com>
Signed-off-by: Harvey Tuch <htuch@google.com>
Signed-off-by: Harvey Tuch <htuch@google.com>
@htuch htuch merged commit 9b86ed6 into envoyproxy:master Jul 1, 2020
@htuch htuch deleted the resource-name-opt branch July 1, 2020 15:17
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.

3 participants