From: Willy Tarreau Date: Tue, 8 Mar 2022 09:41:40 +0000 (+0100) Subject: MINOR: pools: add a new global option "no-memory-trimming" X-Git-Tag: v2.5.5~24 X-Git-Url: http://git.haproxy.org/?a=commitdiff_plain;h=4bcff9ba47e1c8f78405a1d6686edda68f254b44;p=haproxy-2.5.git MINOR: pools: add a new global option "no-memory-trimming" Some users with very large numbers of connections have been facing extremely long malloc_trim() calls on reload that managed to trigger the watchdog! That's a bit counter-productive. It's even possible that some implementations are not perfectly reliable or that their trimming time grows quadratically with the memory used. Instead of constantly trying to work around these issues, let's offer an option to disable this mechanism, since nobody had been complaining in the past, and this was only meant to be an improvement. This should be backported to 2.4 where trimming on reload started to appear. (cherry picked from commit c4e56dc58c9ada7c4a8d585cb117a5b825916002) [wt: minor context adj] Signed-off-by: Willy Tarreau --- diff --git a/doc/configuration.txt b/doc/configuration.txt index e3949d1..2c00fc9 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1070,6 +1070,7 @@ The following keywords are supported in the "global" section : - maxsslconn - maxsslrate - maxzlibmem + - no-memory-trimming - noepoll - nokqueue - noevports @@ -2379,6 +2380,22 @@ maxzlibmem with "show info" on the line "MaxZlibMemUsage", the memory used by zlib is "ZlibMemUsage" in bytes. +no-memory-trimming + Disables memory trimming ("malloc_trim") at a few moments where attempts are + made to reclaim lots of memory (on memory shortage or on reload). Trimming + memory forces the system's allocator to scan all unused areas and to release + them. This is generally seen as nice action to leave more available memory to + a new process while the old one is unlikely to make significant use of it. + But some systems dealing with tens to hundreds of thousands of concurrent + connections may experience a lot of memory fragmentation, that may render + this release operation extremely long. During this time, no more traffic + passes through the process, new connections are not accepted anymore, some + health checks may even fail, and the watchdog may even trigger and kill the + unresponsive process, leaving a huge core dump. If this ever happens, then it + is suggested to use this option to disable trimming and stop trying to be + nice with the new process. Note that advanced memory allocators usually do + not suffer from such a problem. + noepoll Disables the use of the "epoll" event polling system on Linux. It is equivalent to the command-line argument "-de". The next polling system diff --git a/src/pool.c b/src/pool.c index ba1d235..d34e6d5 100644 --- a/src/pool.c +++ b/src/pool.c @@ -44,6 +44,7 @@ static int mem_fail_rate = 0; #if defined(HA_HAVE_MALLOC_TRIM) static int using_libc_allocator = 0; +static int disable_trim __read_mostly = 0; /* ask the allocator to trim memory pools. * This must run under thread isolation so that competing threads trying to @@ -55,6 +56,9 @@ static void trim_all_pools(void) { int isolated = thread_isolated(); + if (disable_trim) + return; + if (!isolated) thread_isolate(); @@ -724,11 +728,23 @@ static int mem_parse_global_fail_alloc(char **args, int section_type, struct pro } #endif +/* config parser for global "no-memory-trimming" */ +static int mem_parse_global_no_mem_trim(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + if (too_many_args(0, args, err, NULL)) + return -1; + disable_trim = 1; + return 0; +} + /* register global config keywords */ static struct cfg_kw_list mem_cfg_kws = {ILH, { #ifdef DEBUG_FAIL_ALLOC { CFG_GLOBAL, "tune.fail-alloc", mem_parse_global_fail_alloc }, #endif + { CFG_GLOBAL, "no-memory-trimming", mem_parse_global_no_mem_trim }, { 0, NULL, NULL } }};