See also: tune.h2.initial-window-size.
-tune.h2.fe.max-concurrent-streams <number>
+tune.h2.fe.max-concurrent-streams <number> [args...]
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
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.
+ generally good and it is recommended not to change this value. A larger
+ concurrency also has an impact on the processing load and latency when
+ dealing with large numbers of connections which are themselves using many
+ streams, and it may lower the barrier to denial of service attacks. The
+ command supports the following optional arguments after the number:
+
+ - rq-load { <number> | auto | ignore }:
+ The optional argument "rq-load" permits to dynamically adjust the
+ advertised concurrency based on the executing thread's run-queue load:
+ as long as the thread's load remains below the indicated threshold, the
+ configured streams limit will be advertised. When the thread's load
+ increases beyond the configured limit, the advertised streams limit will be
+ decreased proportionally to the square of the excess ratio. Target load
+ levels between 50 and 100 generally show very good moderation under heavy
+ loads. Alternately, instead of specifying an explicit number, the keyword
+ accepts "ignore", which is the default and means that the thread's
+ run-queue load will not be considered to moderate the advertised streams
+ limit, and "auto", which sets the limit to the "tune.runqueue-depth"
+ value, which generally provides good results without having to tweak
+ the configuration any further.
tune.h2.fe.max-total-streams <number>
Sets the HTTP/2 maximum number of total streams processed per incoming
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 unsigned int h2_fe_max_rq_load = ~0; /* max rq for FE dynamic MCS sizing. 0=def rq */
static int h2_settings_max_frame_size = 0; /* unset */
static int h2_settings_log_errors = H2_ERR_LOG_ERR_STRM;
h2_fe_settings_max_concurrent_streams;
ret = ret ? ret : h2_settings_max_concurrent_streams;
+
+ /* if h2_fe_max_rq_load is set, adjust the max concurrent streams
+ * according to it and the current load.
+ */
+ if (!(h2c->flags & H2_CF_IS_BACK) && h2_fe_max_rq_load != ~0) {
+ uint limit = h2_fe_max_rq_load ? h2_fe_max_rq_load : global.tune.runqueue_depth;
+ uint load = MAX(swrate_avg(th_ctx->rq_tot_peak, RQ_LOAD_SAMPLES), th_ctx->rq_total);
+
+ /* divide limits by the square of the ratio of current load to
+ * the limit so as to react fast.
+ */
+ if (load > limit)
+ ret = (uint64_t)ret * limit / load * limit / load;
+ ret = ret ? ret : 1;
+ }
return ret;
}
{
uint *vptr;
- if (too_many_args(1, args, err, NULL))
- return -1;
-
/* 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;
+
+ if ((args[0][8] != 'f' && too_many_args(1, args, err, NULL)) ||
+ too_many_args(3, args, err, NULL))
+ return -1;
+
*vptr = atoi(args[1]);
if ((int)*vptr < 0) {
memprintf(err, "'%s' expects a positive numeric value.", args[0]);
return -1;
}
+
+ if (args[0][8] != 'f')
+ goto leave;
+
+ /* tune.h2.fe. here */
+ if (strcmp(args[2], "rq-load") == 0) {
+ if (strcmp(args[3], "ignore") == 0)
+ h2_fe_max_rq_load = ~0;
+ else if (strcmp(args[3], "auto") == 0)
+ h2_fe_max_rq_load = 0;
+ else if (!*args[3] || (h2_fe_max_rq_load = atoi(args[3])) <= 0) {
+ memprintf(err, "'%s' expects a strictly positive run-queue length, or 'auto' or 'ignore'.", args[0]);
+ return -1;
+ }
+ }
+ else if (*args[2]) {
+ memprintf(err, "'%s' only supports 'rq-load' after the numeric value, but found '%s'.", args[0], args[2]);
+ return -1;
+ }
+
+ leave:
return 0;
}