This document describes a load balancing name server written in Perl 4. I am presenting a paper at the LISA '95 conference on this work and a version written in Perl 5. After the conference (Sept95) I will update this page with a pointer to the Perl 5 version.
For example, when somone types:
telnet best-elaine.Stanford.EDUThey get connected to one of the 57 different SPARCstations which have the name (elaine1-elaine57). The current definition of what the "best" host is can be found in the appendix.
A problem still exists when a host responds to poller requests, and has a low load, but no one can login because of a problem (lack of swap, etc). A future version may be smarter and watch for trends where a host is constantly handed out but the weight of that host never changes.
To other name servers, lbnamed looks like a standard DNS name server, with the exception that it doesn't answer recursive queries. It only handles requests for the dynamic groups it maintains. lbnamed gets a normal DNS request and based on the name in the request it calculates the host to return. lbnamed then constructs a standard DNS response and sends it back to client that requested it. The time to live (TTL) value in the repsonse is set to 0, in order to prevent this value from being cached by other name servers (which would defeat the whole purpose).
best IN NS dsodb.Stanford.EDU. best IN NS sunlight.Stanford.EDU.These two NS records delegate the best.Stanford.EDU domain to the lbnamed's running on dsodb and sunlight. Now when the primary servers for the Stanford.EDU domain get a request like elaine.best.stanford.edu they know to forward it off the the lbnamed's. Note that the two lbnamed's don't communicate to each other, they both operate independent of each other for simplicity and redundancy.
http://www-leland.stanford.edu/~schemers/dist/lb.tar
Use the code at your own risk. We have been using it for over a year and a half with good results.
fudge = (tot_user - uniq_user)*20; weight = (uniq_user)*100 + (3*l1) + fudge;Where the variables are:
host weight-multiplier group1 [group2 ...]The weight-multiplier field is currently not used but will be used in the future to allow for better selection among different hardware in the same group.
The following is a sample poller configuration file with some lines removed to save space.
# # groups # ------------------------- # sweet all machines # elaine elaine1-elaine57 # sparc elaine1-elaine57 # sunos elaine1-elaine57 # sparc2 sparc2 (elaine1-elaine19) # sparc1 sparc1 (elaine20-elaine57) # adelbert adelbert1-adelbert26 # ultrix adelbert1-adelbert26 # dec adelbert1-adelbert26 # dec5000 adelbert1-adelbert13 # dec3100 adelbert14-adelbert26 # rs rs1-rs10 # rs6000 rs1-rs10 # aix rs1-rs10 # rs1 1 rs rs6000 aix rs2 1 rs rs6000 aix ... rs10 1 rs rs6000 aix # elaine1 1 elaine sparc2 sparc sunos sweet elaine2 1 elaine sparc2 sparc sunos sweet ... elaine19 1 elaine sparc2 sparc sunos sweet # elaine20 1 elaine sparc1 sparc sunos sweet elaine21 1 elaine sparc1 sparc sunos sweet ... elaine57 1 elaine sparc1 sparc sunos sweet # adelbert1 1 adelbert dec5000 dec ultrix sweet adelbert2 1 adelbert dec5000 dec ultrix sweet ... adelbert13 1 adelbert dec5000 dec ultrix sweet # adelbert14 1 adelbert dec3100 dec ultrix sweet ... adelbert26 1 adelbert dec3100 dec ultrix sweet #
weight host ipaddress group1 [group2 ...]
The following is a sample lbnamed configuration file with some lines removed to save space.
2200 elaine11 36.214.0.127 elaine sparc2 sparc sunos sweet 639 adelbert10 36.211.0.81 adelbert dec5000 dec ultrix sweet 651 elaine20 36.215.0.208 elaine sparc1 sparc sunos sweet 2336 elaine3 36.212.0.119 elaine sparc2 sparc sunos sweet ... 866 adelbert6 36.211.0.76 adelbert dec5000 dec ultrix sweet 243 adelbert26 36.212.0.201 adelbert dec3100 dec ultrix sweet
#define PROTO_PORTNUM 4330 #define PROTO_MAXMESG 2048 /* max udp message to receive */ #define PROTO_VERSION 2 typedef enum P_OPS { op_lb_info_req =1, /* load balance info, request and reply */ } p_ops_t; typedef enum P_STATUS { status_request =0, /* a request packet */ status_ok =1, /* ok */ status_error =2, /* generic error */ status_proto_version =3, /* protocol version error */ status_proto_error =4, /* any other protocol error */ status_unknown_op =5, /* unknown operation requested */ } p_status_t; typedef struct { u_short version; /* protocol version */ u_short id; /* requestor's uniq request id */ u_short op; /* operation requested */ u_short status; /* set on reply */ } P_HEADER,*P_HEADER_PTR; typedef struct { P_HEADER h; u_int boot_time; u_int current_time; u_int user_mtime; /* time user information last changed */ u_short l1; /* (int) (load*100) */ u_short l5; u_short l15; u_short tot_users; /* total number of users logged in */ u_short uniq_users; /* total number of uniq users */ u_char on_console; /* true if somone on console */ u_char reserved; /* future use, padding... */ } P_LB_RESPONSE, *P_LB_RESPONSE_PTR;The protocol was meant to be extensible but I have yet to use the daemon for anything but load balancing requests.