MINOR: init: always fail when setrlimit fails

this patch introduces a strict-limits parameter which enforces the
setrlimit setting instead of a warning. This option can be forcingly
disable with the "no" keyword.
The general aim of this patch is to avoid bad surprises on a production
environment where you change the maxconn for example, a new fd limit is
calculated, but cannot be set because of sysfs setting. In that case you
might want to have an explicit failure to be aware of it before seeing
your traffic going down. During a global rollout it is also useful to
explictly fail as most progressive rollout would simply check the
general health check of the process.

As discussed, plan to use the strict by default mode starting from v2.3.

Signed-off-by: William Dauchy <w.dauchy@criteo.com>
This commit is contained in:
William Dauchy 2019-10-27 20:08:11 +01:00 committed by Willy Tarreau
parent ec73098171
commit 0fec3ab7bf
5 changed files with 93 additions and 20 deletions

View File

@ -629,6 +629,7 @@ The following keywords are supported in the "global" section :
- wurfl-information-list
- wurfl-information-list-separator
- wurfl-cache-size
- strict-limits
* Performance tuning
- busy-polling
@ -1405,6 +1406,14 @@ wurfl-cache-size <size>
Please note that this option is only available when haproxy has been compiled
with USE_WURFL=1.
strict-limits
Makes process fail at startup when a setrlimit fails. Haproxy is tries to set
the best setrlimit according to what has been calculated. If it fails, it
will emit a warning. Use this option if you want an explicit failure of
haproxy when those limits fail. This option is disabled by default. If it has
been enabled, it may still be forcibly disabled by prefixing it with the "no"
keyword.
3.2. Performance tuning
-----------------------

View File

