BUG/MEDIUM: config: properly adjust maxconn with nbproc when memmax is forced

When memmax is forced using "-m", the per-process memory limit is enforced
using setrlimit(), but this value is not used to compute the automatic
maxconn limit. In addition, the per-process memory limit didn't consider
the fact that the shared SSL cache only needs to be accounted once.

The doc was also fixed to clearly state that "-m" is global and not per
process. It makes sense because people who use -m want to protect the
system's resources regardless of whatever appears in the configuration.
This commit is contained in:
Willy Tarreau 2015-12-14 12:46:07 +01:00
parent b22fc30aaa
commit 7006045e48
3 changed files with 27 additions and 8 deletions

View File

@ -223,11 +223,13 @@ list of options is :
generally be the "select" poller, which cannot be disabled and is limited
to 1024 file descriptors.
-m <limit> : limit the total allocatable memory to <limit> megabytes per
process. This may cause some connection refusals or some slowdowns
-m <limit> : limit the total allocatable memory to <limit> megabytes across
all processes. This may cause some connection refusals or some slowdowns
depending on the amount of memory needed for normal operations. This is
mostly used to force the process to work in a constrained resource usage
scenario.
mostly used to force the processes to work in a constrained resource usage
scenario. It is important to note that the memory is not shared between
processes, so in a multi-process scenario, this value is first divided by
global.nbproc before forking.
-n <limit> : limits the per-process connection limit to <limit>. This is
equivalent to the global section's keyword "maxconn". It has precedence

View File

@ -115,7 +115,8 @@ struct global {
int maxpipes; /* max # of pipes */
int maxsock; /* max # of sockets */
int rlimit_nofile; /* default ulimit-n value : 0=unset */
int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
int rlimit_memmax_all; /* default all-process memory limit in megs ; 0=unset */
int rlimit_memmax; /* default per-process memory limit in megs ; 0=unset */
long maxzlibmem; /* max RAM for zlib in bytes */
int mode;
unsigned int req_count; /* request counter (HTTP or TCP session) for logs and unique_id */

View File

@ -581,7 +581,7 @@ void init(int argc, char **argv)
#ifdef HAPROXY_MEMMAX
global.rlimit_memmax = HAPROXY_MEMMAX;
global.rlimit_memmax_all = HAPROXY_MEMMAX;
#endif
tv_update_date(-1,-1);
@ -729,7 +729,7 @@ void init(int argc, char **argv)
switch (*flag) {
case 'C' : change_dir = *argv; break;
case 'n' : cfg_maxconn = atol(*argv); break;
case 'm' : global.rlimit_memmax = atol(*argv); break;
case 'm' : global.rlimit_memmax_all = atol(*argv); break;
case 'N' : cfg_maxpconn = atol(*argv); break;
case 'L' : strncpy(localpeer, *argv, sizeof(localpeer) - 1); break;
case 'f' :
@ -794,6 +794,22 @@ void init(int argc, char **argv)
exit(1);
}
/* recompute the amount of per-process memory depending on nbproc and
* the shared SSL cache size (allowed to exist in all processes).
*/
if (global.rlimit_memmax_all) {
#if defined (USE_OPENSSL) && !defined(USE_PRIVATE_CACHE)
int64_t ssl_cache_bytes = global.tune.sslcachesize * 200LL;
global.rlimit_memmax =
((((int64_t)global.rlimit_memmax_all * 1048576LL) -
ssl_cache_bytes) / global.nbproc +
ssl_cache_bytes + 1048575LL) / 1048576LL;
#else
global.rlimit_memmax = global.rlimit_memmax_all / global.nbproc;
#endif
}
#ifdef CONFIG_HAP_NS
err_code |= netns_init();
if (err_code & (ERR_ABORT|ERR_FATAL)) {
@ -1645,7 +1661,7 @@ int main(int argc, char **argv)
if (global.rlimit_memmax) {
limit.rlim_cur = limit.rlim_max =
global.rlimit_memmax * 1048576ULL / global.nbproc;
global.rlimit_memmax * 1048576ULL;
#ifdef RLIMIT_AS
if (setrlimit(RLIMIT_AS, &limit) == -1) {
Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",