value, which generally provides good results without having to tweak
the configuration any further.
+ - min <number>:
+ This sets the minimum advertised concurrency level when rq-load is used,
+ even if this results in a higher load than the configured target. This
+ allows to maintain a good level of interactivity on a site under very
+ heavy load. The minimum and default value is 1, but values between 5
+ and 15 can improve user experience.
+
+ Example:
+
+ tune.h2.fe.max-concurrent-streams 100 rq-load auto min 15
+
tune.h2.fe.max-total-streams <number>
Sets the HTTP/2 maximum number of total streams processed per incoming
connection. Once this limit is reached, HAProxy will send a graceful GOAWAY
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_min_concurrent_streams = 1; /* minimum concurrent streams when using rq-load */
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;
*/
if (load > limit)
ret = (uint64_t)ret * limit / load * limit / load;
- ret = ret ? ret : 1;
+ if (ret < h2_fe_min_concurrent_streams)
+ ret = h2_fe_min_concurrent_streams;
}
return ret;
}
char **err)
{
uint *vptr;
+ int arg;
/* backend/frontend/default */
vptr = (args[0][8] == 'b') ? &h2_be_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))
+ if (args[0][8] != 'f' && too_many_args(1, args, err, NULL))
return -1;
*vptr = atoi(args[1]);
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]);
+ for (arg = 2; *args[arg]; arg += 2) {
+ if (strcmp(args[arg], "rq-load") == 0) {
+ if (strcmp(args[arg + 1], "ignore") == 0)
+ h2_fe_max_rq_load = ~0;
+ else if (strcmp(args[arg + 1], "auto") == 0)
+ h2_fe_max_rq_load = 0;
+ else if (!*args[arg + 1] || (h2_fe_max_rq_load = atoi(args[arg + 1])) <= 0) {
+ memprintf(err, "'%s' expects a strictly positive run-queue length, or 'auto' or 'ignore'.", args[0]);
+ return -1;
+ }
+ }
+ else if (strcmp(args[arg], "min") == 0) {
+ if (!*args[arg + 1] || (h2_fe_min_concurrent_streams = atoi(args[arg + 1])) <= 0) {
+ memprintf(err, "'%s' expects a strictly positive minimum number of streams'.", args[0]);
+ return -1;
+ }
+
+ if (h2_fe_min_concurrent_streams > h2_fe_settings_max_concurrent_streams) {
+ memprintf(err, "'%s' minimum number of streams (%u) cannot be higher than the maximum (%u)'.",
+ args[0], h2_fe_min_concurrent_streams, h2_fe_settings_max_concurrent_streams);
+ return -1;
+ }
+ }
+ else if (*args[arg]) {
+ memprintf(err, "'%s' only supports 'rq-load' or 'min' after the numeric value, but found '%s'.", args[0], args[arg]);
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;
}