From 81c25d0ee62fa93ea7a72bdf3d163b0604476065 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 7 Sep 2011 15:17:21 +0200 Subject: [PATCH] [MEDIUM] add support for global.maxconnrate to limit the per-process conn rate. This one enforces a per-process connection rate limit, regardless of what may be set per frontend. It can be a way to limit the CPU usage of a process being severely attacked. The side effect is that the global process connection rate is now measured for each incoming connection, so it will be possible to report it. --- doc/configuration.txt | 11 +++++++++++ include/proto/proxy.h | 1 + include/types/global.h | 2 ++ src/cfgparse.c | 13 +++++++++++++ src/dumpstats.c | 1 + src/stream_sock.c | 19 +++++++++++++++++++ 6 files changed, 47 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index becdab745b..62fc5e902c 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -448,6 +448,7 @@ The following keywords are supported in the "global" section : * Performance tuning - maxconn + - maxconnrate - maxpipes - noepoll - nokqueue @@ -649,6 +650,16 @@ maxconn connections when this limit is reached. The "ulimit-n" parameter is automatically adjusted according to this value. See also "ulimit-n". +maxconnrate + Sets the maximum per-process number of connections per second to . + 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. + maxpipes Sets the maximum per-process number of pipes to . Currently, pipes are only used by kernel-based tcp splicing. Since a pipe contains two file diff --git a/include/proto/proxy.h b/include/proto/proxy.h index 2b5328c680..f5303bc72e 100644 --- a/include/proto/proxy.h +++ b/include/proto/proxy.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/include/types/global.h b/include/types/global.h index cdd1bc478e..a5c7fa01c3 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -66,6 +66,8 @@ struct global { int gid; int nbproc; int maxconn, hardmaxconn; + struct freq_ctr conn_per_sec; + int cps_lim, cps_max; int maxpipes; /* max # of pipes */ int maxsock; /* max # of sockets */ int rlimit_nofile; /* default ulimit-n value : 0=unset */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 5b942e2ea9..1889654d26 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -682,6 +682,19 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } #endif /* SYSTEM_MAXCONN */ } + else if (!strcmp(args[0], "maxconnrate")) { + if (global.cps_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.cps_lim = atol(args[1]); + } else if (!strcmp(args[0], "maxpipes")) { if (global.maxpipes != 0) { Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); diff --git a/src/dumpstats.c b/src/dumpstats.c index c9c40557a0..4fde2919a9 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -808,6 +808,7 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) } } + global.cps_max = 0; return 1; } else if (strcmp(args[1], "table") == 0) { diff --git a/src/stream_sock.c b/src/stream_sock.c index 11e74fdbb4..365f52b97f 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -1156,6 +1156,20 @@ int stream_sock_accept(int fd) return 0; } + if (global.cps_lim) { + int max = freq_ctr_remain(&global.conn_per_sec, global.cps_lim, 0); + + 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))); + return 0; + } + + if (max_accept > max) + max_accept = max; + } + if (p && p->fe_sps_lim) { int max = freq_ctr_remain(&p->fe_sess_per_sec, p->fe_sps_lim, 0); @@ -1237,6 +1251,11 @@ int stream_sock_accept(int fd) return 0; } + /* increase the per-process number of cumulated connections */ + update_freq_ctr(&global.conn_per_sec, 1); + if (global.conn_per_sec.curr_ctr > global.cps_max) + global.cps_max = global.conn_per_sec.curr_ctr; + jobs++; actconn++; totalconn++; -- 2.47.3