diff --git a/doc/configuration.txt b/doc/configuration.txt index 3adab3487..082102b9e 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 + 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 + 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 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 change it. tune.h2.initial-window-size - 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 Sets the HTTP/2 maximum number of concurrent streams per connection (ie the diff --git a/src/mux_h2.c b/src/mux_h2.c index 2f06db8dc..3510c3b24 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -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 },