]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: backend: implement random-based load balancing
authorWilly Tarreau <w@1wt.eu>
Thu, 3 May 2018 05:20:40 +0000 (07:20 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 3 May 2018 05:20:40 +0000 (07:20 +0200)
For large farms where servers are regularly added or removed, picking
a random server from the pool can ensure faster load transitions than
when using round-robin and less traffic surges on the newly added
servers than when using leastconn.

This commit introduces "balance random". It internally uses a random as
the key to the consistent hashing mechanism, thus all features available
in consistent hashing such as weights and bounded load via hash-balance-
factor are usable. It is extremely convenient because one common concern
when using random is what happens when a server is hammered a bit too
much. Here that can trivially be avoided, like in the configuration below :

    backend bk0
        balance random
        hash-balance-factor 110
        server-template s 1-100 127.0.0.1:8000 check inter 1s

Note that while "balance random" internally relies on a hash algorithm,
it holds the same properties as round-robin and as such is compatible with
reusing an existing server connection with "option prefer-last-server".

doc/configuration.txt
include/types/backend.h
src/backend.c
src/cfgparse.c

index 3bea4d659ef2ca09e252ec193b0df97a98114c95..cbea3309da3cc0740b61d9b7d272d20dbc4e90d2 100644 (file)
@@ -2444,6 +2444,16 @@ balance url_param <param> [check_post]
                   changing a server's weight on the fly will have no effect,
                   but this can be changed using "hash-type".
 
+      random      A random number will be used as the key for the consistent
+                  hashing function. This means that the servers' weights are
+                  respected, dynamic weight changes immediately take effect, as
+                  well as new server additions. Random load balancing can be
+                  useful with large farms or when servers are frequently added
+                  or removed. The hash-balance-factor directive can be used to
+                  further improve fairness of the load balancing, especially
+                  in situations where servers show highly variable response
+                  times.
+
       rdp-cookie
       rdp-cookie(<name>)
                   The RDP cookie <name> (or "mstshash" if omitted) will be
@@ -3642,6 +3652,9 @@ hash-balance-factor <factor>
   lower <factor> means that more servers will be checked on average, affecting
   performance. Reasonable values are from 125 to 200.
 
+  This setting is also used by "balance random" which internally relies on the
+  consistent hashing mechanism.
+
   See also : "balance" and "hash-type".
 
 
index c7f9fa3274ff9714fc5e3902d36ae6df11a5acb3..b36cd4112c2d6ddb72a700adf88245e47a590d90 100644 (file)
 #define BE_LB_HASH_PRM  0x00002  /* hash HTTP URL parameter */
 #define BE_LB_HASH_HDR  0x00003  /* hash HTTP header value */
 #define BE_LB_HASH_RDP  0x00004  /* hash RDP cookie value */
+#define BE_LB_HASH_RND  0x00008  /* hash a random value */
 
 /* BE_LB_RR_* is used with BE_LB_KIND_RR */
 #define BE_LB_RR_DYN    0x00000  /* dynamic round robin (default) */
 #define BE_LB_RR_STATIC 0x00001  /* static round robin */
+#define BE_LB_RR_RANDOM 0x00002  /* random round robin */
 
 /* BE_LB_CB_* is used with BE_LB_KIND_CB */
 #define BE_LB_CB_LC     0x00000  /* least-connections */
@@ -79,6 +81,7 @@
  */
 #define BE_LB_ALGO_NONE (BE_LB_KIND_NONE | BE_LB_NEED_NONE)    /* not defined */
 #define BE_LB_ALGO_RR   (BE_LB_KIND_RR | BE_LB_NEED_NONE)      /* round robin */
+#define BE_LB_ALGO_RND  (BE_LB_KIND_RR | BE_LB_NEED_NONE | BE_LB_RR_RANDOM) /* random value */
 #define BE_LB_ALGO_LC   (BE_LB_KIND_CB | BE_LB_NEED_NONE | BE_LB_CB_LC)    /* least connections */
 #define BE_LB_ALGO_FAS  (BE_LB_KIND_CB | BE_LB_NEED_NONE | BE_LB_CB_FAS)   /* first available server */
 #define BE_LB_ALGO_SRR  (BE_LB_KIND_RR | BE_LB_NEED_NONE | BE_LB_RR_STATIC) /* static round robin */
index 2b6167dc2d2b96d277f09601148b46385fae11e8..8473efbd80831546069e5e4736706d851a08a07a 100644 (file)
@@ -513,6 +513,21 @@ static struct server *get_server_rch(struct stream *s)
                return map_get_server_hash(px, hash);
 }
 
+/* random value  */
+static struct server *get_server_rnd(struct stream *s)
+{
+       unsigned int hash = 0;
+       struct proxy  *px = s->be;
+
+       /* tot_weight appears to mean srv_count */
+       if (px->lbprm.tot_weight == 0)
+               return NULL;
+
+       /* ensure all 32 bits are covered as long as RAND_MAX >= 65535 */
+       hash = ((uint64_t)random() * ((uint64_t)RAND_MAX + 1)) ^ random();
+       return chash_get_server_hash(px, hash);
+}
+
 /*
  * This function applies the load-balancing algorithm to the stream, as
  * defined by the backend it is assigned to. The stream is then marked as
@@ -615,7 +630,9 @@ int assign_server(struct stream *s)
                case BE_LB_LKUP_CHTREE:
                case BE_LB_LKUP_MAP:
                        if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
-                               if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
+                               if ((s->be->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM)
+                                       srv = get_server_rnd(s);
+                               else if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
                                        srv = chash_get_next_server(s->be, prev_srv);
                                else
                                        srv = map_get_server_rr(s->be, prev_srv);
@@ -1503,6 +1520,10 @@ int backend_parse_balance(const char **args, char **err, struct proxy *curproxy)
                curproxy->lbprm.algo &= ~BE_LB_ALGO;
                curproxy->lbprm.algo |= BE_LB_ALGO_LC;
        }
+       else if (!strcmp(args[0], "random")) {
+               curproxy->lbprm.algo &= ~BE_LB_ALGO;
+               curproxy->lbprm.algo |= BE_LB_ALGO_RND;
+       }
        else if (!strcmp(args[0], "source")) {
                curproxy->lbprm.algo &= ~BE_LB_ALGO;
                curproxy->lbprm.algo |= BE_LB_ALGO_SH;
index 76535360ff21f1c2966731e86f3aac50df61e46a..024502c4b8639515fc7b85e14480204c428d722e 100644 (file)
@@ -8350,6 +8350,9 @@ out_uri_auth_compat:
                        if ((curproxy->lbprm.algo & BE_LB_PARM) == BE_LB_RR_STATIC) {
                                curproxy->lbprm.algo |= BE_LB_LKUP_MAP;
                                init_server_map(curproxy);
+                       } else if ((curproxy->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM) {
+                               curproxy->lbprm.algo |= BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN;
+                               chash_init_server_tree(curproxy);
                        } else {
                                curproxy->lbprm.algo |= BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN;
                                fwrr_init_server_groups(curproxy);