- maxcomprate
- maxcompcpuusage
- maxpipes
+ - maxsessrate
- maxsslconn
- noepoll
- nokqueue
The splice code dynamically allocates and releases pipes, and can fall back
to standard copy, so setting this value too low may only impact performance.
+maxsessrate <number>
+ Sets the maximum per-process number of sessions per second to <number>.
+ Proxies will stop accepting connections when this limit is reached. It can be
+ used to limit the global capacity regardless of each frontend capacity. It is
+ important to note that this can only be used as a service protection measure,
+ as there will not necessarily be a fair share between frontends when the
+ limit is reached, so it's a good idea to also limit each frontend to some
+ value close to its expected share. Also, lowering tune.maxaccept can improve
+ fairness.
+
maxsslconn <number>
Sets the maximum per-process number of concurrent SSL connections to
<number>. By default there is no SSL-specific limit, which means that the
passed in number of kilobytes per second. The value is available in the "show
info" on the line "CompressBpsRateLim" in bytes.
+set rate-limit sessions global <value>
+ Change the process-wide session rate limit, which is set by the global
+ 'maxsessrate' setting. A value of zero disables the limitation. This limit
+ applies to all frontends and the change has an immediate effect. The value
+ is passed in number of sessions per second.
+
set table <table> key <key> [data.<data_type> <value>]*
Create or update a stick-table entry in the table. If the key is not present,
an entry is inserted. See stick-table in section 4.2 to find all possible
char *connect_default_ciphers;
#endif
struct freq_ctr conn_per_sec;
+ struct freq_ctr sess_per_sec;
struct freq_ctr comp_bps_in; /* bytes per second, before http compression */
struct freq_ctr comp_bps_out; /* bytes per second, after http compression */
int cps_lim, cps_max;
+ int sps_lim, sps_max;
int comp_rate_lim; /* HTTP compression rate limit */
int maxpipes; /* max # of pipes */
int maxsock; /* max # of sockets */
}
global.cps_lim = atol(args[1]);
}
+ else if (!strcmp(args[0], "maxsessrate")) {
+ if (global.sps_lim != 0) {
+ Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
+ err_code |= ERR_ALERT;
+ goto out;
+ }
+ if (*(args[1]) == 0) {
+ Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ global.sps_lim = atol(args[1]);
+ }
else if (!strcmp(args[0], "maxcomprate")) {
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer argument in kb/s.\n", file, linenum, args[0]);
}
global.cps_max = 0;
+ global.sps_max = 0;
return 1;
}
else if (strcmp(args[1], "table") == 0) {
return 1;
}
}
+ else if (strcmp(args[2], "sessions") == 0) {
+ if (strcmp(args[3], "global") == 0) {
+ int v;
+
+ if (s->listener->bind_conf->level < ACCESS_LVL_ADMIN) {
+ appctx->ctx.cli.msg = stats_permission_denied_msg;
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ if (!*args[4]) {
+ appctx->ctx.cli.msg = "Expects an integer value.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ v = atoi(args[4]);
+ if (v < 0) {
+ appctx->ctx.cli.msg = "Value out of range.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ global.sps_lim = v;
+
+ /* Dequeues all of the listeners waiting for a resource */
+ if (!LIST_ISEMPTY(&global_listener_queue))
+ dequeue_all_listeners(&global_listener_queue);
+
+ return 1;
+ }
+ else {
+ appctx->ctx.cli.msg = "'set rate-limit sessions' only supports 'global'.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
else if (strcmp(args[2], "http-compression") == 0) {
if (strcmp(args[3], "global") == 0) {
int v;
}
}
else {
- appctx->ctx.cli.msg = "'set rate-limit' supports 'connections' and 'http-compression'.\n";
+ appctx->ctx.cli.msg = "'set rate-limit' supports 'connections', 'sessions', and 'http-compression'.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
"ConnRate: %d\n"
"ConnRateLimit: %d\n"
"MaxConnRate: %d\n"
+ "SessRate: %d\n"
+ "SessRateLimit: %d\n"
+ "MaxSessRate: %d\n"
"CompressBpsIn: %u\n"
"CompressBpsOut: %u\n"
"CompressBpsRateLim: %u\n"
#endif
global.maxpipes, pipes_used, pipes_free,
read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max,
+ read_freq_ctr(&global.sess_per_sec), global.sps_lim, global.sps_max,
read_freq_ctr(&global.comp_bps_in), read_freq_ctr(&global.comp_bps_out),
global.comp_rate_lim,
#ifdef USE_ZLIB
return;
}
- if (global.cps_lim && !(l->options & LI_O_UNLIMITED)) {
+ if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) {
+ int max = freq_ctr_remain(&global.sess_per_sec, global.sps_lim, 0);
+ int expire;
+
+ if (unlikely(!max)) {
+ /* frontend accept rate limit was reached */
+ limit_listener(l, &global_listener_queue);
+ expire = tick_add(now_ms, next_event_delay(&global.sess_per_sec, global.sps_lim, 0));
+ task_schedule(global_listener_queue_task, tick_first(expire, global_listener_queue_task->expire));
+ return;
+ }
+
+ if (max_accept > max)
+ max_accept = max;
+ }
+
+ if (!(l->options & LI_O_UNLIMITED) && global.cps_lim) {
int max = freq_ctr_remain(&global.conn_per_sec, global.cps_lim, 0);
+ int expire;
if (unlikely(!max)) {
/* frontend accept rate limit was reached */
limit_listener(l, &global_listener_queue);
- task_schedule(global_listener_queue_task, tick_add(now_ms, next_event_delay(&global.conn_per_sec, global.cps_lim, 0)));
+ expire = tick_add(now_ms, next_event_delay(&global.conn_per_sec, global.cps_lim, 0));
+ task_schedule(global_listener_queue_task, tick_first(expire, global_listener_queue_task->expire));
return;
}
return;
}
+ /* increase the per-process number of cumulated connections */
+ if (!(l->options & LI_O_UNLIMITED)) {
+ update_freq_ctr(&global.sess_per_sec, 1);
+ if (global.sess_per_sec.curr_ctr > global.sps_max)
+ global.sps_max = global.sess_per_sec.curr_ctr;
+ }
+
} /* end of while (max_accept--) */
/* we've exhausted max_accept, so there is no need to poll again */