sticky load balancing: a core feature or
Niklas Norberg
niklas.norberg at bahnhof.se
Wed Apr 14 19:48:24 CEST 2010
You're welcome, here it is.
If you find it useful or find anything else please send me feedback.
Actually I figured out that it would have been best performance wise to
only set the backends i.e. look if there is a LB cookie and... when it's
necessary that is in vcl_fetch, vcl_pass, vcl_pipe and so on. But I'm
lasy and take this performance penalty to be sure to cover all cases
without digging to much, at least at this point.
So maybe the call:
call recv_loadBalancingOnStickyCookie;
should have been best placed in vcl_prefetch but that sub was removed in
2.1.0 :(
One can also hard code some C string lengths and so on...
Regards
Niklas
ons 2010-04-14 klockan 10:32 -0700 skrev Rob Rogers:
> thanks,
>
> would you mind sending or posting the entire LBSubs.vcl as a file?
>
> thank you.
>
> rob
> On Apr 14, 2010, at 10:27 AM, Niklas Norberg wrote:
>
> >
> > ons 2010-04-14 klockan 10:10 -0700 skrev Rob Rogers:
> >
> >
> >
> >>
> >> finally, per adding this config to MY config. how do you do that? That
> >> is, i don't want to just copy and paste this vcl snippet into my main
> >> varnish.vcl. Is there a way to include vcls from vcls?
> >>
> >>
> >
> > Include VCL-snips with:
> >
> > include "/etc/varnish/c.vcl";
> > include "/etc/varnish/subs.vcl";
> > include "/etc/varnish/defaultBackend.vcl";
> > include "/etc/varnish/backends.vcl";
> > include "/etc/varnish/LBsubs.vcl";
> >
> > Best Regards
> >
> > Niklas Norberg
> >
> >
> >
>
-------------- next part --------------
C{
// Obs This string is also used hard coded in pure VCL code
static const char VARNISH_LB_COOKIE_NAME[] = "VARNISH_LB=";
// Let STICKY balance everything(/) for four hours a time:
static const char VARNISH_LB_ENDING[] =
"; path=/; Max-Age=14400; Comment=Varnish Sticky Load Balancing Cookie";
static const int CANDIDATE_CNT = 3;
static const int MAX_LEN_LB_ID = 2; // covers 1-99
// Load balancing weights:
// The first value should be the sum of the others.
static const int LB_FACTOR[4] = {10, 7, 1, 2};
// The first is not used, just to keep indexes same in the arrays.
static int lbStatus[4] = {-1, 0, 0, 0};
static int lastCandidate = 1;
/**
Load Balancing according to Request Counting Algorithm, see:
http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html#requests
or write your own.
*/
int getCandidate4LB() {
/*
for each worker in workers
worker lbstatus += worker lbfactor
total factor += worker lbfactor
if worker lbstatus > candidate lbstatus
candidate = worker
candidate lbstatus -= total factor
*/
int worker=1;
// This local copy is really overkill
int candidate = lastCandidate;
while ( worker<=CANDIDATE_CNT ) {
lbStatus[worker] += LB_FACTOR[worker];
if ( lbStatus[worker] > lbStatus[candidate] )
candidate = worker;
worker++;
}
//int totalFactor = LB_FACTOR[0];
//lbStatus[candidate] -= totalFactor;
lbStatus[candidate] -= LB_FACTOR[0];
lastCandidate = candidate;
return candidate;
}
}C
/**
Check if a LB cookie is present.
If it is
- Copy the LB cookie value to a marker.
- set backend
- unset marker
If it isn't
- find candidate for LB and set value to marker
- set backend
- don't unset marker so a cookie can be set in vcl_deliver.
*/
sub recv_loadBalancingOnStickyCookie {
if (req.http.Cookie ~ "VARNISH_LB=") {
set req.http.StickyVarnish =
regsub( req.http.Cookie, "^.*?VARNISH_LB=([^;]*);*.*$", "\1" );
call chooseBackend;
unset req.http.StickyVarnish;
} else {
call findCandidate4LB;
call chooseBackend;
}
}
/**
Get candidate from some fancy smanchy algorithm.
Set value to marker.
*/
sub findCandidate4LB {
// set req.http.StickyVarnish = "X";:
C{
// get index for backend
int idxBackend = getCandidate4LB();
// Store index in a header marker so we can use this later
char strBackendIndex[MAX_LEN_LB_ID + 1];
sprintf(strBackendIndex, "%d", idxBackend);
VRT_SetHdr(sp, HDR_REQ, "\016StickyVarnish:", strBackendIndex, vrt_magic_string_end);
}C
// C{
// //Debug test:
// int i=1;
// while(i<=100) {
// syslog( LOG_INFO, "getCandidate4LB(): %d", getCandidate4LB() );
// i++;
// }
// }C
}
/**
Choose backend (via director) from the marker ("StickyVarnish").
Change this as necessary.
Directors and Backends are defined elsewhere.
*/
sub chooseBackend {
// if else in weight order, switch statements would have been better
if (req.http.StickyVarnish == "1") {
set req.backend = Backends1;
} else
if (req.http.StickyVarnish == "3") {
set req.backend = Backends3;
} else
if (req.http.StickyVarnish == "2") {
set req.backend = Backends2;
}
}
/**
Set the Sticky Varnish Load Balancing Cookie as:
"VARNISH_LB=X; ..."
*/
sub deliver_setLBCookie {
if (req.http.StickyVarnish) {
C{
// Also send cookie from backend if any
char* existing_set_cookie = VRT_GetHdr(sp, HDR_OBJ, "\013Set-Cookie:");
int len;
if (existing_set_cookie == NULL)
len = 0;
else
len = strlen(existing_set_cookie) + 1; // + 1 for "\r"
len += strlen(VARNISH_LB_COOKIE_NAME);
len += MAX_LEN_LB_ID;
len += strlen(VARNISH_LB_ENDING);
char set_cookie[len + 1];
set_cookie[0] = '\0';
if (existing_set_cookie != 0) {
strcat( set_cookie, existing_set_cookie );
strcat( set_cookie, "\r" );
}
strcat( set_cookie, VARNISH_LB_COOKIE_NAME );
char* strBackend = VRT_GetHdr(sp, HDR_REQ, "\016StickyVarnish:");
strcat( set_cookie, strBackend );
strcat( set_cookie, VARNISH_LB_ENDING );
// Send cookie(s)
VRT_SetHdr(sp, HDR_RESP, "\013Set-Cookie:", set_cookie, vrt_magic_string_end);
}C
}
}
/**
Call the LB subs from the subs:
- vcl_recv
- vcl_deliver
*/
/*
sub vcl_recv {
call recv_loadBalancingOnStickyCookie;
}
sub vcl_deliver {
call deliver_setLBCookie;
}
*/
/**
If directors are defined as below we can in practice:
Load balance to a specific backend by choosing a director
and still have a fallback function.
Risk for wrong backend = (1+1)/4294967295 = 5 * 10^-10,
a price I'm willing to take for this fallback function.
This way I can restart the backends and still keep the
load balancing intact when all is up again.
*/
/*
director Backends1 random {
{ .backend = www1; .weight = 4294967295;}
{ .backend = www2; .weight = 1;}
{ .backend = www3; .weight = 1;}
}
director Backends2 random {
{ .backend = www1; .weight = 1;}
{ .backend = www2; .weight = 4294967295;}
{ .backend = www3; .weight = 1;}
}
director Backends3 random {
{ .backend = www1; .weight = 1;}
{ .backend = www2; .weight = 1;}
{ .backend = www3; .weight = 4294967295;}
}
*/
More information about the varnish-misc
mailing list