Using haproxy, I want:

  • A pool of 'main' servers and 'backup' servers, though they don't necessarily have to be in separate pools.
  • Each backend has a low 'maxconn' (in this case 1)
  • Clients should not wait in a queue. If there are no immediately available servers in the 'main' pool they should be shunted to the 'backup' pool without delay.

Right now I have one backend, 'main' servers have an absurdly high weighting and it 'works'.

acl use_backend + connslots is along the right lines but without the patch in my own answer it isn't perfect.

Bonus points for not requiring a modified haproxy binary.

  • 1
    I don't see why running a patched haproxy is so bad; you need custom behaviour, you get a custom program. – womble Jul 9 '11 at 7:24
  • It just means one more thing to maintain, which I'd rather not have to do. Also, I have no idea whether my patch is 'reasonable'. For all I know I've just introduced a severe memory leak which'll hit me every fortnight. I'm not a C coder :-) – Pricey Jul 9 '11 at 11:06
  • So find someone who is a C coder to do it right. That way, you get exactly what you need without needing to go to extraordinarily complicated lengths to get half of your solution. – womble Jul 9 '11 at 21:40

The correct way is to add an ACL in the frontend which checks the amount of connections on the server, and then makes a decision based on that.

The config below will check the "monitor_conns" frontend and if there are 500 or more connections, they will be sent to the "backups" backend, otherwise they'll go to the "regular" backend.

Here's an untested example:

frontend monitor_conns
  bind *:80
  acl too_many_conns fe_conn 500
  use_backend backups if too_many_conns
  default_backend regular

backend backups
  ... your config
  server backupsrv check port 80 maxconn 1000 inter 1s rise 1 fall 1

backend regular
  ... your config
  server regularsrv check port 80 maxconn 500 inter 1s rise 1 fall 1

It's just an example, but it should give you an idea on how to proceed.

  • I'd never thought of using acl's before. In this case, I think fe_conn measures the total number of connections on the frontend. This isn't quite what I want. (When adding new servers I 'could' total up the available conns but this approach would fail should a server go 'down') That said, you've pointed me in the direction of connslots which I think will do what I want. Will get back to you after some testing! – Pricey Jul 7 '11 at 8:23
  • Hmm please see my question edit, its close but not quite there. – Pricey Jul 7 '11 at 9:07

Old question, but I face the same problem, and here is my solution:

You can check front end conn using acl, and use backend that have extra server for that extra server I mean your backup server

So the config will look like this

frontend frontend1
    mode tcp
    acl max_conn_reached fe_conn gt 15
    acl production_almost_dead nbsrv(prod1) lt 2

    default_backend prod1
    use_backend prod1_and_prod2 if max_conn_reached OR production_almost_dead

backend prod1
    mode tcp
    balance leastconn
    server se_prod1 check maxconn 10
    server se_prod2 check maxconn 10

backend prod1_and_prod2
    mode tcp
    balance leastconn

    server se_prod1 check maxconn 10
    server se_prod2 check maxconn 10

    server se_backup1 check maxconn 10
    server se_backup2 check maxconn 10

The front end will use backup server (together with production server) if connection on frontend is greater than 15 or one service on backend1 is down


The following seems to work for me but it has required patching haproxy-1.4.15/src/backend.c:

# diff haproxy-1.4.15/src/backend.c backend.c
> /* set test->i to the number of enabled servers on the proxy */
> static int
> acl_fetch_connfree(struct proxy *px, struct session *l4, void *l7, int dir,
>                     struct acl_expr *expr, struct acl_test *test)
> {
>         struct server *iterator;
>         test->flags = ACL_TEST_F_VOL_TEST;
>         if (expr->arg_len) {
>                 /* another proxy was designated, we must look for it */
>                 for (px = proxy; px; px = px->next)
>                         if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
>                                 break;
>         }
>         if (!px)
>                 return 0;
>         test->i = 0;
>         iterator = px->srv;
>         while (iterator) {
>                 if ((iterator->state & SRV_RUNNING) == 0) {
>                         iterator = iterator->next;
>                         continue;
>                 }
>                 if (iterator->maxconn == 0) {
>                         test->i = -1;
>                         return 1;
>                 }
>                 test->i += (iterator->maxconn - (iterator->cur_sess + iterator->nbpend));
>                 iterator = iterator->next;
>         }
>         return 1;
> }
>       { "connfree", acl_parse_int,   acl_fetch_connfree, acl_match_int, ACL_USE_NOTHING },

I can then use connfree in my acl:

frontend frontend1
    bind *:12345
    acl main_full connfree(main) eq 0
    use_backend backup if main_full
    default_backend     main

backend main
    balance leastconn
    default-server maxconn 1 maxqueue 1
    server main2 check
    server main1 check

backend backup
    balance leastconn
    default-server maxconn 1 maxqueue 1
    server backup1 check
    server backup2 check

Hopefully comparing acl_fetch_connfree() to acl_fetch_connslots() will make the change obvious:

old = (maxconn - current conns) + (maxqueue - pending conns)

new = maxconn - (current conns + pending conns)

  • Hoping this "answer" isn't too foolish for some unknown reason. (I'm hardly a C coder) Unless I get a better answer I'll accept this one and award the bounty to alexandermensa for the inspiration. – Pricey Jul 8 '11 at 11:02
  • Your solution is interesting but I'm not sure I fully understand what you're trying to do, so I have difficulty providing you with a proper solution (without patching HAProxy). Sorry I can't be more helpful. You might also want to look into the 'queue' and 'be_conn' ACL options: Search for 7.5.1. in the HAProxy 1.4 Doc – user82810 Jul 23 '11 at 10:18
  • Yes be_conn is all well and good but I can't compare it to the number of currently available servers? As for queue, I can't set it to 0? – Pricey Jul 23 '11 at 21:04
  • 1
    Actually for the number of available servers there's the ACL option 'nbsrv(backend_name)' which also allows you to do integer matching, ex: acl main_full nbsrv(main) lt 1 or acl main_full nbsrv(main) eq 1. Don't forget you can also create multiple ACLs: acl main_full nbsrv(main) eq 1 and on another line: acl main_queue queue(main) eq 1 and then do use_backend backup if main_full main_queue That basically will use the backup backend if the ACLs main_full and main_queue are true. Hope that makes sense. – user82810 Jul 24 '11 at 19:48
  • The problem with nbsrv is that it counts a server which has queue slots free as 'available'. I want to ensure that each connection goes to an available server, preferably a main server if available. queue could 'work' if I accepted that one connection (the one queueing) would always break whilst the rest were redirected to the backup group. – Pricey Jul 25 '11 at 1:33

use the "backup" parameter in the backend section

frontend my-frontend *:9091 #arbitrary name for the frontend
         maxconn 500
         default_backend my-backend

backend my-backend
        mode http
        option httpchk
        server solr-1 weight 1 maxconn 500 check
        server solr-2 weight 1 maxconn 500 check backup

if solr-1 fails the httpchk, then solr-2 takes over.

  • Backups are only used if the main servers are 'down'. Even if they have a full connection pool they are still 'up' and so new connections will just fail. – Pricey Jul 7 '11 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.