@ -72,8 +72,8 @@
#define GTUNE_BUSY_POLLING (1<<11)
#define GTUNE_LISTENER_MQ (1<<12)
#define GTUNE_SET_DUMPABLE (1<<13)
#define GTUNE_USE_EVPORTS (1<<14)
#define GTUNE_STRICT_LIMITS (1<<15)
/* SSL server verify mode */
enum {

View File

@ -1172,6 +1172,14 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
env++;
}
}
else if (!strcmp(args[0], "strict-limits")) { /* "no strict-limits" or "strict-limits" */
if (alertif_too_many_args(0, file, linenum, args, &err_code))
goto out;
if (kwm == KWM_NO)
global.tune.options &= ~GTUNE_STRICT_LIMITS;
else
global.tune.options |= GTUNE_STRICT_LIMITS;
}
else {
struct cfg_kw_list *kwl;
int index;

View File

@ -2149,10 +2149,10 @@ int readcfgfile(const char *file)
if (kwm != KWM_STD && strcmp(args[0], "option") != 0 &&
strcmp(args[0], "log") != 0 && strcmp(args[0], "busy-polling") != 0 &&
strcmp(args[0], "set-dumpable") != 0) {
strcmp(args[0], "set-dumpable") != 0 && strcmp(args[0], "strict-limits") != 0) {
ha_alert("parsing [%s:%d]: negation/default currently "
"supported only for options, log, busy-polling and "
"set-dumpable.\n", file, linenum);
"supported only for options, log, busy-polling, "
"set-dumpable and strict-limits.\n", file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
}

View File

@ -2829,14 +2829,24 @@ int main(int argc, char **argv)
limit.rlim_max = MAX(rlim_fd_max_at_boot, limit.rlim_cur);
if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
/* try to set it to the max possible at least */
getrlimit(RLIMIT_NOFILE, &limit);
limit.rlim_cur = limit.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &limit) != -1)
getrlimit(RLIMIT_NOFILE, &limit);
if (global.tune.options & GTUNE_STRICT_LIMITS) {
ha_alert("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n",
argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
if (!(global.mode & MODE_MWORKER))
exit(1);
}
else {
/* try to set it to the max possible at least */
limit.rlim_cur = limit.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &limit) != -1)
getrlimit(RLIMIT_NOFILE, &limit);
ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d.\n", argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
global.rlimit_nofile = limit.rlim_cur;
ha_warning("[%s.main()] Cannot raise FD limit to %d, limit is %d. "
"This will fail in >= v2.3\n",
argv[0], global.rlimit_nofile, (int)limit.rlim_cur);
global.rlimit_nofile = limit.rlim_cur;
}
}
}
@ -2845,13 +2855,29 @@ int main(int argc, char **argv)
global.rlimit_memmax * 1048576ULL;
#ifdef RLIMIT_AS
if (setrlimit(RLIMIT_AS, &limit) == -1) {
ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
argv[0], global.rlimit_memmax);
if (global.tune.options & GTUNE_STRICT_LIMITS) {
ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
argv[0], global.rlimit_memmax);
if (!(global.mode & MODE_MWORKER))
exit(1);
}
else
ha_warning("[%s.main()] Cannot fix MEM limit to %d megs."
"This will fail in >= v2.3\n",
argv[0], global.rlimit_memmax);
}
#else
if (setrlimit(RLIMIT_DATA, &limit) == -1) {
ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
argv[0], global.rlimit_memmax);
if (global.tune.options & GTUNE_STRICT_LIMITS) {
ha_alert("[%s.main()] Cannot fix MEM limit to %d megs.\n",
argv[0], global.rlimit_memmax);
if (!(global.mode & MODE_MWORKER))
exit(1);
}
else
ha_warning("[%s.main()] Cannot fix MEM limit to %d megs.",
"This will fail in >= v2.3\n",
argv[0], global.rlimit_memmax);
}
#endif
}
@ -3050,13 +3076,31 @@ int main(int argc, char **argv)
limit.rlim_cur = limit.rlim_max = RLIM_INFINITY;
#if defined(RLIMIT_FSIZE)
if (setrlimit(RLIMIT_FSIZE, &limit) == -1)
ha_warning("[%s.main()] Failed to set the raise the maximum file size.\n", argv[0]);
if (setrlimit(RLIMIT_FSIZE, &limit) == -1) {
if (global.tune.options & GTUNE_STRICT_LIMITS) {
ha_alert("[%s.main()] Failed to set the raise the maximum "
"file size.\n", argv[0]);
if (!(global.mode & MODE_MWORKER))
exit(1);
}
else
ha_warning("[%s.main()] Failed to set the raise the maximum "
"file size. This will fail in >= v2.3\n", argv[0]);
}
#endif
#if defined(RLIMIT_CORE)
if (setrlimit(RLIMIT_CORE, &limit) == -1)
ha_warning("[%s.main()] Failed to set the raise the core dump size.\n", argv[0]);
if (setrlimit(RLIMIT_CORE, &limit) == -1) {
if (global.tune.options & GTUNE_STRICT_LIMITS) {
ha_alert("[%s.main()] Failed to set the raise the core "
"dump size.\n", argv[0]);
if (!(global.mode & MODE_MWORKER))
exit(1);
}
else
ha_warning("[%s.main()] Failed to set the raise the core "
"dump size. This will fail in >= v2.3\n", argv[0]);
}
#endif
#if defined(USE_PRCTL)
@ -3069,8 +3113,20 @@ int main(int argc, char **argv)
limit.rlim_cur = limit.rlim_max = 0;
getrlimit(RLIMIT_NOFILE, &limit);
if (limit.rlim_cur < global.maxsock) {
ha_warning("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
if (global.tune.options & GTUNE_STRICT_LIMITS) {
ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
"Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
global.maxsock);
if (!(global.mode & MODE_MWORKER))
exit(1);
}
else
ha_alert("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. "
"Please raise 'ulimit-n' to %d or more to avoid any trouble."
"This will fail in >= v2.3\n",
argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock,
global.maxsock);
}
if (global.mode & (MODE_DAEMON | MODE_MWORKER | MODE_MWORKER_WAIT)) {