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.
This commit is contained in:
Willy Tarreau 2022-03-08 10:41:40 +01:00
parent 5bcfd33063
commit c4e56dc58c
2 changed files with 33 additions and 0 deletions

View File

@ -1070,6 +1070,7 @@ The following keywords are supported in the "global" section :
- maxsslconn - maxsslconn
- maxsslrate - maxsslrate
- maxzlibmem - maxzlibmem
- no-memory-trimming
- noepoll - noepoll
- nokqueue - nokqueue
- noevports - noevports
@ -2380,6 +2381,22 @@ maxzlibmem <number>
with "show info" on the line "MaxZlibMemUsage", the memory used by zlib is with "show info" on the line "MaxZlibMemUsage", the memory used by zlib is
"ZlibMemUsage" in bytes. "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 noepoll
Disables the use of the "epoll" event polling system on Linux. It is Disables the use of the "epoll" event polling system on Linux. It is
equivalent to the command-line argument "-de". The next polling system equivalent to the command-line argument "-de". The next polling system

View File

@ -83,6 +83,7 @@ static const struct {
static int mem_fail_rate __read_mostly = 0; static int mem_fail_rate __read_mostly = 0;
static int using_default_allocator __read_mostly = 1; static int using_default_allocator __read_mostly = 1;
static int disable_trim __read_mostly = 0;
static int(*my_mallctl)(const char *, void *, size_t *, void *, size_t) = NULL; static int(*my_mallctl)(const char *, void *, size_t *, void *, size_t) = NULL;
/* ask the allocator to trim memory pools. /* ask the allocator to trim memory pools.
@ -95,6 +96,9 @@ static void trim_all_pools(void)
{ {
int isolated = thread_isolated(); int isolated = thread_isolated();
if (disable_trim)
return;
if (!isolated) if (!isolated)
thread_isolate(); thread_isolate();
@ -1073,9 +1077,21 @@ static int mem_parse_global_fail_alloc(char **args, int section_type, struct pro
return 0; return 0;
} }
/* 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 */ /* register global config keywords */
static struct cfg_kw_list mem_cfg_kws = {ILH, { static struct cfg_kw_list mem_cfg_kws = {ILH, {
{ CFG_GLOBAL, "tune.fail-alloc", mem_parse_global_fail_alloc }, { CFG_GLOBAL, "tune.fail-alloc", mem_parse_global_fail_alloc },
{ CFG_GLOBAL, "no-memory-trimming", mem_parse_global_no_mem_trim },
{ 0, NULL, NULL } { 0, NULL, NULL }
}}; }};