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

Limit initial window size increases and per-stream window delta #26342

Merged
merged 13 commits into from
Aug 9, 2021

Conversation

yashykt
Copy link
Member

@yashykt yashykt commented May 21, 2021

Internal bug reference b/179093825

gRPC Core at present does not consider the flow control windows of existing active streams when sending initial window updates. This can cause flow control windows to go beyond the max limit of 2^31-1 as determined by the HTTP2 spec. This PR fixes that by adding -

  1. an upper limit of 1 GB on the maximum initial window size
  2. an upper limit of 1 MB on per-stream window deltas

@yashykt yashykt added release notes: yes Indicates if PR needs to be in release notes lang/core labels May 21, 2021
@@ -309,7 +309,7 @@ class TransportFlowControl final : public TransportFlowControlBase {
return action;
}

const grpc_chttp2_transport* const t_;
Copy link
Member

Choose a reason for hiding this comment

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

why?

Copy link
Member Author

Choose a reason for hiding this comment

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

Iirc it's because grpc_chttp2_stream_map_for_each requires a non-const field. I can probably write a const version of it too though

Copy link
Member

Choose a reason for hiding this comment

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

I think that would be preferable... just to limit the scope of potential mutations.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can track some kind of crude approximation and recheck iff that approximation says we'd overflow?

Copy link
Member Author

Choose a reason for hiding this comment

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

Is this really that much though? Internally, I've seen 100 as the number being thrown around as the configuration for maximum number of concurrent streams?

If it is an issue, we could probably say something like - the initial window size can only grow as much as half the maximum flow control window and a similar restriction on the window delta.

// delta. Min has a ceiling of 0, while max has a floor of 0.
WindowDelta ComputeLocalWindowDeltaBoundaries(grpc_chttp2_transport* t) {
WindowDelta delta;
grpc_chttp2_stream_map_for_each(&t->stream_map,
Copy link
Member

Choose a reason for hiding this comment

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

does this change the update from O(1) to O(N)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it does unfortunately. I wonder if there is a way to do this without adding an O(N) loop

Copy link
Member

Choose a reason for hiding this comment

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

I wonder too... as it is this feels a little risky in terms of CPU usage.

Copy link
Member Author

@yashykt yashykt left a comment

Choose a reason for hiding this comment

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

Also, there is a remaining change that I'm trying to push but running into proxy issues. The change is to do with also limiting stream flow control window updates.

(PS: Thanks for taking a look :))

// delta. Min has a ceiling of 0, while max has a floor of 0.
WindowDelta ComputeLocalWindowDeltaBoundaries(grpc_chttp2_transport* t) {
WindowDelta delta;
grpc_chttp2_stream_map_for_each(&t->stream_map,
Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it does unfortunately. I wonder if there is a way to do this without adding an O(N) loop

@@ -309,7 +309,7 @@ class TransportFlowControl final : public TransportFlowControlBase {
return action;
}

const grpc_chttp2_transport* const t_;
Copy link
Member Author

Choose a reason for hiding this comment

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

Iirc it's because grpc_chttp2_stream_map_for_each requires a non-const field. I can probably write a const version of it too though

@ctiller
Copy link
Member

ctiller commented Jul 27, 2021

I'm super uncomfortable with expanding this mechanism to become O(n) - especially since doing so will make the flow control mechanism that we use when under duress more expensive.

Instead, can I propose we split the flow control windows into two budgets: one for initial window, the other per stream, and we bound each to something extreme but sensible (order 100MB springs to mind, 10MB may be a better default).

At that point, we disallow advertising over budget, eliminating the possibility of this condition occuring.

@yashykt
Copy link
Member Author

yashykt commented Aug 4, 2021

@ctiller PTALA

Copy link
Member

@ctiller ctiller left a comment

Choose a reason for hiding this comment

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

This is fairly difficult to reason through whether it's correct.
Can you please write a unit test demonstrating that it has the desired behaviors?

@yashykt yashykt changed the title Limit initial window size increases by flow control windows of active streams Limit initial window size increases and per-stream window delta Aug 4, 2021
@yashykt
Copy link
Member Author

yashykt commented Aug 4, 2021

Tests added. (There is an internal stress test that helps to verify the behavior too.)

@ctiller
Copy link
Member

ctiller commented Aug 4, 2021

My memory was that we had an isolated unit test for flow_control.cc, but searching history reveals no such test - perhaps it was started and never completed. I don't think there's any sense in blocking this work on that right now, but it seems this code is ripe for an explicit test that says "if this state changes, this action is performed" so that we can track changes in behavior here.

@yashykt
Copy link
Member Author

yashykt commented Aug 9, 2021

Known issues: #26595

@yashykt yashykt merged commit 3e197ac into grpc:master Aug 9, 2021
dennycd pushed a commit to dennycd/grpc that referenced this pull request Aug 10, 2021
…#26342)

* Limit initial window size increases/decreases by flow control windows of active streams

* Limit stream flow control window updates to maximum allowable

* Reviewer comments

* Alternative way

* Clean-up

* Add tests

* Remove unnecessary cq_verifier

* Generate projects

* Initialize recv_message

* Get around compilation issue

* Test size large
Vignesh2208 pushed a commit to Vignesh2208/grpc that referenced this pull request Aug 20, 2021
…#26342)

* Limit initial window size increases/decreases by flow control windows of active streams

* Limit stream flow control window updates to maximum allowable

* Reviewer comments

* Alternative way

* Clean-up

* Add tests

* Remove unnecessary cq_verifier

* Generate projects

* Initialize recv_message

* Get around compilation issue

* Test size large
veblush added a commit to veblush/grpc that referenced this pull request Sep 9, 2021
lidizheng pushed a commit to lidizheng/grpc that referenced this pull request Sep 23, 2021
…#26342)

* Limit initial window size increases/decreases by flow control windows of active streams

* Limit stream flow control window updates to maximum allowable

* Reviewer comments

* Alternative way

* Clean-up

* Add tests

* Remove unnecessary cq_verifier

* Generate projects

* Initialize recv_message

* Get around compilation issue

* Test size large
@yashykt yashykt deleted the chttp2windowbug branch May 18, 2023 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lang/core release notes: yes Indicates if PR needs to be in release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants