Throttling from several clients, based on url


#1

Hi,

despite many examples and reading the haproxy docs, I still don’t manage to do the following:

note that we use haproxy 1.5.14

we use haproxy to distribute HTTP requests (roundrobin) over a number of backends.
I would like to limit the number of HTTP requests on the frontend, regardless from which IP address they are coming.

Initially I used something like:

#frontend:
stick-table type ip size 500k expire 2s store http_req_rate(1s)
tcp-request connection track-sc1 src

#backend
timeout tarpit 1000
acl abuse_xxx src_http_req_rate(frontend_name) ge 5
http-request tarpit if abuse_xxx

This worked when sending requests from 1 ip address, in this case allowing 5 requests per second.

As far as I understand, the stick-table type ip counts entries per IP address. We don’t want this, throttling has to be done on the total number of HTTP requests, independent from the client ip.

To throttle on the total, I expect I need to use the url path in some way, as these are the same for each client, only the client ip address differs.

So far I did not manage to do so, when using stick tables with type string, I did not find a way to store entries in this table in the frontend, when adding entries to the backend, socat shows 1 entry per request instead of a total.

so: I need some guidance here :slight_smile:

Leon


#2

I assume that your intention is to protect your backend server from overload. Is that correct? In that case, you are asking all the wrong questions. Request per seconds is not the correct metric to avoid overloading your server, concurrent (in flight) requests are.

You’d find out how many concurrent requests your backend server can handle, and then use maxconn to limit that number. If you server doesn’t handle concurrency well at all, you may even set the per server maxconn value to 1 (but whether this is a good idea for your deployment is something that you need to find out).

Then it’s as simple as setting the value:

backend blablabla
 server s1 192.168.1.100:80 check maxconn 20

On the other hand, stick table based abuse detection is there so that you can limit the request per source-IP, which is explicitly not what you want.


#3

Hi Lukas,

thanks for your fast reply, I was on the wrong track then, apparently.
As indeed the idea was to protect the backend from overload.

Still, when trying your proposal, for testing I put the maxconn to 1

backend backend-xxx
log global
mode http
balance roundrobin

server s1 172.16.1.3:38080 check maxconn 1
server s2 172.16.1.4:38080 check maxconn 1

I use SOAPUI to send HTTP requests with 10 threads in parallel to my frontend, and see 5 connections setup to each backend, where I would expect only 1 per backend,
can you explain why?

tcp 0 0 172.16.1.1:54560 172.16.1.3:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:54562 172.16.1.3:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:54564 172.16.1.3:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:54570 172.16.1.3:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:54573 172.16.1.3:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:57037 172.16.1.4:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:57039 172.16.1.4:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:57041 172.16.1.4:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:57047 172.16.1.4:38080 ESTABLISHED 32130/haproxy
tcp 0 0 172.16.1.1:57050 172.16.1.4:38080 ESTABLISHED 32130/haproxy


#4

maxconn 1 guarantees that there are no more than 1 concurrent connections to the server at any given time. It does not multiplex or pool connections from different frontend connection to a single backend connection however.

Also, when the client closes the connection, the backend connection closes as well.

So it looks like your client did not use keepalive between the request (or maybe the server closed the connection), and that round-robin distributes the request fairly.