src/ebmbtree.o src/cfgcond.o src/action.o src/xprt_handshake.o \
src/protocol.o src/proto_uxst.o src/proto_udp.o src/lb_map.o \
src/fix.o src/ev_select.o src/arg.o src/sock_inet.o src/event_hdl.o \
- src/mworker-prog.o src/hpack-dec.o src/cfgparse-tcp.o \
+ src/mworker-prog.o src/hpack-dec.o src/cfgparse-tcp.o src/lb_ss.o \
src/sock_unix.o src/shctx.o src/proto_uxdg.o src/fcgi.o \
src/eb64tree.o src/clock.o src/chunk.o src/cfgdiag.o src/signal.o \
src/regex.o src/lru.o src/eb32tree.o src/eb32sctree.o \
the log messages. When the server goes DOWN, the next server
in the list takes its place. When a previously DOWN server
goes back UP it is added at the end of the list so that the
- sticky server doesn't change until it becomes DOWN. This
- algorithm is only usable for backends in LOG mode.
+ sticky server doesn't change until it becomes DOWN.
<arguments> is an optional list of arguments which may be needed by some
algorithms. Right now, only "url_param", "uri" and "log-hash"
#include <haproxy/lb_fwlc-t.h>
#include <haproxy/lb_fwrr-t.h>
#include <haproxy/lb_map-t.h>
+#include <haproxy/lb_ss-t.h>
#include <haproxy/server-t.h>
#include <haproxy/thread-t.h>
#define BE_LB_CB_LC 0x00000000 /* least-connections */
#define BE_LB_CB_FAS 0x00000001 /* first available server (opposite of leastconn) */
+/* BE_LB_SA_* is used with BE_LB_KIND_SA */
+#define BE_LB_SA_SS 0x00000000 /* stick to server as long as it is available */
+
#define BE_LB_PARM 0x000000FF /* mask to get/clear the LB param */
/* Required input(s) */
#define BE_LB_KIND_RR 0x00010000 /* round-robin */
#define BE_LB_KIND_CB 0x00020000 /* connection-based */
#define BE_LB_KIND_HI 0x00030000 /* hash of input (see hash inputs above) */
+#define BE_LB_KIND_SA 0x00040000 /* standalone (specific algorithms, cannot be grouped) */
#define BE_LB_KIND 0x00070000 /* mask to get/clear LB algorithm */
/* All known variants of load balancing algorithms. These can be cleared using
#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_SS (BE_LB_KIND_SA | BE_LB_NEED_NONE | BE_LB_SA_SS) /* sticky */
#define BE_LB_ALGO_SRR (BE_LB_KIND_RR | BE_LB_NEED_NONE | BE_LB_RR_STATIC) /* static round robin */
#define BE_LB_ALGO_SH (BE_LB_KIND_HI | BE_LB_NEED_ADDR | BE_LB_HASH_SRC) /* hash: source IP */
#define BE_LB_ALGO_UH (BE_LB_KIND_HI | BE_LB_NEED_HTTP | BE_LB_HASH_URI) /* hash: HTTP URI */
#define BE_LB_ALGO_RCH (BE_LB_KIND_HI | BE_LB_NEED_DATA | BE_LB_HASH_RDP) /* hash: RDP cookie value */
#define BE_LB_ALGO_SMP (BE_LB_KIND_HI | BE_LB_NEED_DATA | BE_LB_HASH_SMP) /* hash: sample expression */
#define BE_LB_ALGO_LH (BE_LB_KIND_HI | BE_LB_NEED_LOG | BE_LB_HASH_SMP) /* log hash: sample expression */
-#define BE_LB_ALGO_LS (BE_LB_KIND_CB | BE_LB_NEED_LOG | BE_LB_CB_FAS) /* log sticky */
#define BE_LB_ALGO (BE_LB_KIND | BE_LB_NEED | BE_LB_PARM ) /* mask to clear algo */
/* Higher bits define how a given criterion is mapped to a server. In fact it
struct lb_fwlc fwlc;
struct lb_chash chash;
struct lb_fas fas;
+ struct lb_ss ss;
struct {
struct server **srv; /* array containing in-use log servers */
struct list avail; /* servers available for lb are registered in this list */
--- /dev/null
+/*
+ * include/haproxy/lb_ss-t.h
+ * Types for sticky load-balancing
+ *
+ * Copyright 2024 HAProxy Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _HAPROXY_LB_LH_T_H
+#define _HAPROXY_LB_LH_T_H
+
+#include <haproxy/api-t.h>
+#include <haproxy/server-t.h>
+
+struct lb_ss {
+ struct server *srv; /* sticked server */
+};
+
+#endif /* _HAPROXY_LB_LH_T_H */
--- /dev/null
+/*
+ * include/haproxy/lb_ss.h
+ * sticky load-balancing
+ *
+ * Copyright 2024 HAProxy Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _HAPROXY_LB_SS_H
+#define _HAPROXY_LB_SS_H
+
+#include <haproxy/api.h>
+#include <haproxy/proxy-t.h>
+#include <haproxy/server-t.h>
+
+void recalc_server_ss(struct proxy *px);
+void init_server_ss(struct proxy *px);
+struct server *ss_get_server(struct proxy *px);
+
+#endif /* _HAPROXY_LB_SS_H */
#include <haproxy/lb_fwlc.h>
#include <haproxy/lb_fwrr.h>
#include <haproxy/lb_map.h>
+#include <haproxy/lb_ss.h>
#include <haproxy/log.h>
#include <haproxy/namespace.h>
#include <haproxy/obj_type.h>
break;
default:
+ if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_SA) {
+ /* some special algos that cannot be grouped together */
+
+ if ((s->be->lbprm.algo & BE_LB_PARM) == BE_LB_SA_SS)
+ srv = ss_get_server(s->be);
+
+ break;
+ }
/* unknown balancing algorithm */
err = SRV_STATUS_INTERNAL;
goto out;
}
else if (strcmp(args[0], "sticky") == 0) {
curproxy->lbprm.algo &= ~BE_LB_ALGO;
- curproxy->lbprm.algo |= BE_LB_ALGO_LS;
+ curproxy->lbprm.algo |= BE_LB_ALGO_SS;
}
else {
memprintf(err, "only supports 'roundrobin', 'static-rr', 'leastconn', 'source', 'uri', 'url_param', 'hash', 'hdr(name)', 'rdp-cookie(name)', 'log-hash' and 'sticky' options.");
#include <haproxy/lb_fwlc.h>
#include <haproxy/lb_fwrr.h>
#include <haproxy/lb_map.h>
+#include <haproxy/lb_ss.h>
#include <haproxy/listener.h>
#include <haproxy/log.h>
#include <haproxy/sink.h>
init_server_map(curproxy);
}
break;
+ case BE_LB_KIND_SA:
+ if ((curproxy->lbprm.algo & BE_LB_PARM) == BE_LB_SA_SS) {
+ curproxy->lbprm.algo |= BE_LB_PROP_DYN;
+ init_server_ss(curproxy);
+ }
+ break;
}
skip_server_lb_init:
HA_RWLOCK_INIT(&curproxy->lbprm.lock);
--- /dev/null
+/*
+ * sticky load-balancing
+ *
+ * Copyright 2024 HAProxy Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <haproxy/api.h>
+#include <haproxy/backend.h>
+#include <haproxy/lb_ss.h>
+#include <haproxy/server-t.h>
+
+/* this function updates the stick server according to server <srv>'s new state.
+ *
+ * The server's lock must be held. The lbprm's lock will be used.
+ */
+static void ss_set_server_status_down(struct server *srv)
+{
+ struct proxy *p = srv->proxy;
+
+ if (!srv_lb_status_changed(srv))
+ return;
+
+ if (srv_willbe_usable(srv))
+ goto out_update_state;
+
+ HA_RWLOCK_WRLOCK(LBPRM_LOCK, &p->lbprm.lock);
+
+ if (!srv_currently_usable(srv))
+ /* server was already down */
+ goto out_update_backend;
+
+ if (srv->flags & SRV_F_BACKUP) {
+ p->lbprm.tot_wbck -= srv->cur_eweight;
+ p->srv_bck--;
+ } else {
+ p->lbprm.tot_wact -= srv->cur_eweight;
+ p->srv_act--;
+ }
+ if (srv == p->lbprm.ss.srv) {
+ /* sticked server is down, elect a new server
+ * that we will be sticking on.
+ */
+ recalc_server_ss(p);
+ }
+
+ out_update_backend:
+ /* check/update tot_used, tot_weight */
+ update_backend_weight(p);
+ HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &p->lbprm.lock);
+
+ out_update_state:
+ srv_lb_commit_status(srv);
+}
+
+/* This function updates the stick server according to server <srv>'s new state.
+ *
+ * The server's lock must be held. The lbprm's lock will be used.
+ */
+static void ss_set_server_status_up(struct server *srv)
+{
+ struct proxy *p = srv->proxy;
+
+ if (!srv_lb_status_changed(srv))
+ return;
+
+ if (!srv_willbe_usable(srv))
+ goto out_update_state;
+
+ HA_RWLOCK_WRLOCK(LBPRM_LOCK, &p->lbprm.lock);
+
+ if (srv_currently_usable(srv))
+ /* server was already up */
+ goto out_update_backend;
+
+ if (srv->flags & SRV_F_BACKUP) {
+ p->lbprm.tot_wbck += srv->next_eweight;
+ p->srv_bck++;
+ } else {
+ p->lbprm.tot_wact += srv->next_eweight;
+ p->srv_act++;
+ }
+ if (!p->lbprm.ss.srv ||
+ ((p->lbprm.ss.srv->flags & SRV_F_BACKUP) && !(srv->flags & SRV_F_BACKUP))) {
+ /* we didn't have a server or were sticking on a backup server,
+ * but now we have an active server, let's switch to it
+ */
+ p->lbprm.ss.srv = srv;
+ }
+
+ out_update_backend:
+ /* check/update tot_used, tot_weight */
+ update_backend_weight(p);
+ HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &p->lbprm.lock);
+
+ out_update_state:
+ srv_lb_commit_status(srv);
+}
+
+/* This function elects a new stick server for proxy px.
+ *
+ * The lbprm's lock must be held.
+ */
+void recalc_server_ss(struct proxy *px)
+{
+ struct server *cur, *first;
+ int flag;
+
+ if (!px->lbprm.tot_used)
+ return; /* no server */
+
+ /* here we *know* that we have some servers */
+ if (px->srv_act)
+ flag = 0;
+ else
+ flag = SRV_F_BACKUP;
+
+ first = NULL;
+
+ for (cur = px->srv; cur; cur = cur->next) {
+ if ((cur->flags & SRV_F_BACKUP) == flag &&
+ srv_willbe_usable(cur)) {
+ first = cur;
+ break;
+ }
+ }
+ px->lbprm.ss.srv = first;
+}
+
+/* This function is responsible for preparing sticky LB algorithm.
+ * It should be called only once per proxy, at config time.
+ */
+void init_server_ss(struct proxy *p)
+{
+ struct server *srv;
+
+ p->lbprm.set_server_status_up = ss_set_server_status_up;
+ p->lbprm.set_server_status_down = ss_set_server_status_down;
+ p->lbprm.update_server_eweight = NULL;
+
+ if (!p->srv)
+ return;
+
+ for (srv = p->srv; srv; srv = srv->next) {
+ srv->next_eweight = 1; /* ignore weights, all servers have the same weight */
+ srv_lb_commit_status(srv);
+ }
+
+ /* recounts servers and their weights */
+ recount_servers(p);
+ update_backend_weight(p);
+ recalc_server_ss(p);
+}
+
+/*
+ * This function returns the server that we're sticking on. If any server
+ * is found, it will be returned. If no valid server is found, NULL is
+ * returned.
+ *
+ * The lbprm's lock will be used.
+ */
+struct server *ss_get_server(struct proxy *px)
+{
+ struct server *srv = NULL;
+
+ HA_RWLOCK_RDLOCK(LBPRM_LOCK, &px->lbprm.lock);
+ srv = px->lbprm.ss.srv;
+ HA_RWLOCK_RDUNLOCK(LBPRM_LOCK, &px->lbprm.lock);
+ return srv;
+}
}
if (balance_algo != BE_LB_ALGO_RR &&
balance_algo != BE_LB_ALGO_RND &&
- balance_algo != BE_LB_ALGO_LS &&
+ balance_algo != BE_LB_ALGO_SS &&
balance_algo != BE_LB_ALGO_LH) {
ha_alert("in %s '%s': \"balance\" only supports 'roundrobin', 'random', 'sticky' and 'log-hash'.\n", proxy_type_str(be), be->id);
err_code |= ERR_ALERT | ERR_FATAL;
*/
targetid = HA_ATOMIC_FETCH_ADD(&be->lbprm.log.lastid, 1) % nb_srv;
}
- else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_LS) {
+ else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_SS) {
/* sticky mode: use first server in the pool, which will always stay
* first during dequeuing and requeuing, unless it becomes unavailable
* and will be replaced by another one