Is Haproxy 2.0 default maxconn still enforced?

Hi everyone !

Quick question :
the facts
We are running haproxy 1.8 for the moment and are thinking of upgrading to Haproxy 2.0.7 but something is bugging me regarding the default maxconn.

haproxy -vv for 1.8 does display defaults : maxconn = 2000
however haproxy -vv for 2.0.7 there is no default for maxconn.

We are migrating from 1.8 with nbproc 3 with a global maxconn at 1024 and no other explicit maxconn setting in haproxy.cfg to 2.0.7 with no nbproc setting and a maxconn at 4000 to compensate for the loss of 2 processes.

My question is the following : assuming I don’t want to limit any of my frontend/backend maxconn, is setting maxconn globally at 4000 enough for frontend and backends to inherit this setting or is the default maxconn = 2000 still present even though it is no longer reported by haproxy -vv ?

If this is still the case, that means I need to explicitly set maxconn to 4000 for every backend/frontend and it would make my configuration file quite redundant.

Willy’s comment at the bottom of this offical blog post is a little bit confusing to me with the release of Haproxy 2.0

Thank you for your help !

As of haproxy 2.0 there no longer is a default maxconn for frontends. Unless specified, frontend maxconn is inherited from global maxconn. global maxconn is automatically computed if you don’t set one in your global section.

https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#maxconn

Thank you for your reply.

May I ask how the global maxconn is actually computed if unspecified ?

How reliable is this auto setting for large machines (4 core 8 GB RAM) ?

We added LimitNOFILE=65536 to the systemd service (RHEL7) unit because we were hard capped at 4096 file descriptors which would have prevented going over 2000 maxconn.

Are there any other system tweaks I should perform to ensure HaProxy can fully use the server it’s running on?

Thanks again for your help, it is very much appreciated.

quoting the documentation I referred to:

If this value is not set, it will automatically be
calculated based on the current file descriptors limit reported by the
"ulimit -n" command, possibly reduced to a lower value if a memory limit
is enforced, based on the buffer size, memory allocated to compression, SSL
cache size, and use or not of SSL and the associated maxsslconn (which can
also be automatic).

you can check the value set with the show info command on the stats socket.
as for system tweaks it depends on the type of workload you expect.

Our traffic is 99% SSL with security restrictions such as
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

a restricted cipher list and tune.ssl.default-dh-param 2048

Most rules are TCP based and we only have one http-request set-path %[path,regsub(/service/,/)] to replace an old reqrep.

That useless. Haproxy adjust this itself, based on maxconn.

If you are not sure about the automatic maxconn calculation, set it yourself. You don’t have to adjust anything in systemd unit files or the likes.

From my (admittedly limited) sysadmin experience, this is not the case, at least for RHEL 7 (or the particular flavor used at my company… I cannot guarantee we use a stock image of RHEL7)

[root@myserver ~]# ulimit -n
1024
[root@myserver ~]# echo "show info" | socat - /var/run/haproxy.sock | grep -E -i "ulimit|maxconn|maxsock"
Ulimit-n: 1024
Maxsock: 1024
Maxconn: 476
Hard_maxconn: 476

This is what I get whithout setting maxconn in the global section.

If I set it to, say 8000 , restart the service, I get the exact same output.

Adding LimitNOFILE=65536

[root@myserver ~]# vim /usr/lib/systemd/system/haproxy.service
[root@myserver~]# systemctl daemon-reload
[root@myserver ~]# systemctl restart haproxy.service
[root@myserver ~]# echo "show info" | socat - /var/run/haproxy.sock | grep -E -i "ulimit|maxconn|maxsock"
Ulimit-n: 65536
Maxsock: 65536
Maxconn: 32732
Hard_maxconn: 32732
MaxConnRate: 2

Maybe I missed something in the configuration guide somewhere, and believe me, I would LOVE to not touch the service unit, but I don’t see how I can avoid this.

Also, I used to have a weird behavior where Haproxy used the Hard limit instead of soft (still the case on my production server with Ha 1.8) but that’s totally off-topic.

1 Like

