blob: a1e1d34927f9eaa14d74234a0f00862d1c87fc5d [file] [log] [blame]
Willy Tarreauf89c1872009-10-01 11:19:37 +02001/*
2 * Map-based load-balancing (RR and HASH)
3 *
4 * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <common/compat.h>
14#include <common/config.h>
15#include <common/debug.h>
Willy Tarreau45cb4fb2009-10-26 21:10:04 +010016#include <eb32tree.h>
Willy Tarreauf89c1872009-10-01 11:19:37 +020017
18#include <types/global.h>
19#include <types/server.h>
20
21#include <proto/backend.h>
Christopher Faulet5b517552017-06-09 14:17:53 +020022#include <proto/lb_map.h>
Willy Tarreauf89c1872009-10-01 11:19:37 +020023#include <proto/proto_http.h>
24#include <proto/proto_tcp.h>
25#include <proto/queue.h>
26
27/* this function updates the map according to server <srv>'s new state */
28static void map_set_server_status_down(struct server *srv)
29{
30 struct proxy *p = srv->proxy;
31
Willy Tarreauc5150da2014-05-13 19:27:31 +020032 if (!srv_lb_status_changed(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020033 return;
34
Emeric Brun52a91d32017-08-31 14:41:55 +020035 if (srv_willbe_usable(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020036 goto out_update_state;
37
38 /* FIXME: could be optimized since we know what changed */
39 recount_servers(p);
40 update_backend_weight(p);
Christopher Faulet5b517552017-06-09 14:17:53 +020041 recalc_server_map(p);
Willy Tarreauf89c1872009-10-01 11:19:37 +020042 out_update_state:
Willy Tarreauc5150da2014-05-13 19:27:31 +020043 srv_lb_commit_status(srv);
Willy Tarreauf89c1872009-10-01 11:19:37 +020044}
45
46/* This function updates the map according to server <srv>'s new state */
47static void map_set_server_status_up(struct server *srv)
48{
49 struct proxy *p = srv->proxy;
50
Willy Tarreauc5150da2014-05-13 19:27:31 +020051 if (!srv_lb_status_changed(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020052 return;
53
Emeric Brun52a91d32017-08-31 14:41:55 +020054 if (!srv_willbe_usable(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020055 goto out_update_state;
56
57 /* FIXME: could be optimized since we know what changed */
58 recount_servers(p);
59 update_backend_weight(p);
Christopher Faulet5b517552017-06-09 14:17:53 +020060 recalc_server_map(p);
Willy Tarreauf89c1872009-10-01 11:19:37 +020061 out_update_state:
Willy Tarreauc5150da2014-05-13 19:27:31 +020062 srv_lb_commit_status(srv);
Willy Tarreauf89c1872009-10-01 11:19:37 +020063}
64
65/* This function recomputes the server map for proxy px. It relies on
66 * px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be
67 * called after recount_servers(). It also expects px->lbprm.map.srv
68 * to be allocated with the largest size needed. It updates tot_weight.
69 */
70void recalc_server_map(struct proxy *px)
71{
72 int o, tot, flag;
73 struct server *cur, *best;
74
75 switch (px->lbprm.tot_used) {
76 case 0: /* no server */
Willy Tarreauf89c1872009-10-01 11:19:37 +020077 return;
Willy Tarreauf89c1872009-10-01 11:19:37 +020078 default:
79 tot = px->lbprm.tot_weight;
80 break;
81 }
82
83 /* here we *know* that we have some servers */
84 if (px->srv_act)
Willy Tarreauc93cd162014-05-13 15:54:22 +020085 flag = 0;
Willy Tarreauf89c1872009-10-01 11:19:37 +020086 else
Willy Tarreauc93cd162014-05-13 15:54:22 +020087 flag = SRV_F_BACKUP;
Willy Tarreauf89c1872009-10-01 11:19:37 +020088
89 /* this algorithm gives priority to the first server, which means that
90 * it will respect the declaration order for equivalent weights, and
91 * that whatever the weights, the first server called will always be
92 * the first declared. This is an important asumption for the backup
93 * case, where we want the first server only.
94 */
95 for (cur = px->srv; cur; cur = cur->next)
96 cur->wscore = 0;
97
98 for (o = 0; o < tot; o++) {
99 int max = 0;
100 best = NULL;
101 for (cur = px->srv; cur; cur = cur->next) {
Willy Tarreau9943d312014-05-22 16:20:59 +0200102 if ((cur->flags & SRV_F_BACKUP) == flag &&
Emeric Brun52a91d32017-08-31 14:41:55 +0200103 srv_willbe_usable(cur)) {
Willy Tarreauf89c1872009-10-01 11:19:37 +0200104 int v;
105
106 /* If we are forced to return only one server, we don't want to
107 * go further, because we would return the wrong one due to
108 * divide overflow.
109 */
110 if (tot == 1) {
111 best = cur;
112 /* note that best->wscore will be wrong but we don't care */
113 break;
114 }
115
Christopher Faulet5b517552017-06-09 14:17:53 +0200116 HA_ATOMIC_ADD(&cur->wscore, cur->next_eweight);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200117 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
118 if (best == NULL || v > max) {
119 max = v;
120 best = cur;
121 }
122 }
123 }
124 px->lbprm.map.srv[o] = best;
Cyril Bonté3906d572017-12-14 16:39:26 +0100125 HA_ATOMIC_SUB(&best->wscore, tot);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200126 }
Willy Tarreauf89c1872009-10-01 11:19:37 +0200127}
128
129/* This function is responsible of building the server MAP for map-based LB
130 * algorithms, allocating the map, and setting p->lbprm.wmult to the GCD of the
131 * weights if applicable. It should be called only once per proxy, at config
132 * time.
133 */
134void init_server_map(struct proxy *p)
135{
136 struct server *srv;
137 int pgcd;
138 int act, bck;
139
140 p->lbprm.set_server_status_up = map_set_server_status_up;
141 p->lbprm.set_server_status_down = map_set_server_status_down;
142 p->lbprm.update_server_eweight = NULL;
143
144 if (!p->srv)
145 return;
146
147 /* We will factor the weights to reduce the table,
148 * using Euclide's largest common divisor algorithm.
149 * Since we may have zero weights, we have to first
150 * find a non-zero weight server.
151 */
152 pgcd = 1;
153 srv = p->srv;
154 while (srv && !srv->uweight)
155 srv = srv->next;
156
157 if (srv) {
158 pgcd = srv->uweight; /* note: cannot be zero */
159 while (pgcd > 1 && (srv = srv->next)) {
160 int w = srv->uweight;
161 while (w) {
162 int t = pgcd % w;
163 pgcd = w;
164 w = t;
165 }
166 }
167 }
168
169 /* It is sometimes useful to know what factor to apply
170 * to the backend's effective weight to know its real
171 * weight.
172 */
173 p->lbprm.wmult = pgcd;
174
175 act = bck = 0;
176 for (srv = p->srv; srv; srv = srv->next) {
Emeric Brun52a91d32017-08-31 14:41:55 +0200177 srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult;
Willy Tarreauc5150da2014-05-13 19:27:31 +0200178
Willy Tarreauc93cd162014-05-13 15:54:22 +0200179 if (srv->flags & SRV_F_BACKUP)
Emeric Brun52a91d32017-08-31 14:41:55 +0200180 bck += srv->next_eweight;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200181 else
Emeric Brun52a91d32017-08-31 14:41:55 +0200182 act += srv->next_eweight;
183 srv_lb_commit_status(srv);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200184 }
185
186 /* this is the largest map we will ever need for this servers list */
187 if (act < bck)
188 act = bck;
189
190 if (!act)
191 act = 1;
192
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200193 p->lbprm.map.srv = calloc(act, sizeof(struct server *));
Willy Tarreauf89c1872009-10-01 11:19:37 +0200194 /* recounts servers and their weights */
Willy Tarreauf89c1872009-10-01 11:19:37 +0200195 recount_servers(p);
196 update_backend_weight(p);
197 recalc_server_map(p);
198}
199
200/*
201 * This function tries to find a running server with free connection slots for
202 * the proxy <px> following the round-robin method.
203 * If any server is found, it will be returned and px->lbprm.map.rr_idx will be updated
204 * to point to the next server. If no valid server is found, NULL is returned.
205 */
206struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid)
207{
208 int newidx, avoididx;
209 struct server *srv, *avoided;
210
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100211 HA_SPIN_LOCK(LBPRM_LOCK, &px->lbprm.lock);
Christopher Faulet5b517552017-06-09 14:17:53 +0200212 if (px->lbprm.tot_weight == 0) {
213 avoided = NULL;
214 goto out;
215 }
Willy Tarreauf89c1872009-10-01 11:19:37 +0200216
217 if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight)
218 px->lbprm.map.rr_idx = 0;
219 newidx = px->lbprm.map.rr_idx;
220
221 avoided = NULL;
222 avoididx = 0; /* shut a gcc warning */
223 do {
224 srv = px->lbprm.map.srv[newidx++];
Godbach8f9fd2f2013-08-07 09:48:23 +0800225 if (!srv->maxconn || (!srv->nbpend && srv->served < srv_dynamic_maxconn(srv))) {
Willy Tarreauf89c1872009-10-01 11:19:37 +0200226 /* make sure it is not the server we are try to exclude... */
Willy Tarreau03071f62017-11-05 10:59:12 +0100227 /* ...but remember that is was selected yet avoided */
228 avoided = srv;
229 avoididx = newidx;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200230 if (srv != srvtoavoid) {
231 px->lbprm.map.rr_idx = newidx;
Willy Tarreau03071f62017-11-05 10:59:12 +0100232 goto out;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200233 }
Willy Tarreauf89c1872009-10-01 11:19:37 +0200234 }
235 if (newidx == px->lbprm.tot_weight)
236 newidx = 0;
237 } while (newidx != px->lbprm.map.rr_idx);
238
239 if (avoided)
240 px->lbprm.map.rr_idx = avoididx;
241
Christopher Faulet5b517552017-06-09 14:17:53 +0200242 out:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100243 HA_SPIN_UNLOCK(LBPRM_LOCK, &px->lbprm.lock);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200244 /* return NULL or srvtoavoid if found */
245 return avoided;
246}
247
Willy Tarreau39c9ba72009-10-01 21:11:15 +0200248/*
249 * This function returns the running server from the map at the location
250 * pointed to by the result of a modulo operation on <hash>. The server map may
251 * be recomputed if required before being looked up. If any server is found, it
252 * will be returned. If no valid server is found, NULL is returned.
253 */
254struct server *map_get_server_hash(struct proxy *px, unsigned int hash)
255{
256 if (px->lbprm.tot_weight == 0)
257 return NULL;
Willy Tarreau39c9ba72009-10-01 21:11:15 +0200258 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
259}
260
Willy Tarreauf89c1872009-10-01 11:19:37 +0200261
262/*
263 * Local variables:
264 * c-indent-level: 8
265 * c-basic-offset: 8
266 * End:
267 */