mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-31 23:58:16 +00:00
MINOR: mux-h2: make the max number of concurrent streams configurable per side
For a long time the maximum number of concurrent streams was set once for both sides (front and back) while the impacts are different. 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:
parent
9d7abda787
commit
ca1027c22f
@ -2895,6 +2895,20 @@ tune.h2.be.initial-window-size <number>
|
||||
between clients. It doesn't affect resource usage.
|
||||
See also: tune.h2.initial-window-size.
|
||||
|
||||
tune.h2.be.max-concurrent-streams <number>
|
||||
Sets the HTTP/2 maximum number of concurrent streams per outgoing connection
|
||||
(i.e. the number of outstanding requests on a single connection to a server).
|
||||
When not set, the default set by tune.h2.max-concurrent-streams applies. A
|
||||
smaller value than the default 100 may improve a site's responsiveness at the
|
||||
expense of maintaining more established connections to the servers. When the
|
||||
"http-reuse" setting is set to "always", it is recommended to reduce this
|
||||
value so as not to mix too many different clients over the same connection,
|
||||
because if a client is slower than others, a mechanism known as "head of
|
||||
line blocking" tends to cause cascade effect on download speed for all
|
||||
clients sharing a connection (keep tune.h2.be.initial-window-size low in this
|
||||
case). It is highly recommended not to increase this value; some might find
|
||||
it optimal to run at low values (1..5 typically).
|
||||
|
||||
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
|
||||
@ -2907,6 +2921,16 @@ tune.h2.fe.initial-window-size <number>
|
||||
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.fe.max-concurrent-streams <number>
|
||||
Sets the HTTP/2 maximum number of concurrent streams per incoming connection
|
||||
(i.e. the number of outstanding requests on a single connection from a
|
||||
client). When not set, the default set by tune.h2.max-concurrent-streams
|
||||
applies. A larger value than the default 100 may sometimes slightly improve
|
||||
the page load time for complex sites with lots of small objects over high
|
||||
latency networks but can also result in using more memory by allowing a
|
||||
client to allocate more resources at once. The default value of 100 is
|
||||
generally good and it is recommended not to change this value.
|
||||
|
||||
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
|
||||
@ -2927,13 +2951,15 @@ tune.h2.initial-window-size <number>
|
||||
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
|
||||
number of outstanding requests on a single connection). The default value is
|
||||
100. A larger one may slightly improve page load time for complex sites when
|
||||
visited over high latency networks, but increases the amount of resources a
|
||||
single client may allocate. A value of zero disables the limit so a single
|
||||
client may create as many streams as allocatable by HAProxy. It is highly
|
||||
recommended not to change this value.
|
||||
Sets the default HTTP/2 maximum number of concurrent streams per connection
|
||||
(i.e. the number of outstanding requests on a single connection). Ths value
|
||||
is used for incoming connections when tune.h2.fe.max-concurrent-streams is
|
||||
not set, and for outgoing connections when tune.h2.be.max-concurrent-streams
|
||||
is not set. The default value is 100. The impact varies depending on the side
|
||||
so please see the two settings above for more details. It is recommended not
|
||||
to use this setting and to switch to the per-side ones instead. A value of
|
||||
zero disables the limit so a single client may create as many streams as
|
||||
allocatable by HAProxy. It is highly recommended not to change this value.
|
||||
|
||||
tune.h2.max-frame-size <number>
|
||||
Sets the HTTP/2 maximum frame size that HAProxy announces it is willing to
|
||||
|
52
src/mux_h2.c
52
src/mux_h2.c
@ -406,7 +406,9 @@ static int h2_settings_header_table_size = 4096; /* 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 unsigned int h2_settings_max_concurrent_streams = 100; /* default value */
|
||||
static unsigned int h2_be_settings_max_concurrent_streams = 0; /* backend value */
|
||||
static unsigned int h2_fe_settings_max_concurrent_streams = 0; /* frontend value */
|
||||
static int h2_settings_max_frame_size = 0; /* unset */
|
||||
|
||||
/* a dummy closed endpoint */
|
||||
@ -572,6 +574,23 @@ static inline int h2c_may_expire(const struct h2c *h2c)
|
||||
return !h2c->nb_sc;
|
||||
}
|
||||
|
||||
/* returns the number of max concurrent streams permitted on a connection,
|
||||
* depending on its side (frontend or backend), falling back to the default
|
||||
* h2_settings_max_concurrent_streams. It may even be zero.
|
||||
*/
|
||||
static inline int h2c_max_concurrent_streams(const struct h2c *h2c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = (h2c->flags & H2_CF_IS_BACK) ?
|
||||
h2_be_settings_max_concurrent_streams :
|
||||
h2_fe_settings_max_concurrent_streams;
|
||||
|
||||
ret = ret ? ret : h2_settings_max_concurrent_streams;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* update h2c timeout if needed */
|
||||
static void h2c_update_timeout(struct h2c *h2c)
|
||||
{
|
||||
@ -715,7 +734,7 @@ static inline void h2c_restart_reading(const struct h2c *h2c, int consider_buffe
|
||||
/* returns true if the front connection has too many stream connectors attached */
|
||||
static inline int h2_frt_has_too_many_sc(const struct h2c *h2c)
|
||||
{
|
||||
return h2c->nb_sc > h2_settings_max_concurrent_streams;
|
||||
return h2c->nb_sc > h2c_max_concurrent_streams(h2c);
|
||||
}
|
||||
|
||||
/* Tries to grab a buffer and to re-enable processing on mux <target>. The h2c
|
||||
@ -1001,7 +1020,7 @@ static int h2_init(struct connection *conn, struct proxy *prx, struct session *s
|
||||
/* Initialise the context. */
|
||||
h2c->st0 = H2_CS_PREFACE;
|
||||
h2c->conn = conn;
|
||||
h2c->streams_limit = h2_settings_max_concurrent_streams;
|
||||
h2c->streams_limit = h2c_max_concurrent_streams(h2c);
|
||||
h2c->max_id = -1;
|
||||
h2c->errcode = H2_ERR_NO_ERROR;
|
||||
h2c->rcvd_c = 0;
|
||||
@ -1528,7 +1547,7 @@ static struct h2s *h2c_frt_stream_new(struct h2c *h2c, int id, struct buffer *in
|
||||
|
||||
TRACE_ENTER(H2_EV_H2S_NEW, h2c->conn);
|
||||
|
||||
if (h2c->nb_streams >= h2_settings_max_concurrent_streams) {
|
||||
if (h2c->nb_streams >= h2c_max_concurrent_streams(h2c)) {
|
||||
TRACE_ERROR("HEADERS frame causing MAX_CONCURRENT_STREAMS to be exceeded", H2_EV_H2S_NEW|H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn);
|
||||
goto out;
|
||||
}
|
||||
@ -1645,6 +1664,7 @@ static int h2c_send_settings(struct h2c *h2c)
|
||||
struct buffer buf;
|
||||
int iws;
|
||||
int mfs;
|
||||
int mcs;
|
||||
int ret = 0;
|
||||
|
||||
TRACE_ENTER(H2_EV_TX_FRAME|H2_EV_TX_SETTINGS, h2c->conn);
|
||||
@ -1685,13 +1705,14 @@ static int h2c_send_settings(struct h2c *h2c)
|
||||
chunk_memcat(&buf, str, 6);
|
||||
}
|
||||
|
||||
if (h2_settings_max_concurrent_streams != 0) {
|
||||
mcs = h2c_max_concurrent_streams(h2c);
|
||||
if (mcs != 0) {
|
||||
char str[6] = "\x00\x03"; /* max_concurrent_streams */
|
||||
|
||||
/* Note: 0 means "unlimited" for haproxy's config but not for
|
||||
* the protocol, so never send this value!
|
||||
*/
|
||||
write_n32(str + 2, h2_settings_max_concurrent_streams);
|
||||
write_n32(str + 2, mcs);
|
||||
chunk_memcat(&buf, str, 6);
|
||||
}
|
||||
|
||||
@ -2247,8 +2268,8 @@ static int h2c_handle_settings(struct h2c *h2c)
|
||||
case H2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
||||
if (h2c->flags & H2_CF_IS_BACK) {
|
||||
/* the limit is only for the backend; for the frontend it is our limit */
|
||||
if ((unsigned int)arg > h2_settings_max_concurrent_streams)
|
||||
arg = h2_settings_max_concurrent_streams;
|
||||
if ((unsigned int)arg > h2c_max_concurrent_streams(h2c))
|
||||
arg = h2c_max_concurrent_streams(h2c);
|
||||
h2c->streams_limit = arg;
|
||||
}
|
||||
break;
|
||||
@ -6924,16 +6945,23 @@ static int h2_parse_initial_window_size(char **args, int section_type, struct pr
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* config parser for global "tune.h2.max-concurrent-streams" */
|
||||
/* config parser for global "tune.h2.{be.,fe.,}max-concurrent-streams" */
|
||||
static int h2_parse_max_concurrent_streams(char **args, int section_type, struct proxy *curpx,
|
||||
const struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
uint *vptr;
|
||||
|
||||
if (too_many_args(1, args, err, NULL))
|
||||
return -1;
|
||||
|
||||
h2_settings_max_concurrent_streams = atoi(args[1]);
|
||||
if ((int)h2_settings_max_concurrent_streams < 0) {
|
||||
/* backend/frontend/default */
|
||||
vptr = (args[0][8] == 'b') ? &h2_be_settings_max_concurrent_streams :
|
||||
(args[0][8] == 'f') ? &h2_fe_settings_max_concurrent_streams :
|
||||
&h2_settings_max_concurrent_streams;
|
||||
|
||||
*vptr = atoi(args[1]);
|
||||
if ((int)*vptr < 0) {
|
||||
memprintf(err, "'%s' expects a positive numeric value.", args[0]);
|
||||
return -1;
|
||||
}
|
||||
@ -6993,7 +7021,9 @@ 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.be.max-concurrent-streams", h2_parse_max_concurrent_streams },
|
||||
{ CFG_GLOBAL, "tune.h2.fe.initial-window-size", h2_parse_initial_window_size },
|
||||
{ CFG_GLOBAL, "tune.h2.fe.max-concurrent-streams", h2_parse_max_concurrent_streams },
|
||||
{ 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 },
|
||||
|
Loading…
Reference in New Issue
Block a user