Haproxy does not DECREASE the ulimit. It only INCREASES it, and ONLY when necessary.

So for a proper test you need to:

  • NOT set LimitNOFILE in the unit file at all
  • actively set global maxconn to something that actually warrants in INCREASE of the standard value

I just had the same discussion a month ago, it looks like people get confused because haproxy only intervenes when needed:

https://www.mail-archive.com/haproxy@formilux.org/msg34964.html

1 Like

In my first example, as I said, LimitNOFILE was not set at all.

I’m starting to realize that maxconn has no effect at all on our RPM version of HaProxy. I did not package it and I’m starting to suspect that something might be wrong with the build (it used to be built for v 1.5 and not everything might have been updated correctly in the makefiles).

Testing this again with proof :

[root@myserver ~]# cat /usr/lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=network.target

[Service]
EnvironmentFile=-/etc/default/haproxy
EnvironmentFile=-/etc/sysconfig/haproxy
Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" "EXTRAOPTS=-S /run/haproxy-master.sock"
ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS
ExecStart=/usr/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS
ExecReload=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
Restart=always
SuccessExitStatus=143
Type=notify

# The following lines leverage SystemD's sandboxing options to provide
# defense in depth protection at the expense of restricting some flexibility
# in your setup (e.g. placement of your configuration files) or possibly
# reduced performance. See systemd.service(5) and systemd.exec(5) for further
# information.

# NoNewPrivileges=true
# ProtectHome=true
# If you want to use 'ProtectSystem=strict' you should whitelist the PIDFILE,
# any state files and any other files written using 'ReadWritePaths' or
# 'RuntimeDirectory'.
# ProtectSystem=true
# ProtectKernelTunables=true
# ProtectKernelModules=true
# ProtectControlGroups=true
# If your SystemD version supports them, you can add: @reboot, @swap, @sync
# SystemCallFilter=~@cpu-emulation @keyring @module @obsolete @raw-io

[Install]
WantedBy=multi-user.target

[root@myserver ~]# systemctl daemon-reload
[root@myserver ~]# systemctl stop haproxy
[root@myserver ~]# systemctl start haproxy
[root@myserver ~]# cat /etc/haproxy/haproxy.cfg | grep maxconn
    maxconn                 120000 

[root@myserver ~]# echo "show info" | socat - /var/run/haproxy.sock | grep -E -i "maxconn|ulimit|maxsock"
Ulimit-n: 1024
Maxsock: 1024
Maxconn: 476
Hard_maxconn: 476
MaxConnRate: 2

My build of HaProxy seems to completely ignore the maxconn parameter, that really does not seem right and I suspect it might be caused by the way it’s packaged…

Edit: Went back to 1.8 in production and checked : maxconn is set at 1024 but show info reports maxconn = 2000. tried another machine that still has 1.5 and maxconn is also ignored…

1 Like

Interesting. Do you see any warning in the unit logs (journalctl -xe haproxy)? I suggest to make a secondary configuration file, not listening to any production ports, just to set a specfic maxconn value and run it manually from the shell with haproxy -f /path/to/secondary-test-config.cfg -d, to see if any warnings or errors show up.

Here is what’s inside journalctl -xe when I stop then start haproxy. Don’t know if that helps…

