MINOR: mux-h2: make the initial window size configurable per side

For a long time the initial window size (per-stream size) was set once
for both directions, frontend and backend, resulting in a tradeoff between
upload speed and download fairness. This commit allows it to be configured
separately for each side. The older settings remains the fallback choice
when other ones are not set.
This commit is contained in:
Willy Tarreau 2023-04-17 15:04:34 +02:00
parent b36e512bd0
commit 9d7abda787
2 changed files with 55 additions and 14 deletions

View File

@ -2885,6 +2885,28 @@ tune.fd.edge-triggered { on | off } [ EXPERIMENTAL ]
certain scenarios. This is still experimental, it may result in frozen
connections if bugs are still present, and is disabled by default.
tune.h2.be.initial-window-size <number>
Sets the HTTP/2 initial window size for outgoing connections, which is the
number of bytes the server can respond before waiting for an acknowledgment
from HAProxy. This setting only affects payload contents, not headers. When
not set, the common default value set by tune.h2.initial-window-size applies.
It can make sense to slightly increase this value to allow faster downloads
or to reduce CPU usage on the servers, at the expense of creating unfairness
between clients. It doesn't affect resource usage.
See also: tune.h2.initial-window-size.
tune.h2.fe.initial-window-size <number>
Sets the HTTP/2 initial window size for incoming connections, which is the
number of bytes the client can upload before waiting for an acknowledgment
from HAProxy. This setting only affects payload contents (i.e. the body of
POST requests), not headers. When not set, the common default value set by
tune.h2.initial-window-size applies. It can make sense to increase this value
to allow faster uploads. The default value of 65536 allows up to 5 Mbps of
bandwidth per client over a 100 ms ping time, and 500 Mbps for 1 ms ping
time. It doesn't affect resource usage. Using too large values may cause
clients to experience a lack of responsiveness if pages are accessed in
parallel to large uploads. See also: tune.h2.initial-window-size.
tune.h2.header-table-size <number>
Sets the HTTP/2 dynamic header table size. It defaults to 4096 bytes and
cannot be larger than 65536 bytes. A larger value may help certain clients
@ -2893,14 +2915,16 @@ tune.h2.header-table-size <number>
change it.
tune.h2.initial-window-size <number>
Sets the HTTP/2 initial window size, which is the number of bytes the client
can upload before waiting for an acknowledgment from HAProxy. This setting
only affects payload contents (i.e. the body of POST requests), not headers.
The default value is 65536, which roughly allows up to 5 Mbps of upload
bandwidth per client over a network showing a 100 ms ping time, or 500 Mbps
over a 1-ms local network. It can make sense to increase this value to allow
faster uploads, or to reduce it to increase fairness when dealing with many
clients. It doesn't affect resource usage.
Sets the default value for the HTTP/2 initial window size, on both incoming
and outgoing connections. This value is used for incoming connections when
tune.h2.fe.initial-window-size is not set, and by outgoing connections when
tune.h2.be.initial-window-size is not set. The default value is 65536, which
for uploads roughly allows up to 5 Mbps of bandwidth per client over a
network showing a 100 ms ping time, or 500 Mbps over a 1-ms local network.
Given that changing the default value will both increase upload speeds and
cause more unfairness between clients on downloads, it is recommended to
instead use the side-specific settings tune.h2.fe.initial-window-size and
tune.h2.be.initial-window-size.
tune.h2.max-concurrent-streams <number>
Sets the HTTP/2 maximum number of concurrent streams per connection (ie the

View File

@ -403,7 +403,9 @@ DECLARE_STATIC_POOL(pool_head_h2s, "h2s", sizeof(struct h2s));
/* a few settings from the global section */
static int h2_settings_header_table_size = 4096; /* initial value */
static int h2_settings_initial_window_size = 65536; /* initial value */
static int h2_settings_initial_window_size = 65536; /* default initial value */
static int h2_be_settings_initial_window_size = 0; /* backend's default initial value */
static int h2_fe_settings_initial_window_size = 0; /* frontend's default initial value */
static unsigned int h2_settings_max_concurrent_streams = 100;
static int h2_settings_max_frame_size = 0; /* unset */
@ -1641,6 +1643,7 @@ static int h2c_send_settings(struct h2c *h2c)
struct buffer *res;
char buf_data[100]; // enough for 15 settings
struct buffer buf;
int iws;
int mfs;
int ret = 0;
@ -1670,10 +1673,15 @@ static int h2c_send_settings(struct h2c *h2c)
chunk_memcat(&buf, str, 6);
}
if (h2_settings_initial_window_size != 65535) {
iws = (h2c->flags & H2_CF_IS_BACK) ?
h2_be_settings_initial_window_size:
h2_fe_settings_initial_window_size;
iws = iws ? iws : h2_settings_initial_window_size;
if (iws != 65535) {
char str[6] = "\x00\x04"; /* initial_window_size */
write_n32(str + 2, h2_settings_initial_window_size);
write_n32(str + 2, iws);
chunk_memcat(&buf, str, 6);
}
@ -6893,16 +6901,23 @@ static int h2_parse_header_table_size(char **args, int section_type, struct prox
return 0;
}
/* config parser for global "tune.h2.initial-window-size" */
/* config parser for global "tune.h2.{be.,fe.,}initial-window-size" */
static int h2_parse_initial_window_size(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
int *vptr;
if (too_many_args(1, args, err, NULL))
return -1;
h2_settings_initial_window_size = atoi(args[1]);
if (h2_settings_initial_window_size < 0) {
/* backend/frontend/default */
vptr = (args[0][8] == 'b') ? &h2_be_settings_initial_window_size :
(args[0][8] == 'f') ? &h2_fe_settings_initial_window_size :
&h2_settings_initial_window_size;
*vptr = atoi(args[1]);
if (*vptr < 0) {
memprintf(err, "'%s' expects a positive numeric value.", args[0]);
return -1;
}
@ -6977,6 +6992,8 @@ INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_h2);
/* config keyword parsers */
static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "tune.h2.be.initial-window-size", h2_parse_initial_window_size },
{ CFG_GLOBAL, "tune.h2.fe.initial-window-size", h2_parse_initial_window_size },
{ CFG_GLOBAL, "tune.h2.header-table-size", h2_parse_header_table_size },
{ CFG_GLOBAL, "tune.h2.initial-window-size", h2_parse_initial_window_size },
{ CFG_GLOBAL, "tune.h2.max-concurrent-streams", h2_parse_max_concurrent_streams },