Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Least connections algorithm #128

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 70 additions & 3 deletions src/vmod_dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,54 @@ dom_wait_active(struct dynamic_domain *dom)
DBG(NULL, dom, "wait-active ret %d", ret);
}

/* find a healthy dynamic_ref with the least connections */
static struct dynamic_ref *
dom_find_leastconn(VRT_CTX, struct dynamic_domain *dom)
{
struct dynamic_ref *next, *best_next;
int most_connections_available;

CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(dom, DYNAMIC_DOMAIN_MAGIC);

dom_wait_active(dom);

if (dom->status > DYNAMIC_ST_ACTIVE)
return (NULL);

next = VTAILQ_FIRST(&dom->refs);
best_next = NULL;
most_connections_available = INT_MIN;

do {
CHECK_OBJ_ORNULL(next, DYNAMIC_REF_MAGIC);
if (next == NULL)
break;

if (next->dir != creating && next->dir != NULL && VRT_Healthy(ctx, next->dir, NULL)) {
if (VALID_OBJ((struct backend *)next->dir->priv, BACKEND_MAGIC)) {
struct backend *be;
int connections_available;

CAST_OBJ_NOTNULL(be, next->dir->priv, BACKEND_MAGIC);
connections_available = be->max_connections > 0 ? be->max_connections - be->n_conn : - be->n_conn;
if (connections_available > most_connections_available) {
best_next = next;
most_connections_available = connections_available;
}
}
}

next = VTAILQ_NEXT(next, list);
} while (1);

if (best_next != NULL) {
return best_next;
} else {
return NULL;
}
}

/* find a healthy dynamic_ref */
static struct dynamic_ref *
dom_find(VRT_CTX, struct dynamic_domain *dom, struct dynamic_ref *start,
Expand Down Expand Up @@ -330,7 +378,7 @@ static VCL_BACKEND v_matchproto_(vdi_resolve_f)
dom_resolve(VRT_CTX, VCL_BACKEND d)
{
struct dynamic_domain *dom;
struct dynamic_ref *r;
struct dynamic_ref *r = NULL;
VCL_BACKEND n = NULL;

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

Lck_Lock(&dom->mtx);
r = dom_find(ctx, dom, dom->current, NULL, NULL, 1);
if (dom->obj->algorithm == LEAST) {
r = dom_find_leastconn(ctx, dom);
}
if (r == NULL) {
r = dom_find(ctx, dom, dom->current, NULL, NULL, 1);
}
dom->current = r;
if (r != NULL)
VRT_Assign_Backend(&n, r->dir);
Expand Down Expand Up @@ -1308,6 +1361,18 @@ dynamic_ttl_parse(const char *s)
INCOMPL();
}

static inline enum dynamic_algorithm_e
dynamic_algorithm_parse(const char *algorithm_s)
{
switch (algorithm_s[0]) {
case 'R': return RR; break;
case 'L': return LEAST; break;
default: INCOMPL();
}
INCOMPL();
NEEDLESS(return(0));
}


VCL_VOID v_matchproto_()
vmod_director__init(VRT_CTX,
Expand All @@ -1333,7 +1398,8 @@ vmod_director__init(VRT_CTX,
VCL_INT keep,
VCL_STRING authority,
VCL_DURATION wait_timeout,
VCL_INT wait_limit)
VCL_INT wait_limit,
VCL_ENUM algorithm_arg)
{
struct vmod_dynamic_director *obj;

Expand Down Expand Up @@ -1406,6 +1472,7 @@ vmod_director__init(VRT_CTX,
obj->max_connections = (unsigned)max_connections;
obj->proxy_header = (unsigned)proxy_header;
obj->ttl_from = dynamic_ttl_parse(ttl_from_arg);
obj->algorithm = dynamic_algorithm_parse(algorithm_arg);
obj->keep = (unsigned)keep;
obj->wait_timeout = wait_timeout;
obj->wait_limit = wait_limit;
Expand Down
6 changes: 6 additions & 0 deletions src/vmod_dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ enum dynamic_ttl_e {
TTL_E_MAX
};

enum dynamic_algorithm_e {
RR,
LEAST
};

struct dynamic_domain {
unsigned magic;
#define DYNAMIC_DOMAIN_MAGIC 0x1bfe1345
Expand Down Expand Up @@ -205,6 +210,7 @@ struct vmod_dynamic_director {
const struct res_cb *resolver;
struct VPFX(dynamic_resolver) *resolver_inst;
enum dynamic_ttl_e ttl_from;
enum dynamic_algorithm_e algorithm;
unsigned debug;
};

Expand Down
13 changes: 12 additions & 1 deletion src/vmod_dynamic.vcc
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ $Object director(
INT keep = 3,
STRING authority = NULL,
DURATION wait_timeout = -1,
INT wait_limit = 0)
INT wait_limit = 0,
ENUM { RR, LEAST } algorithm = "RR")

Description
Create a DNS director.
Expand Down Expand Up @@ -366,6 +367,16 @@ Parameters:
a high positive value (``UINT_MAX``, usually 4 294 967 295,
see :ref:`limits.h(7POSIX)`).

- *algorithm* (default: RR)

Load balancing algorithm to use.

``RR`` cycles between health backends.

``LEAST`` chooses the healthy backend with the most number of connections available
(i.e. the difference between ``max_connections`` and the backends current connections).
The algorithm works in a similar way if ``max_connections`` isn't set.

Parameters to set attributes of backends

See varnish documentation for details
Expand Down