Oct 24 18:33:28 myserver.mycompany.tld systemd[1]: Stopping HAProxy Load Balancer...
-- Subject: Unit haproxy.service has begun shutting down
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit haproxy.service has begun shutting down.
Oct 24 18:33:28 myserver.mycompany.tld haproxy[21574]: [WARNING] 296/183328 (21574) : Exiting Master process...
Oct 24 18:33:28 myserver.mycompany.tld haproxy[21574]: [ALERT] 296/183328 (21574) : Current worker #1 (21576) exited with code 143 (Terminated)
Oct 24 18:33:28 myserver.mycompany.tld haproxy[21574]: [WARNING] 296/183328 (21574) : All workers exited. Exiting... (0)
Oct 24 18:33:28 myserver.mycompany.tld systemd[1]: Stopped HAProxy Load Balancer.
-- Subject: Unit haproxy.service has finished shutting down
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit haproxy.service has finished shutting down.
Oct 24 18:33:28 myserver.mycompany.tld polkitd[7446]: Unregistered Authentication Agent for unix-process:21720:9853155 (system bus name :1.5886, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8) (disconnected from bus)
Oct 24 18:33:32 myserver.mycompany.tld polkitd[7446]: Registered Authentication Agent for unix-process:21727:9853556 (system bus name :1.5887 [/usr/bin/pkttyagent --notify-fd 5 --fallback], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8)
Oct 24 18:33:32 myserver.mycompany.tld systemd[1]: Starting HAProxy Load Balancer...
-- Subject: Unit haproxy.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit haproxy.service has begun starting up.
Oct 24 18:33:33 myserver.mycompany.tld haproxy[21735]: [NOTICE] 296/183333 (21735) : New worker #1 (21737) forked
Oct 24 18:33:33 myserver.mycompany.tld systemd[1]: Started HAProxy Load Balancer.
-- Subject: Unit haproxy.service has finished start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit haproxy.service has finished starting up.
-- 
-- The start-up result is done.

I will try to load the secondary test file tomorrow and will report back with the results.

I am looking into our rpmspec file and will ask for help from our experts as I have no proficiency in C and using make in general.

I think it’s very unlikely that this is build related, especially since you just confirmed the problem on different builds with 1.8 and 1.5 releases.

There are lot of things to check first.

Isolating the issue with a small configuration without production impact is the first step, then I’d suggest to start reproduce the issue through strace -tt so we see what actually happens.

But we are gonna need the full picture here. Output of:

  • uname -a
  • haproxy -vv
  • full configuration (the configuration needed to actually reproduce the issue)

Hi Lukas, first of all, I want to thank you for taking the time to troubleshoot this issue with us.

All tests below are done on dev server using HaProxy 2.0.7

Here’s a small config file I used to perform the test you asked for in debug mode

[root@myserver haproxy]# cat haproxy-test-minimal-config.cfg 
# Simple configuration for an HTTP proxy listening on port 80 on all
# interfaces and forwarding requests to a single backend "servers" with a
# single server "server1" listening on 127.0.0.1:8000
global
   master-worker
   maxconn 256

defaults
   mode http
   timeout connect 5000ms
   timeout client 50000ms
   timeout server 50000ms

frontend http-in
   bind *:8080
   default_backend servers

backend servers
   server server1 127.0.0.1:8000 maxconn 32


[root@myserver haproxy]# haproxy -f haproxy-test-minimal-config.cfg  -d
Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use epoll.

Available filters :
	[SPOE] spoe
	[COMP] compression
	[CACHE] cache
	[TRACE] trace
Using epoll() as the polling mechanism.
[NOTICE] 297/102545 (4923) : New worker #1 (4924) forked

I changed the default frontend port from 80 to 8080 to avoid any impact but otherwise it is the default conf provided in the documentation

here’s the output of uname -a and haproxy -vv

[root@myserver haproxy]# uname -a
Linux myserver.mycompany.tld 3.10.0-693.2.2.el7.x86_64 #1 SMP Sat Sep 9 03:55:24 EDT 2017 x86_64 x86_64 x86_64 GNU/Linux
[root@myserver haproxy]# haproxy -vv
HA-Proxy version 2.0.7 2019/09/27 - https://haproxy.org/
Build options :
  TARGET  = linux-glibc
  CPU     = generic
  CC      = gcc
  CFLAGS  = -m64 -march=x86-64 -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-old-style-declaration -Wno-ignored-qualifiers -Wno-clobbered -Wno-missing-field-initializers -Wtype-limits
  OPTIONS = USE_PCRE=1 USE_THREAD=1 USE_REGPARM=1 USE_LINUX_TPROXY=1 USE_CRYPT_H=1 USE_GETADDRINFO=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1

