diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 45986f3f527..7eabeb89093 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -352,6 +352,7 @@ Thank you! Matthias Pitzl Matthieu Herrb Max Okumoto + Max Schmitt Merik Karman Michael Buchau diff --git a/src/cf.data.pre b/src/cf.data.pre index 28bbbd5681a..66d70485f98 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -10681,14 +10681,32 @@ DOC_END NAME: max_filedescriptors max_filedesc TYPE: int DEFAULT: 0 -DEFAULT_DOC: Use operating system soft limit set by ulimit. +DEFAULT_DOC: Guess a reasonable value (e.g., use soft limit set by ulimit). LOC: Config.max_filedescriptors DOC_START - Set the maximum number of filedescriptors, either below the - operating system default or up to the hard limit. - - Remove from squid.conf to inherit the current ulimit soft - limit setting. + Sets the maximum number of file descriptors, up to the hard OS limit (where + supported). + + Currently, the explicitly configured value is ignored when `setrlimit(2)` or + `RLIMIT_NOFILE` support was not detected at `./configure` time. A level-1 + "WARNING" message is written to cache.log in such cases, but future Squid + versions will fail to start instead. + + Currently, if `setrlimit(2)` fails to set the soft and hard limits to the + configured value, a level-0 "ERROR" message is written to cache.log, and + Squid attempts to raise the soft limit to match the hard limit instead. The + resulting soft limit (raised or not) is then used instead of the configured + value. Future Squid versions will fail to start in such cases. + + By default, Squid tries to guess a reasonable value (e.g., the current + operating system soft limit set by `ulimit -n` or equivalent). The details + of the guessing algorithm may change. Use this directive to avoid exposure + to those changes and unwanted dependencies on build and runtime environment + states, especially in high-performance deployments that require a large + number of descriptors. + + Squid fails to start if `setrlimit(2)` is supported but fails to set a soft + limit to the configured or guessed value. Note: Changing this requires a restart of Squid. Also not all I/O types supports large values (eg on Windows). diff --git a/src/tools.cc b/src/tools.cc index 65adc5f18c8..f42f6e4ed32 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -764,6 +764,8 @@ setMaxFD(void) struct rlimit rl; #endif + auto checkLimits = true; + if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { int xerrno = errno; debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno)); @@ -787,13 +789,40 @@ setMaxFD(void) xerrno = errno; debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno)); } + // else: getrlimit() will still return two OS-originated rl.rlim_max limits that must be checked + } else { + // getrlimit() will now return admin-configured numbers, not OS-provided ones + checkLimits = false; } } if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { int xerrno = errno; debugs(50, DBG_CRITICAL, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno)); } else { - Squid_MaxFD = rl.rlim_cur; + // An OS may supply us with huge RLIMIT_NOFILE limits (e.g., the soft + // limit may exceed one billion on Kubernets). We cap these OS-provided + // limits to protect deployments from accidentally or unknowingly + // allocating huge FD-indexed structures (e.g., ~432 GB fd_table on + // Kubernetes). Special deployments that really need more descriptors + // than this cap must set max_filedescriptors accordingly. + const auto defaultCapForMaximumNumberOfFiles = rlim_t(100*1024); // ~42 MB fd_table + + // No cap if setrlimit() changed the limits to match max_filedescriptors + // because, in that case, rl.rlim_cur is effectively set by the Squid + // admin (rather than reflecting OS configuration that we do not trust). + if (checkLimits && rl.rlim_cur > defaultCapForMaximumNumberOfFiles) { + debugs(50, DBG_IMPORTANT, "WARNING: OS-provided soft limit (" << rl.rlim_cur << " RLIMIT_NOFILE) " << + "is too big to use for calculating the maximum number of descriptors Squid may use; " << + "setting that maximum to " << defaultCapForMaximumNumberOfFiles); + Squid_MaxFD = defaultCapForMaximumNumberOfFiles; + } else { + debugs(50, 3, "Squid_MaxFD was " << Squid_MaxFD << "; now " << rl.rlim_cur << " <= " << rl.rlim_max); + Squid_MaxFD = rl.rlim_cur; + } + // XXX: When checkLimits, take ./configure --with-filedescriptors (if any) into account. + // XXX: rl.rlim_cur is often too small (e.g. 1024). In those cases, use a larger value if rl.rlim_max allows. + // XXX: The new value may make Squid_MaxFD different from SQUID_MAXFD still used by ModEpoll, ModPoll, ipcCreate(), etc.! + // XXX: If this increases Squid_MaxFD, then the new value will violate any defined SQUID_MAXFD_LIMIT. } #endif /* HAVE_SETRLIMIT */