]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: init: pre-allocate kernel data structures on init
authorPatrick Hemmer <patrick.hemmer@gmail.com>
Tue, 23 May 2023 17:02:08 +0000 (13:02 -0400)
committerWilly Tarreau <w@1wt.eu>
Fri, 26 May 2023 07:28:18 +0000 (09:28 +0200)
The Linux kernel maintains data structures to track a processes' open file
descriptors, and it expands these structures as necessary when FD usage grows
(at every FD=2^X starting at 64). However when threading is in use, during
expansion the kernel will pause (observed up to 47ms) while it waits for thread
synchronization (see https://bugzilla.kernel.org/show_bug.cgi?id=217366).

This change addresses the issue and avoids the random pauses by opening the
maximum file descriptor during initialization, so that expansion will not occur
while processing traffic.

doc/configuration.txt
include/haproxy/global-t.h
src/cfgparse-global.c
src/haproxy.c

index f8d44cbeb12a511d6eddfeb908b86f16505cc1b1..5f8474adf38b9639678291e709977aff658fbffe 100644 (file)
@@ -1107,6 +1107,7 @@ The following keywords are supported in the "global" section :
    - pidfile
    - pp2-never-send-local
    - presetenv
+   - prealloc-fd
    - resetenv
    - set-dumpable
    - set-var
@@ -2084,6 +2085,12 @@ presetenv <name> <value>
   in the configuration file sees the new value. See also "setenv", "resetenv",
   and "unsetenv".
 
+prealloc-fd
+  Performs a one-time open of the maximum file descriptor which results in a
+  pre-allocation of the kernel's data structures. This prevents short pauses
+  when nbthread>1 and HAProxy opens a file descriptor which requires the kernel
+  to expand its data structures.
+
 resetenv [<name> ...]
   Removes all environment variables except the ones specified in argument. It
   allows to use a clean controlled environment before setting new values with
index e7d02fe2fed332cc1a14bdb99b0a58272c62b09c..0bcfa577a167913802720d1bc8338b06a584a871 100644 (file)
@@ -188,6 +188,7 @@ struct global {
        } unix_bind;
        struct proxy *cli_fe;           /* the frontend holding the stats settings */
        int numa_cpu_mapping;
+       int prealloc_fd;
        int cfg_curr_line;              /* line number currently being parsed */
        const char *cfg_curr_file;      /* config file currently being parsed or NULL */
        char *cfg_curr_section;         /* config section name currently being parsed or NULL */
index cc643f46ea03f0be030c442c13608334e59c37fa..30334ba13cbbe90cec0285989e491fccc8f3ad07 100644 (file)
@@ -1357,3 +1357,21 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
        return err_code;
 }
 
+static int cfg_parse_prealloc_fd(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;
+
+       global.prealloc_fd = 1;
+
+       return 0;
+}
+
+static struct cfg_kw_list cfg_kws = {ILH, {
+       { CFG_GLOBAL, "prealloc-fd", cfg_parse_prealloc_fd },
+       { 0, NULL, NULL },
+}};
+
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
index 0eb78d857ec22f959de590ffe58a4159a785f3ac..04056470199fdcfe8cec4d3cbcccb07a092200d3 100644 (file)
@@ -3522,6 +3522,14 @@ int main(int argc, char **argv)
                                 global.maxsock);
        }
 
+       if (global.prealloc_fd && fcntl((int)limit.rlim_cur - 1, F_GETFD) == -1) {
+               if (dup2(0, (int)limit.rlim_cur - 1) == -1)
+                       ha_warning("[%s.main()] Unable to preallocate file descriptor %lu : %s",
+                                  argv[0], limit.rlim_cur-1, strerror(errno));
+               else
+                       close((int)limit.rlim_cur - 1);
+       }
+
        /* update the ready date a last time to also account for final setup time */
        clock_update_date(0, 1);
        clock_adjust_now_offset();