Feature list : +EPOLL -KQUEUE -MY_EPOLL -MY_SPLICE +NETFILTER +PCRE -PCRE_JIT -PCRE2 -PCRE2_JIT +POLL -PRIVATE_CACHE +THREAD -PTHREAD_PSHARED +REGPARM -STATIC_PCRE -STATIC_PCRE2 +TPROXY +LINUX_TPROXY +LINUX_SPLICE +LIBCRYPT +CRYPT_H -VSYSCALL +GETADDRINFO +OPENSSL -LUA +FUTEX +ACCEPT4 -MY_ACCEPT4 +ZLIB -SLZ +CPU_AFFINITY +TFO +NS +DL +RT -DEVICEATLAS -51DEGREES -WURFL +SYSTEMD -OBSOLETE_LINKER +PRCTL +THREAD_DUMP -EVPORTS

Default settings :
  bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with multi-threading support (MAX_THREADS=64, default=2).
Built with OpenSSL version : OpenSSL 1.0.2k-fips  26 Jan 2017
Running on OpenSSL version : OpenSSL 1.0.2k-fips  26 Jan 2017
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : SSLv3 TLSv1.0 TLSv1.1 TLSv1.2
Built with network namespace support.
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built with zlib version : 1.2.7
Running on zlib version : 1.2.7
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with PCRE version : 8.32 2012-11-30
Running on PCRE version : 8.32 2012-11-30
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Encrypted password support via crypt(3): yes

Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use epoll.

Available multiplexer protocols :
(protocols marked as <default> cannot be specified using 'proto' keyword)
              h2 : mode=HTX        side=FE|BE     mux=H2
              h2 : mode=HTTP       side=FE        mux=H2
       <default> : mode=HTX        side=FE|BE     mux=H1
       <default> : mode=TCP|HTTP   side=FE|BE     mux=PASS

Available services : none

Available filters :
	[SPOE] spoe
	[COMP] compression
	[CACHE] cache
	[TRACE] trace

I will post the full configuration in a bit, I need to anonymize qui a few things inside first…

Here is the general configuration part of our config file :slight_smile:

# reference: http://www.haproxy.org/download/1.5/doc/configuration.txt
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    log         127.0.0.1 local3 err

    # logging notes
    # 1) configuration above sends haproxy events to local syslog as local2
    #
    # 2) configuration for rsyslog is in /etc/rsyslog.d/haproxy.conf
    #
    # 3) optionally disable local2 events going to /var/log/messages
    #    by editing /etc/rsyslog.conf
    #
    #    # Don't log local2/haproxy events in messages
    #    *.info;mail.none;authpriv.none;cron.none;local2.none    /var/log/messages
    #

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    user        haproxy
    group       haproxy
    master-worker

    # turn on stats unix socket
    stats socket /var/run/haproxy.sock level admin
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

# cipher configuration comes from https://wiki.mozilla.org/Security/Server_Side_TLS
# intermediate compatibility
# updated <redacted date>
ssl-default-bind-ciphers <redacted list of ciphers>

ssl-default-server-ciphers <redacted list of ciphers>

tune.ssl.default-dh-param 2048
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    tcp
    option                  tcplog
    log                     global
    option                  dontlognull
    option                  dontlog-normal
    option                  redispatch
    retries                 3
    timeout queue           1m
    timeout connect         5s
    timeout client          5m
    timeout server          5m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 120000 

Maxconn has obviously been changed for testing purposes, it used to be 1024, but as mentioned in this thread, all values have 0 effect on the info reporter by the linux socket.

If you need frontend and backend info I will need to check If I am allowed to discose this info.

Here is proof there is no other global / defaults / maxconn setting in our config file :

[root@myserver ~]# grep -E -i "global|maxconn|defaults" /etc/haproxy/haproxy.cfg 
# Global settings
global
# common defaults that all the 'listen' and 'backend' sections will
defaults
    log                     global
    maxconn                 120000 

Thank you.

1 Like

You have maxconn in the defaults section. You need to put it into the global section instead, or move the entire defaults section before the global section, otherwise the defaults “maxconn” configuration will be applied only to frontends.

1 Like

Of COURSE it had to be something much more trivial…

Thank you for your helping us understand the importance of the sections order and setting maxconn in the right place :smiley:

1 Like