Score:1

HAProxy 2.0 - retrying some of the requests based on URL

jp flag

I have HAProxy version 2.0.14 installed, and I'm looking for a peculiar use-case which I haven't yet managed to configure correctly.

Basically I have a frontend which listens on a port, and two backend servers. Once a session is started, cookies are used, so a session is tied to a particular backend server, and cannot be shared to another server. To achieve this I'm using stick-table and stick on keywords, and a LUA script to get the required value from the requests.

However, when the first request arrives, if the selected backend server fails to respond in time, we should failover to the other one, as at that point the cookie is not yet set.

So far I have the following config:

global
   log 127.0.0.1 len 10000 local2 debug
   chroot /var/lib/haproxy
   user haproxy
   group haproxy
   daemon
   lua-load /opt/LUA/myparser.lua

   stats socket /etc/haproxy/haproxysock level admin

defaults
   log global
   option httplog
   option dontlognull
   mode http
   timeout connect 5000
   timeout client 50000
   timeout server 50000
   log-format "Client IP:port = [%ci:%cp], Start Time = [%tr], Frontend Name = [%ft], Backend Name = [%b], Backend Server = [%s], Time to receive full request = [%TR ms], Response time = [%Tr ms], Status Code = [%ST], Bytes Read = [%B]"

frontend chatgw_front
   bind *:8776

   option http-buffer-request
   declare capture request len 40000
   http-request capture req.body id 0
   http-request capture req.hdrs len 2048

   http-request track-sc0 src table my_back
   use_backend my_back

backend my_back
   balance roundrobin

   stick-table type string len 32 size 30k expire 30m
   stick on "lua.parseId" table my_back

   server server1 x.x.x.1:8080 check
   server server2 x.x.x.2.8080 check

What this does is if the selected backend server doesn't respond in 50 seconds, it throws a HTTP 504 Gateway Timeout to the client. What I would need instead is, if this is the first request in a session, then (and only then) failover to another backend server. We can tell this is the first request based on the URL.

I tried to change the backend like this:

backend my_back
   balance roundrobin

   stick-table type string len 32 size 30k expire 30m
   stick on "lua.parseId" table my_back

# Check if this is "init" request: in this case URL contains "/init"
   acl is_init path_sub /init

# In case of "init" request, enable redispatch to other backend server in case failure
   option redispatch if is_init

# In case of other requests (not "init"), we are already tied to a selected backend server due to session cookie, so disable redispatch
   no option redispatch if !is_init

   server server1 x.x.x.1:8080 check
   server server2 x.x.x.2.8080 check

However I got the exact same behavior. So I tried to add "retry-on":

backend my_back
   balance roundrobin

   stick-table type string len 32 size 30k expire 30m
   stick on "lua.parseId" table my_back

   acl is_init path_sub /init

   option redispatch if is_init

   no option redispatch if !is_init

   retry-on conn-failure empty-response response-timeout

   server server1 x.x.x.1:8080 check
   server server2 x.x.x.2.8080 check

Now, it is different: it tried the initial request 4 times on the same server, and then it returned the HTTP 504. Then it received the next request (which is not "init", so should not be sticking to the selected backend server), and this got sent to the other server instead.

Basically, my problem is: how to implement failover on the first request only? Any other request must always stick to the selected backend server.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.