-
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
Send connection WINDOW_UPDATE before RTT PING #97881
Changes from 2 commits
6af5b27
63c5ebd
7064b1f
2701197
e93920a
82214a9
4928f3c
ccdcdb3
c75d736
b3ec201
e82fee2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -138,13 +138,18 @@ private void AdjustWindowDynamic(int bytesConsumed, Http2Stream stream) | |||||||||||||||||
// Assuming that the network characteristics of the connection wouldn't change much within its lifetime, we are maintaining a running minimum value. | ||||||||||||||||||
// The more PINGs we send, the more accurate is the estimation of MinRtt, however we should be careful not to send too many of them, | ||||||||||||||||||
// to avoid triggering the server's PING flood protection which may result in an unexpected GOAWAY. | ||||||||||||||||||
// With most servers we are fine to send PINGs, as long as we are reading their data, this rule is well formalized for gRPC: | ||||||||||||||||||
// | ||||||||||||||||||
// Several strategies have been implemented to conform with real life servers. | ||||||||||||||||||
// 1. With most servers we are fine to send PINGs as long as we are reading their data, a rule formalized by a gRPC spec: | ||||||||||||||||||
// https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md | ||||||||||||||||||
// As a rule of thumb, we can send send a PING whenever we receive DATA or HEADERS, however, there are some servers which allow receiving only | ||||||||||||||||||
// a limited amount of PINGs within a given timeframe. | ||||||||||||||||||
// To deal with the conflicting requirements: | ||||||||||||||||||
// - We send an initial burst of 'InitialBurstCount' PINGs, to get a relatively good estimation fast | ||||||||||||||||||
// - Afterwards, we send PINGs with the maximum frequency of 'PingIntervalInSeconds' PINGs per second | ||||||||||||||||||
// According to this rule, we are OK to send a PING whenever we receive DATA or HEADERS, since the servers conforming to this doc | ||||||||||||||||||
// will reset their unsolicited ping counter whenever they *send* DATA or HEADERS. | ||||||||||||||||||
// 2. Some servers allow receiving only a limited amount of PINGs within a given timeframe. | ||||||||||||||||||
// To deal with this, we send an initial burst of 'InitialBurstCount' (=4) PINGs, to get a relatively good estimation fast. Afterwards, | ||||||||||||||||||
// we send PINGs each 'PingIntervalInSeconds' second, to maintain our estimation without triggering these servers. | ||||||||||||||||||
// 3. Some servers in Google's backends reset their unsolicited ping counter when they *receive* DATA, HEADERS, or WINDOW_UPDATE. | ||||||||||||||||||
// To deal with this, we need to make sure to send a connection WINDOW_UPDATE before sending a PING. The initial burst is an exception | ||||||||||||||||||
// to this rule, since the mentioned server can tolerate 4 PINGs without receiving a WINDOW_UPDATE. | ||||||||||||||||||
// | ||||||||||||||||||
// Threading: | ||||||||||||||||||
// OnInitialSettingsSent() is called during initialization, all other methods are triggered by HttpConnection.ProcessIncomingFramesAsync(), | ||||||||||||||||||
|
@@ -194,7 +199,7 @@ internal void OnInitialSettingsAckReceived(Http2Connection connection) | |||||||||||||||||
_state = State.Waiting; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
internal void OnDataOrHeadersReceived(Http2Connection connection) | ||||||||||||||||||
internal void OnDataOrHeadersReceived(Http2Connection connection, bool sendWindowUpdateBeforePing) | ||||||||||||||||||
{ | ||||||||||||||||||
if (_state != State.Waiting) return; | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -204,6 +209,14 @@ internal void OnDataOrHeadersReceived(Http2Connection connection) | |||||||||||||||||
{ | ||||||||||||||||||
if (initial) _initialBurst--; | ||||||||||||||||||
|
||||||||||||||||||
// When sendWindowUpdateBeforePing is true, try to send a WINDOW_UPDATE to make Google backends happy. | ||||||||||||||||||
// Unless we are doing the initial burst, do not send PING if we were not able to send the WINDOW_UPDATE. | ||||||||||||||||||
// See point 3. in the comments above the class definition for more info. | ||||||||||||||||||
if (sendWindowUpdateBeforePing && !connection.ForceSendConnectionWindowUpdate() && !initial) | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where are places that can send a windows update? Can a connection be in the situation where a window update is always being sent somewhere else and when it comes time to send a ping, the pending window update is always empty? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For connection window the standard method is
Note that receiving DATA triggers runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs Lines 772 to 779 in 7064b1f
JamesNK marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
{ | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
// Send a PING | ||||||||||||||||||
_pingCounter--; | ||||||||||||||||||
if (NetEventSource.Log.IsEnabled()) connection.Trace($"[FlowControl] Sending RTT PING with payload {_pingCounter}"); | ||||||||||||||||||
|
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.
ExtendWindow
has unnecessary synchronization around_pendingWindowUpdate
manipulation which is didn't add to this method. See #97878.