6

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.

3
  • 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, 2011 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, 2011 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, 2011 at 21:40

4 Answers 4

6
+50

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 192.168.0.101:80 check port 80 maxconn 1000 inter 1s rise 1 fall 1

backend regular
  ... your config
  server regularsrv 192.168.0.100:80 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.

2
  • 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, 2011 at 8:23
  • Hmm please see my question edit, its close but not quite there.
    – Pricey
    Jul 7, 2011 at 9:07
5

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 127.0.0.1:9200
    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 127.0.0.1:8001 check maxconn 10
    server se_prod2 127.0.0.1:8002 check maxconn 10

backend prod1_and_prod2
    mode tcp
    balance leastconn

    server se_prod1 127.0.0.1:8001 check maxconn 10
    server se_prod2 127.0.0.1:8002 check maxconn 10

    server se_backup1 127.0.0.1:8003 check maxconn 10
    server se_backup2 127.0.0.1:8004 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

1

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
1298a1299,1333
> /* 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;
> }
>
1461a1497
>       { "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 10.0.0.1:12345 check
    server main1 10.0.0.2:12345 check

backend backup
    balance leastconn
    default-server maxconn 1 maxqueue 1
    server backup1 10.0.1.1:12345 check
    server backup2 10.0.1.2:12345 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)

5
  • 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, 2011 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, 2011 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, 2011 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, 2011 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, 2011 at 1:33
-1

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 10.30.3.100:9091 weight 1 maxconn 500 check
        server solr-2 10.30.3.101:9091 weight 1 maxconn 500 check backup

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

1
  • 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, 2011 at 8:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .