Skip to content

Commit 1b02912

Browse files
committed
Least connections algorithm
1 parent dc68d3b commit 1b02912

File tree

3 files changed

+91
-4
lines changed

3 files changed

+91
-4
lines changed

src/vmod_dynamic.c

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,57 @@ dom_wait_active(struct dynamic_domain *dom)
251251
DBG(NULL, dom, "wait-active ret %d", ret);
252252
}
253253

254+
/* find a healthy dynamic_ref with the least connections */
255+
static struct dynamic_ref *
256+
dom_find_leastconn(VRT_CTX, struct dynamic_domain *dom)
257+
{
258+
struct dynamic_ref *next, *start, *best_next;
259+
unsigned most_connections_available;
260+
261+
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
262+
CHECK_OBJ_NOTNULL(dom, DYNAMIC_DOMAIN_MAGIC);
263+
264+
dom_wait_active(dom);
265+
266+
if (dom->status > DYNAMIC_ST_ACTIVE)
267+
return (NULL);
268+
269+
next = dom->current;
270+
start = next;
271+
best_next = next;
272+
most_connections_available = 0;
273+
274+
do {
275+
CHECK_OBJ_ORNULL(next, DYNAMIC_REF_MAGIC);
276+
if (next != NULL)
277+
next = VTAILQ_NEXT(next, list);
278+
if (next == NULL)
279+
next = VTAILQ_FIRST(&dom->refs);
280+
if (next == NULL)
281+
break;
282+
283+
if (next->dir != creating && next->dir != NULL && VRT_Healthy(ctx, next->dir, NULL)) {
284+
if (VALID_OBJ((struct backend *)next->dir->priv, BACKEND_MAGIC)) {
285+
struct backend *be;
286+
unsigned connections_available;
287+
288+
CAST_OBJ_NOTNULL(be, next->dir->priv, BACKEND_MAGIC);
289+
connections_available = be->max_connections > 0 ? be->max_connections - be->n_conn : - be->n_conn;
290+
if (connections_available > most_connections_available) {
291+
best_next = next;
292+
most_connections_available = connections_available;
293+
}
294+
}
295+
}
296+
} while (next != start);
297+
298+
if (best_next != NULL) {
299+
return best_next;
300+
} else {
301+
return NULL;
302+
}
303+
}
304+
254305
/* find a healthy dynamic_ref */
255306
static struct dynamic_ref *
256307
dom_find(VRT_CTX, struct dynamic_domain *dom, struct dynamic_ref *start,
@@ -330,7 +381,7 @@ static VCL_BACKEND v_matchproto_(vdi_resolve_f)
330381
dom_resolve(VRT_CTX, VCL_BACKEND d)
331382
{
332383
struct dynamic_domain *dom;
333-
struct dynamic_ref *r;
384+
struct dynamic_ref *r = NULL;
334385
VCL_BACKEND n = NULL;
335386

336387
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
@@ -348,7 +399,12 @@ dom_resolve(VRT_CTX, VCL_BACKEND d)
348399
dynamic_gc_expired(dom->obj);
349400

350401
Lck_Lock(&dom->mtx);
351-
r = dom_find(ctx, dom, dom->current, NULL, NULL, 1);
402+
if (dom->obj->algorithm == LEAST) {
403+
r = dom_find_leastconn(ctx, dom);
404+
}
405+
if (r == NULL) {
406+
r = dom_find(ctx, dom, dom->current, NULL, NULL, 1);
407+
}
352408
dom->current = r;
353409
if (r != NULL)
354410
VRT_Assign_Backend(&n, r->dir);
@@ -1306,6 +1362,18 @@ dynamic_ttl_parse(const char *s)
13061362
INCOMPL();
13071363
}
13081364

1365+
static inline enum dynamic_algorithm_e
1366+
dynamic_algorithm_parse(const char *algorithm_s)
1367+
{
1368+
switch (algorithm_s[0]) {
1369+
case 'R': return RR; break;
1370+
case 'L': return LEAST; break;
1371+
default: INCOMPL();
1372+
}
1373+
INCOMPL();
1374+
NEEDLESS(return(0));
1375+
}
1376+
13091377

13101378
VCL_VOID v_matchproto_()
13111379
vmod_director__init(VRT_CTX,
@@ -1329,7 +1397,8 @@ vmod_director__init(VRT_CTX,
13291397
VCL_DURATION retry_after,
13301398
VCL_BACKEND via,
13311399
VCL_INT keep,
1332-
VCL_STRING authority)
1400+
VCL_STRING authority,
1401+
VCL_ENUM algorithm_arg)
13331402
{
13341403
struct vmod_dynamic_director *obj;
13351404

@@ -1402,6 +1471,7 @@ vmod_director__init(VRT_CTX,
14021471
obj->max_connections = (unsigned)max_connections;
14031472
obj->proxy_header = (unsigned)proxy_header;
14041473
obj->ttl_from = dynamic_ttl_parse(ttl_from_arg);
1474+
obj->algorithm = dynamic_algorithm_parse(algorithm_arg);
14051475
obj->keep = (unsigned)keep;
14061476

14071477
if (resolver != NULL) {

src/vmod_dynamic.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ enum dynamic_ttl_e {
7676
TTL_E_MAX
7777
};
7878

79+
enum dynamic_algorithm_e {
80+
RR,
81+
LEAST
82+
};
83+
7984
struct dynamic_domain {
8085
unsigned magic;
8186
#define DYNAMIC_DOMAIN_MAGIC 0x1bfe1345
@@ -203,6 +208,7 @@ struct vmod_dynamic_director {
203208
const struct res_cb *resolver;
204209
struct VPFX(dynamic_resolver) *resolver_inst;
205210
enum dynamic_ttl_e ttl_from;
211+
enum dynamic_algorithm_e algorithm;
206212
unsigned debug;
207213
};
208214

src/vmod_dynamic.vcc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ $Object director(
250250
DURATION retry_after = 30,
251251
BACKEND via = NULL,
252252
INT keep = 3,
253-
STRING authority = NULL)
253+
STRING authority = NULL,
254+
ENUM { RR, LEAST } algorithm = "RR")
254255

255256
Description
256257
Create a DNS director.
@@ -364,6 +365,16 @@ Parameters:
364365
a high positive value (``UINT_MAX``, usually 4 294 967 295,
365366
see :ref:`limits.h(7POSIX)`).
366367

368+
- *algorithm* (default: RR)
369+
370+
Load balancing algorithm to use.
371+
372+
``RR`` cycles between health backends.
373+
374+
``LEAST`` chooses the healthy backend with the most number of connections available
375+
(i.e. the difference between ``max_connections`` and the backends current connections).
376+
The algorithm works in a similar way if ``max_connections`` isn't set.
377+
367378
Parameters to set attributes of backends
368379

369380
See varnish documentation for details

0 commit comments

Comments
 (0)