Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Load Balancing fun..

by reyjrar (Hermit)
on Oct 02, 2000 at 19:16 UTC ( [id://34915]=CUFP: print w/replies, xml ) Need Help??

just out of the sake of boredom and insanity, I was asked to setup load balancing here for a server at work. and I instantly fired up a pico session and starting hacking away at some perl :)
now, what they actually wanted me to do was email a guy and setup a round robin DNS, but of course, in my delirious, sick state I began a script to do load balancing in perl.
here's what I hacked out: (I plan on developing this to be a really kick ass system, but right now, its basic and it works)
#!/usr/bin/perl # This is going to be fun.. # anyways.. code by me.. # Brad Lhotsky # <brad@divisionbyzero.net> # use Socket; use Symbol; use Time::localtime; use strict; my $port = 8080; my %CONF = {}; my $cfgfile = "balance.cfg"; my $DATADIR = "/home/blhotsky/code/load/data/"; %CONF = &readconf($cfgfile); my ($crap,$things); foreach $crap (keys(%CONF)) { print "$crap\n"; foreach $things (@{$CONF{$crap}}) { print "\t$things\n"; } } socket(SERVER, AF_INET, SOCK_STREAM, getprotobyname('tcp')) || die $!; setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1); select SERVER; $|++; +select('stdout'); my $sin = sockaddr_in($port, INADDR_ANY); bind(SERVER, $sin) || die $!; listen(SERVER, SOMAXCONN); while(1) { my $socket = gensym(); accept($socket, SERVER); select $socket; $|++; select('stdout'); my $get = <$socket>; chomp $get; my ($null, $url,$opts); ($null, $url,$null) = split(/\s/,$get); ($url, $opts) = split(/\?/, $url); &print_header($socket); my $redirect = &balance($url); if($opts) { $redirect .= "?$opts"; } $redirect .= "\n\n"; print $socket $redirect; close $socket; } sub readconf { my $file = shift; die "no conf file!\n" if !$file; open(FILE, "< $file") || die "could not open $file\n"; my %HASH; my $link; while(<FILE>) { s/^\s+//; chomp; next if /^$/; next if /^\#/; my($line,$comment) = split /\#/, $_; if(($line !~ /^:/) && !$link) { next; } if($line =~ /^:(.*)/) { $link = $1; $HASH{$link} = (); + next; } # If we get here, we need to push stuff into the hashe +s anon array. $line =~ s/\s+$//; push @{$HASH{$link}}, $line; } return %HASH; } sub balance { my $url = shift; if($url eq '/') { $url = "index.html"; } else { $url =~ s%^/%%; } if(!$url) { die "dammit no url to go to!\n"; } my $redirect; my $index = &getindex($url); if($CONF{$url}) { $redirect = $CONF{$url}->[$index]; } else { $redirect = "http://divisionbyzero.net/~trilex/index.ht +ml"; } $redirect = "Location: $redirect\n\n"; return $redirect; } sub print_header { my $socket = shift; if(!$socket) { die "no socket dumbass!\n"; } my $date = "Date: " . ctime() . " EST\n"; my $headers = "HTTP/1.1 302 Found\n" . $date . "Server: Funky +Load Balancer/0.0.1 (Unix) Perl\n" . "Connection: close\n"; print $socket $headers; } sub getindex { my $url = shift; if(!$url) { die "dammit no url to go to!\n"; } open(DATA, "<$DATADIR/$url") || sub { &datahandle($url); retur +n 0; }; my $line = <DATA>; close DATA; chomp $line; $line =~ s/\D+//g; &datahandle($url,$line); return $line; } sub datahandle { my $url = shift; my $num = shift; my $file = "$DATADIR/$url"; $num++; if($num > $#{$CONF{$url}}) { $num = "0"; } if(!$url) { die "how the hell did this die?"; } open(DATA, ">$file") || die "this is not good no permissions i +n $DATADIR\n"; print DATA "$num\n"; close DATA; } and here's the config file: ####################### # Load Balancing conf file. # format: # :file # absolute path from the server dir # http://some.domain.com/path/to/file # http://some.domain2.com/path/to/file # :file2 # http://some.domain.com/path/to/file2 # http://some.domain2.com/path/to/file2 :dbz http://divisionbyzero.net/index.html http://spark.divisionbyzero.net/index.html :funky http://ackers.net/index.html http://realms.divisionbyzero.net/index.html


-brad..

Replies are listed 'Best First'.
RE: Load Balancing fun..
by AgentM (Curate) on Oct 02, 2000 at 20:50 UTC
    Quick comment: It is rarely good to return a hash. This has come up before. Even though this will probably not prove to be a bottleneck in your program. It is still a wasteful use of resources. When you return a hash, the hash is copied into the assigned variable. bad idea. You should just return a reference like this:
    return \%hash;
    Otherwise, be sure to post the final product. This is neato.
    AgentM Systems or Nasca Enterprises is not responsible for the comments made by AgentM- anywhere.
      Returning a hash can be very good. I basically did that in ret_tag_handlers in a recent post to good effect.

      But if you think it matters, give a choice:

      return wantarray ? %hash : \%hash;
      Also worrying about low-level efficiency too much is a bad idea - real problems tend to be overall system design and algorithm choices. If you spend your time sweating details, you won't ever address the real problems...
        Sorry, but I've got to disagree (somewhat) with your statement. In this case, the waste may not be impressive but such a mistake can lead to hard2debug code if you don't catch it quickly enough. The overall system design and algorithm choices are best made before putting fingers to the keyboard. Perhaps pseudocode or object-based organizers are good here. The actual coding is a focus on the "time-sweating" details. While I agree that wasting time on details may not get one anywhere, a typical error like FULL hash returns or array returns can lead to wasted resources and can ultimately lead to a bottleneck. Returned hashes may be useful in threads (as a workaround and definitely not a solution). C/C++ is a finely tuned instrument for making sure that such mistakes are not easily made. Perl, on the other hand, allows this as almost a sort of default (it's not obvious to the programmer that this is potentially serious). As I said, in the code above, there will be most likely no performance issue, but it's more useful to note bad programming techniques before they become serious.

        I'm not exactly certain what you mean by "real problems". I would consider a bottleneck based on a single line of code very serious (although not above). If you mean debugging and testing to provide a final product, such coding will most likely not be caught by the debugger or tester and if the user decides to run 5000 of these load balancers than there is a potentially dangerous situation. Whenever i hear that word "potential" (let's say for a problem), I prefer to clean it up as best I can. A simple code alteration of two characters (as in the code above) will also be ultimately beneficial to all programmers since they see an learn from improvement. While you provide an example how you return an array in your sub, I don't fully understand the benefits of it in your example. A little more info on that would be nice. Thanks.

        AgentM Systems or Nasca Enterprises is not responsible for the comments made by AgentM- anywhere.
RE: Load Balancing fun..
by merlyn (Sage) on Oct 03, 2000 at 04:30 UTC
    Heh. The same topic as column #55 of WT, which isn't published yet but should be hitting the streets next month. I'll edit this node when I've got the link on my website.

    -- Randal L. Schwartz, Perl hacker

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://34915]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (2)
As of 2024-04-26 06:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found