Anybody interested in testing patch to allow weighted nodes?
Brett G. Durrett
brett at imvu.com
Wed May 16 23:05:35 UTC 2007
I have attached a patch to 1.57 that will allow weighting of nodes
specified in a nodefile. This might be handy if your servers have a
wide range of performance and you want to direct less traffic to less
powerful servers.
I am putting this out in case anybody has use for it and is willing to
test it :)
Some notes:
- It only works using nodefiles, not the config file node definitions or
the configuration interface "add" or "remove" commands.
- I am running about 5% of our traffic through my production test
server... it appears to be working well but I would not feel comfortable
asking others to try it in production. I have done very little
testing... I am not sure about the behavior in failure cases, especially
in regards to failing-out bad nodes.
- To weight a node, add whitespace and weight:<int> to the nodefile...
for example:
10.10.10.78 weight:1
10.10.10.79 weight:1
10.10.10.124 weight:5
10.10.10.125 weight:5
- If you do not specify a weight for any node the weighting code is
ignored.
- If you specify a weight for some (but not all) nodes, it will assume a
weight of "1" for nodes that did not have a weight.
- If weights are assigned, the "show pool <pool>" command will add the
weights of all nodes to the output... if you did not use weighting, the
standard output will be displayed. For example:
show pool virtual_web
10.10.10.78:80 765 weight:1
10.10.10.79:80 770 weight:1
10.10.10.124:80 4007 weight:5
10.10.10.125:80 3921 weight:5
Again, this was a quick hack and I am providing this for testing... if
your Perlbal is controlling a nuclear reactor, please don't try this.
Thanks in advance for any testing / feedback you can provide,
B-
-------------- next part --------------
Index: lib/Perlbal/Pool.pm
===================================================================
--- lib/Perlbal/Pool.pm (revision 674)
+++ lib/Perlbal/Pool.pm (working copy)
@@ -19,6 +19,9 @@
use constant BM_ROUNDROBIN => 2;
use constant BM_RANDOM => 3;
+# if weights used, defualt weight for non-weighted node
+use constant NODE_DEFAULT_WEIGHT => 1;
+
use fields (
'name', # string; name of this pool
'use_count', # int; number of services using us
@@ -32,6 +35,11 @@
'nodefile.lastmod', # unix time nodefile was last modified
'nodefile.lastcheck', # unix time nodefile was last stated
'nodefile.checking', # boolean; if true AIO is stating the file for us
+
+ # used for weighted random
+ 'node_weight', # hashref; { ip:port => int weight }
+ 'weighted_nodes', # array FIXME
+ 'node_weight_total', # int; sum of weight of all nodes, used to flag weighted
);
sub new {
@@ -46,6 +54,8 @@
$self->{nodes} = [];
$self->{node_count} = 0;
$self->{node_used} = {};
+ $self->{node_weight} = {};
+ $self->{node_weight_total} = 0;
$self->{nodefile} = undef;
$self->{balance_method} = BM_RANDOM;
@@ -120,6 +130,7 @@
my $dataref = shift;
my @nodes = split(/\r?\n/, $$dataref);
+ my $totalnodeweight = 0;
# prepare for adding nodes
$self->{nodes} = [];
@@ -130,6 +141,14 @@
if (/(\d+\.\d+\.\d+\.\d+)(?::(\d+))?/) {
my ($ip, $port) = ($1, $2);
$port ||= 80;
+ if(/weight:(\d+)/){
+ my $weight = $1;
+ $self->{node_weight}->{"$ip:$port"} = $weight;
+ $totalnodeweight += $weight;
+ }
+ else{
+ $self->{node_weight}->{"$ip:$port"} = 0;
+ }
$self->{node_used}->{"$ip:$port"} ||= 0; # set to 0 if not set
push @{$self->{nodes}}, [ $ip, $port ];
}
@@ -137,6 +156,30 @@
# setup things using new data
$self->{node_count} = scalar @{$self->{nodes}};
+
+ # if weight used, build array for weights, assign default to unweighted
+ if( $totalnodeweight ){
+ $self->{weighted_nodes} = [];
+ my $nodeindex = 0;
+ foreach ( @{$self->{nodes}} ){
+ my ( $ip, $port ) = @{ $_ };
+ if( not( $self->{node_weight}->{"$ip:$port"} ) ){
+ # FIXME: consider warning that some nodes not weighted
+ $self->{node_weight}->{"$ip:$port"} = NODE_DEFAULT_WEIGHT;
+ $totalnodeweight += NODE_DEFAULT_WEIGHT;
+ }
+ my $nodeweight = $self->{node_weight}->{"$ip:$port"};
+ while( $nodeweight-- > 0 ){
+ push @{$self->{weighted_nodes}}, $nodeindex;
+ }
+ $nodeindex++;
+ }
+ $self->{node_weight_total} = $totalnodeweight;
+ }
+ else{
+ # Set total weight to zero to disable weighting
+ $self->{node_weight_total} = 0;
+ }
}
sub _load_nodefile_sync {
@@ -225,8 +268,14 @@
# no nodes?
return () unless $self->{node_count};
- # pick one randomly
- return @{$self->{nodes}[int(rand($self->{node_count}))]};
+ if( not $self->{node_weight_total} ){
+ # pick one randomly
+ return @{$self->{nodes}[int(rand($self->{node_count}))]};
+ }
+ else{
+ # use weighted random
+ return @{$self->{nodes}[$self->{weighted_nodes}[int(rand($self->{node_weight_total}))]]};
+ }
}
sub backend_should_live {
@@ -270,6 +319,16 @@
$self->{use_count}--;
}
+sub node_weight {
+ my Perlbal::Pool $self = $_[0];
+ return $self->{node_weight}->{$_[1]};
+}
+
+sub node_weight_total {
+ my Perlbal::Pool $self = $_[0];
+ return $self->{node_weight_total};
+}
+
sub name {
my Perlbal::Pool $self = $_[0];
return $self->{name};
Index: lib/Perlbal.pm
===================================================================
--- lib/Perlbal.pm (revision 674)
+++ lib/Perlbal.pm (working copy)
@@ -807,7 +807,14 @@
foreach my $node (@{ $pl->nodes }) {
my $ipport = "$node->[0]:$node->[1]";
- $mc->out($ipport . " " . $pl->node_used($ipport));
+ if( not $pl->node_weight_total() ){
+ # Not using weights, standard output
+ $mc->out($ipport . " " . $pl->node_used($ipport));
+ }
+ else{
+ # Weights in use, add weight to output
+ $mc->out($ipport . " " . $pl->node_used($ipport) . " weight:" . $pl->node_weight($ipport));
+ }
}
} else {
foreach my $name (sort keys %pool) {
More information about the perlbal
mailing list