This episode squeezes performance out of HAProxy: tuning maxconn, buffers, and threads, reducing latency with keepalive, compression, and HTTP/2, and measuring results with benchmarking tools like wrk, hey, and h2load.

HAProxy has been fast from the start, but wrong calibration can make it feel slow: buffers too small, threads unbalanced, or compression not enabled. Episode 15 covers the art of performance tuning.
You'll size the process capacity, reduce latency with keepalive, compression, and HTTP/2, then prove the changes with benchmarking tools. The principle emphasized: measure first, change one thing, measure again.
maxconn determines the process's connection capacity. Its value is bounded by the system's file descriptor limit:
global
maxconn 50000
tune.bufsize 32768
tune.maxrewrite 4096The tune.bufsize 32768 directive enlarges the buffer per connection, useful for large requests. tune.maxrewrite reserves buffer space for header rewriting. Both only need raising if your requests are large.
Before raising maxconn, make sure the system allows it:
ulimit -n
sysctl fs.file-maxulimit -n shows the process's current file descriptor limit. If the value is smaller than the maxconn you want, raise it via limits.conf or a systemd unit file.
CPU utilization is managed with threads:
global
nbthread 4
cpu-map auto:1/1-4 0-3nbthread 4 creates four threads. cpu-map binds threads to specific cores so the CPU cache stays warmer. For most workloads, an nbthread equal to the number of physical cores is enough.
New connections cost TCP and TLS handshakes. Keepalive avoids that cost:
frontend web_front
bind *:80
mode http
option http-keep-alive
default_backend web_back
backend web_back
server web1 127.0.0.1:8080 keepalive 32
server web2 127.0.0.1:8081 keepalive 32option http-keep-alive keeps client connections alive, and keepalive 32 on the server lines limits how many requests each backend connection handles before it's closed. This cuts per-request latency significantly.
Compressing responses reduces the bytes sent, lowering network latency:
backend web_back
mode http
compression algo gzip
compression type text/html text/plain text/css \
application/json application/javascript
server web1 127.0.0.1:8080compression algo gzip enables gzip, and compression type limits which content types get compressed. Make sure the backend isn't already compressing to avoid double work.
HTTP/2 combines many requests into one connection, cutting head-of-line latency:
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/fullchain.pem \
alpn h2,http/1.1
mode http
default_backend web_backalpn h2,http/1.1 makes supporting clients use HTTP/2. The multiplexing it brings is most noticeable on pages that load many assets at once.
wrk is a low-latency thread-based load generator:
wrk -t4 -c100 -d30s http://localhost/wrk -t4 -c100 -d30s http://localhost/ opens 100 connections through 4 threads for 30 seconds. Its output shows Requests/sec, average Latency, and percentiles.
hey is simpler and fits quick tests:
hey -n 10000 -c 50 http://localhost/hey -n 10000 -c 50 http://localhost/ sends 10,000 requests with 50 parallel connections. Pay attention to the Total time and Requests/sec sections to compare before and after tuning.
For HTTP/2, h2load is the most appropriate choice:
h2load -n 10000 -c 100 -m 16 https://localhost/ -kh2load -n 10000 -c 100 -m 16 https://localhost/ -k opens 100 connections with 16 parallel streams each. The -k flag is used for a self-signed certificate.
So results can be interpreted:
wrk -t4 -c100 -d30s http://localhost/ > before.txt
# change the configuration then reload
wrk -t4 -c100 -d30s http://localhost/ > after.txt
diff before.txt after.txtThe diff before.txt after.txt pattern shows performance changes directly. If there's no meaningful change, revert the configuration — complexity without benefit isn't worth keeping.
Episode 15 teaches you how to make HAProxy measurably faster: proper process capacity, latency reduced through keepalive and compression, and a disciplined benchmarking habit.
Key takeaways:
maxconn is bounded by the system file descriptor limit; make sure ulimit is enough.nbthread equal to the number of physical cores is usually optimal.In the next episode we'll cover content switching & ACLs — advanced ACL expressions, combining host, path, header, and payload conditions for conditional routing, and structuring complex frontend logic.