-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Buffer Factory: Configuration of the minimum account size to track. #17562
Conversation
account size to track. Signed-off-by: Kevin Baichoo <[email protected]>
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
/assign @antoniovicente PTAL |
Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
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.
API review
@@ -219,6 +219,8 @@ message Bootstrap { | |||
(udpa.annotations.security).configure_for_untrusted_upstream = true | |||
]; | |||
|
|||
BufferFactoryConfig buffer_factory_config = 33; |
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.
Needs comment. Should this be placed in some other message like ResourceTrackingConfig
for future proofing? Not sure what else we anticipate here, but not a big fan of tons of knobs on the top-level bootstrap.
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.
Done.
// Configuration for the Buffer Factories that create Buffers and Accounts. | ||
message BufferFactoryConfig { | ||
// The minimum account size at which Envoy starts tracking a stream. | ||
// This *MUST* be a power of two. |
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.
Why not make it the exponent then?
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.
Good idea, will go with this.
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.
Sorry for review delays. Main comment is how these new config fields would interact with overload manager actions.
// [account_tracking_threshold_bytes, 2 * account_tracking_threshold_bytes). | ||
// With the 8th bucket tracking accounts | ||
// >= 128 * account_tracking_threshold_bytes. | ||
uint32 account_tracking_threshold_bytes = 1 [(validate.rules).uint32 = {gt: 0}]; |
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.
Would it be possible to add a proto validator to verify it is a power of 2?
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.
It's currently not supported by protogen validate, will go with exponent as htuch suggested.
|
||
// Configuration for the Buffer Factories that create Buffers and Accounts. | ||
message BufferFactoryConfig { | ||
// The minimum account size at which Envoy starts tracking a stream. |
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.
Worth providing config options for both the min and max thresholds?
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 think min with 8 buckets based on power of two should be sufficient for now -- e.g. if first bucket's range is [Y, 2Y) the final bucket will be >= 128 * Y.
@@ -642,3 +644,16 @@ message CustomInlineHeader { | |||
// The type of the header that is expected to be set as the inline header. | |||
InlineHeaderType inline_header_type = 2 [(validate.rules).enum = {defined_only: true}]; | |||
} | |||
|
|||
// Configuration for the Buffer Factories that create Buffers and Accounts. | |||
message BufferFactoryConfig { |
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 there other places in the config where we should consider configuring this? HttpConnectionManager or listener may make sense. The issue is that each permutation of the config would require a separate set of tracker objects.
Also, what would the overload manager config for this functionality would look like? This new config field feels like typed config for the overload manager reset streams action.
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.
There's one buffer factory per worker. I think configuring it on something dynamic e.g. listeners would add additional complexity.
I see the argument for this being a typed config for an overload manager reset stream action, would need to do a good amount of plumbing to expose the overload manager to the API object from which I can create the watermark factory. Of the 6 overload actions here: https://www.envoyproxy.io/docs/envoy/latest/configuration/operations/overload_manager/overload_manager#overload-actions only one uses additional typed_config (reduce_timeouts)
See: https://github.com/KBaichoo/envoy/pull/111/files#diff-c69815663eb82a9e98598ce5dc2c55bc7a4b0b180dd7fe188ef1227bdab9160cR170-R190 for how the overload manager could leverage this without additional typed config
I also see the benefit of tracking being independent e.g. stats monitoring the buckets
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.
Looking into the feasibility of this in an overload_manager action:
api_impl
creates watermark buffer factories
through its creation of dispatchers
. The watermark buffer factories should know the minimum account sizes to track at creation.
If we shift the knowledge of the minimum account size to an overload manager action, then the api_impl
needs access to the overload manager
in order to create dispatchers. But the overload manager needs the api object in its ctor.
Going down this route seems very convoluted given that dependence.
We could have instead the api_impl
parse some of the overload manager config from the bootstrap to get the knowledge, but that also seems wrong since the module is leaking.
As such I'm leaning towards wrapping this in ResourceTrackingConfig
or similar as htuch recommends to future proof it.
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.
How about having these parameters are part of the toplevel OverloadManager proto since they are related to that functional area? The OverloadManager proto is already a parsed member in the bootstrap. The config option would go here:
google.protobuf.Duration refresh_interval = 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.
Done, moved to top level of the Overload Manager config.
@@ -195,10 +215,11 @@ BufferMemoryAccountImpl::createAccount(WatermarkBufferFactory* factory, | |||
} | |||
|
|||
int BufferMemoryAccountImpl::balanceToClassIndex() { | |||
const uint64_t shifted_balance = buffer_memory_allocated_ >> 20; // shift by 1MB. | |||
static uint32_t bitshift = factory_->bitshift(); |
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.
Do you mean const?
Use of static here is sure to cause problems in tests as test cases beyond the first would effectively ignore config changes.
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 prematurely optimized will make it const instead.
Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
/retest |
Retrying Azure Pipelines: |
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.
/lgtm api
@@ -206,6 +212,7 @@ class WatermarkBufferFactory : public WatermarkFactory { | |||
using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>, | |||
BufferMemoryAccountImpl::NUM_MEMORY_CLASSES_>; | |||
MemoryClassesToAccountsSet size_class_account_sets_; | |||
uint32_t bitshift_; |
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.
nit: const
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.
A comment would be good.
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.
Done.
: WatermarkBufferFactory([min_tracking_bytes]() { | ||
auto config = envoy::config::bootstrap::v3::ResourceTrackingConfig::BufferFactoryConfig(); | ||
if (min_tracking_bytes > 0) { | ||
config.set_minimum_account_to_track_power_of_two(absl::bit_width(min_tracking_bytes)); |
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.
Could you take minimum_account_to_track_power_of_two as a constructor argument instead of min_tracking_bytes?
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.
Done.
|
||
TEST(WatermarkBufferFactoryTest, DefaultsToTrackingAccountsGreaterThanOrEqualTo256KB) { | ||
TrackedWatermarkBufferFactory factory; | ||
EXPECT_EQ(factory.bitshift(), 18); |
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.
It seems like the previous 2 test cases are testing the behavior of a test-only class.
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 invoke the WatermarkBufferFactory ctor directly now.
// 2^(minimum_account_to_track_power_of_two + 1)) bytes. | ||
// With the 8th bucket tracking accounts | ||
// >= 128 * 2^minimum_account_to_track_power_of_two. | ||
uint32 minimum_account_to_track_power_of_two = 1 [(validate.rules).uint32 = {lte: 63 gt: 0}]; |
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.
Setting the exponent to 1 may not produce great results either since it would only track up to 128 bytes, don't know if it would be worth using a more reasonable floor like 1024 bytes.
Setting to 63 effectively disables all tracking since it would result in a bit shift that would 0 out all reasonable buffer byte sizes. I guess this is a reasonable max.
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.
Floor is now 1024 bytes.
// [2^minimum_account_to_track_power_of_two, | ||
// 2^(minimum_account_to_track_power_of_two + 1)) bytes. | ||
// With the 8th bucket tracking accounts | ||
// >= 128 * 2^minimum_account_to_track_power_of_two. |
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 should describe the default behavior. Another related question is what the default behavior should be: Some specific value or no resource tracking.
"No resource tracking" seems like the more reasonable default.
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.
Done the default is to effectively disable tracking.
@@ -642,3 +644,16 @@ message CustomInlineHeader { | |||
// The type of the header that is expected to be set as the inline header. | |||
InlineHeaderType inline_header_type = 2 [(validate.rules).enum = {defined_only: true}]; | |||
} | |||
|
|||
// Configuration for the Buffer Factories that create Buffers and Accounts. | |||
message BufferFactoryConfig { |
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.
How about having these parameters are part of the toplevel OverloadManager proto since they are related to that functional area? The OverloadManager proto is already a parsed member in the bootstrap. The config option would go here:
google.protobuf.Duration refresh_interval = 1; |
default behavior to not track. Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
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.
Thanks for the review @antoniovicente
@@ -206,6 +212,7 @@ class WatermarkBufferFactory : public WatermarkFactory { | |||
using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>, | |||
BufferMemoryAccountImpl::NUM_MEMORY_CLASSES_>; | |||
MemoryClassesToAccountsSet size_class_account_sets_; | |||
uint32_t bitshift_; |
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.
Done.
: WatermarkBufferFactory([min_tracking_bytes]() { | ||
auto config = envoy::config::bootstrap::v3::ResourceTrackingConfig::BufferFactoryConfig(); | ||
if (min_tracking_bytes > 0) { | ||
config.set_minimum_account_to_track_power_of_two(absl::bit_width(min_tracking_bytes)); |
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.
Done.
// 2^(minimum_account_to_track_power_of_two + 1)) bytes. | ||
// With the 8th bucket tracking accounts | ||
// >= 128 * 2^minimum_account_to_track_power_of_two. | ||
uint32 minimum_account_to_track_power_of_two = 1 [(validate.rules).uint32 = {lte: 63 gt: 0}]; |
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.
Floor is now 1024 bytes.
// [2^minimum_account_to_track_power_of_two, | ||
// 2^(minimum_account_to_track_power_of_two + 1)) bytes. | ||
// With the 8th bucket tracking accounts | ||
// >= 128 * 2^minimum_account_to_track_power_of_two. |
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.
Done the default is to effectively disable tracking.
|
||
TEST(WatermarkBufferFactoryTest, DefaultsToTrackingAccountsGreaterThanOrEqualTo256KB) { | ||
TrackedWatermarkBufferFactory factory; | ||
EXPECT_EQ(factory.bitshift(), 18); |
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 invoke the WatermarkBufferFactory ctor directly now.
@@ -642,3 +644,16 @@ message CustomInlineHeader { | |||
// The type of the header that is expected to be set as the inline header. | |||
InlineHeaderType inline_header_type = 2 [(validate.rules).enum = {defined_only: true}]; | |||
} | |||
|
|||
// Configuration for the Buffer Factories that create Buffers and Accounts. | |||
message BufferFactoryConfig { |
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.
Done, moved to top level of the Overload Manager config.
/retest |
Retrying Azure Pipelines: |
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.
/wait
// With the 8th bucket tracking accounts | ||
// >= 128 * 2^minimum_account_to_track_power_of_two. | ||
// | ||
// Setting this to 63 effectively disables all tracking since the resulting |
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.
Shouldn't this be 64 - 8 = 56 ? Otherwise some higher order buckets will not be tracked.
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.
sgtm will set the max to in pgv to 56 as that's the last valid config that'd use all 8 buckets (56-63). Don't expect that we'll have any buffers using 2^56 bytes in practice.
Omitting the field effectively disables it.
/** | ||
* @return the bootstrap Envoy started with. | ||
*/ | ||
virtual const envoy::config::bootstrap::v3::Bootstrap& bootstrap() const PURE; |
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 think dispatchers are always allocated through the Api interface. In this case you do not need this method. Just save the bootstrap in the ApiImpl and then pass buffer config to the dispatcher constructor.
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.
Dispatchers are created outside of the Api interface in certain places.
Given that the Api has the information, and is already plumbed through the 3 ctors of the dispatcher, avoiding telescoping ctor by having the object with the information expose it seemed like the way to go.
Signed-off-by: Kevin Baichoo <[email protected]>
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.
Thanks for the review @yanavlasov
// With the 8th bucket tracking accounts | ||
// >= 128 * 2^minimum_account_to_track_power_of_two. | ||
// | ||
// Setting this to 63 effectively disables all tracking since the resulting |
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.
sgtm will set the max to in pgv to 56 as that's the last valid config that'd use all 8 buckets (56-63). Don't expect that we'll have any buffers using 2^56 bytes in practice.
Omitting the field effectively disables it.
/** | ||
* @return the bootstrap Envoy started with. | ||
*/ | ||
virtual const envoy::config::bootstrap::v3::Bootstrap& bootstrap() const PURE; |
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.
Dispatchers are created outside of the Api interface in certain places.
Given that the Api has the information, and is already plumbed through the 3 ctors of the dispatcher, avoiding telescoping ctor by having the object with the information expose it seemed like the way to go.
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.
Thanks.
@htuch for api-review round 2 |
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.
/lgtm api
- refactoring `ProcessImpl`, creating a named constructor that allows us to create bootstrap initially and pass it to `Envoy::Api::Impl()` as required since envoyproxy/envoy#17562. Specifically: - Moving method `ProcessImpl::determineConcurrency()` out of the ProcessImpl class so that it can be used during its construction. - Moving code that extracts URIs from `process_impl.cc` into `process_bootstrap.cc`. - Adding a previously missing test case `CreatesBootstrapForH1RespectingPortInUri` into `process_bootstrap_test.cc`. - Removing a TODO that incorrectly indicated URI DNS resolution is optional. Envoy [requires](https://github.com/envoyproxy/envoy/blob/716ee8abc526d51f07ed6d3c2a5aa8a3b2481d9d/api/envoy/config/core/v3/address.proto#L64-L67) resolved IPs in the Bootstrap for cluster of type STATIC. - Creating a named constructor for `ProcessImpl` that creates the `Envoy::Api::Api` with an empty Bootstrap that is then replaced with the one generated. See an inline comment for explanation. - Moving callers onto the named constructor and making the original constructor of `ProcessImpl` private. - no changes to `.bazelrc`, `.bazelversion`, `run_envoy_docker.sh`. Signed-off-by: Jakub Sobon <[email protected]>
…nvoyproxy#17562) Risk Level: low Testing: unit test Docs Changes: NA Release Notes: NA -- the feature isn't entirely user-facing. The documentation and release note changes are already finished in a PR that builds off of this. See: https://github.com/KBaichoo/envoy/pull/111/files#diff-c69815663eb82a9e98598ce5dc2c55bc7a4b0b180dd7fe188ef1227bdab9160c Related Issue envoyproxy#15791 Signed-off-by: Kevin Baichoo <[email protected]>
We can now configure the minimum account size to track.
Signed-off-by: Kevin Baichoo [email protected]
Commit Message: Buffer Factory: Configuration of the minimum account size to track.
Additional Description:
Risk Level: low
Testing: unit test
Docs Changes: NA
Release Notes: NA -- the feature isn't entirely user-facing. The documentation and release note changes are already finished in a PR that builds off of this. See: https://github.com/KBaichoo/envoy/pull/111/files#diff-c69815663eb82a9e98598ce5dc2c55bc7a4b0b180dd7fe188ef1227bdab9160c
Related Issue #15791