Skip to content

Commit 2f02ab0

Browse files
committed
Least connections algorithm
Least connections algorithm
1 parent dc68d3b commit 2f02ab0

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

src/vmod_dynamic.c

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,54 @@ 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, *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 = VTAILQ_FIRST(&dom->refs);
270+
best_next = NULL;
271+
most_connections_available = 0;
272+
273+
do {
274+
CHECK_OBJ_ORNULL(next, DYNAMIC_REF_MAGIC);
275+
if (next != NULL)
276+
next = VTAILQ_NEXT(next, list);
277+
if (next == NULL)
278+
break;
279+
280+
if (next->dir != creating && next->dir != NULL && VRT_Healthy(ctx, next->dir, NULL)) {
281+
if (VALID_OBJ((struct backend *)next->dir->priv, BACKEND_MAGIC)) {
282+
struct backend *be;
283+
unsigned connections_available;
284+
285+
CAST_OBJ_NOTNULL(be, next->dir->priv, BACKEND_MAGIC);
286+
connections_available = be->max_connections > 0 ? be->max_connections - be->n_conn : - be->n_conn;
287+
if (connections_available > most_connections_available) {
288+
best_next = next;
289+
most_connections_available = connections_available;
290+
}
291+
}
292+
}
293+
} while (1);
294+
295+
if (best_next != NULL) {
296+
return best_next;
297+
} else {
298+
return NULL;
299+
}
300+
}
301+
254302
/* find a healthy dynamic_ref */
255303
static struct dynamic_ref *
256304
dom_find(VRT_CTX, struct dynamic_domain *dom, struct dynamic_ref *start,
@@ -330,7 +378,7 @@ static VCL_BACKEND v_matchproto_(vdi_resolve_f)
330378
dom_resolve(VRT_CTX, VCL_BACKEND d)
331379
{
332380
struct dynamic_domain *dom;
333-
struct dynamic_ref *r;
381+
struct dynamic_ref *r = NULL;
334382
VCL_BACKEND n = NULL;
335383

336384
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
@@ -348,7 +396,12 @@ dom_resolve(VRT_CTX, VCL_BACKEND d)
348396
dynamic_gc_expired(dom->obj);
349397

350398
Lck_Lock(&dom->mtx);
351-
r = dom_find(ctx, dom, dom->current, NULL, NULL, 1);
399+
if (dom->obj->algorithm == LEAST) {
400+
r = dom_find_leastconn(ctx, dom);
401+
}
402+
if (r == NULL) {
403+
r = dom_find(ctx, dom, dom->current, NULL, NULL, 1);
404+
}
352405
dom->current = r;
353406
if (r != NULL)
354407
VRT_Assign_Backend(&n, r->dir);
@@ -1306,6 +1359,18 @@ dynamic_ttl_parse(const char *s)
13061359
INCOMPL();
13071360
}
13081361

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

13101375
VCL_VOID v_matchproto_()
13111376
vmod_director__init(VRT_CTX,
@@ -1329,7 +1394,8 @@ vmod_director__init(VRT_CTX,
13291394
VCL_DURATION retry_after,
13301395
VCL_BACKEND via,
13311396
VCL_INT keep,
1332-
VCL_STRING authority)
1397+
VCL_STRING authority,
1398+
VCL_ENUM algorithm_arg)
13331399
{
13341400
struct vmod_dynamic_director *obj;
13351401

@@ -1402,6 +1468,7 @@ vmod_director__init(VRT_CTX,
14021468
obj->max_connections = (unsigned)max_connections;
14031469
obj->proxy_header = (unsigned)proxy_header;
14041470
obj->ttl_from = dynamic_ttl_parse(ttl_from_arg);
1471+
obj->algorithm = dynamic_algorithm_parse(algorithm_arg);
14051472
obj->keep = (unsigned)keep;
14061473

14071474
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)