Load balancing
This is a extension of what is described in http://wiki.debian.org/DebianEdu/Documentation/Etch/HowTo/NetworkClients#head-7587290321a833444df956e05b30f1a4cde2df3e - it extends part 2 with a second option, where the choosen LTSP server is not random but the least utilized one. Un
Option 2
The second option is more advanced, it gives you a server list generated by querying ldminfod for the server rating. By querying ldminfod, you can get the current rating state of the server. This rating goes from 0 to 100, higher is better. For this to work, you have to use the ubuntu version of ldminfod. (remark from h01ger: which version of ubuntu? it looks like Debian lenny is enough too?) The Skolelinux version doesn't have the server rating function.
First you should make a backup of the original ldminfod-file, which is in /usr/sbin/. Then, put the following script in a new ldminfod-file. Make sure the new file has the same permissions as the old one.
import sys import os import locale from subprocess import * def get_memory_usage(): memusg = {} # Get memory usage information, according to /proc/meminfo f = open('/proc/meminfo', 'r') swap_free = 0 mem_physical_free = 0 mem_buffers = 0 mem_cached = 0 for line in f.readlines(): tokens = line.split() label = tokens[0] size = tokens[1] try: size = int(size) except: # The line is an header, skip it. continue # We approximate kb to bytes size = size * 1024 if label == 'MemTotal:': memusg['ram_total'] = size elif label == 'MemFree:': mem_physical_free = size elif label == 'Buffers:': mem_buffers = size elif label == 'Cached:': mem_cached = size elif label == 'SwapTotal:': memusg['swap_total'] = size elif label == 'SwapFree:': swap_free = size f.close() memusg['ram_used'] = memusg['ram_total'] - mem_physical_free - mem_buffers - mem_cached memusg['swap_used'] = memusg['swap_total'] - swap_free return memusg def get_load_average(): # Gets the current system load, according to /proc/loadavg loadavg = {} load_file = open('/proc/loadavg') load_infos = load_file.read().split() loadavg['one_min_avg'] = load_infos[0] loadavg['five_min_avg'] = load_infos[1] loadavg['fifteen_min_avg'] = load_infos[2] # scheduling_info = load_infos[3] # not used # last_pid = load_infos[4] load_file.close() return loadavg def compute_server_rating(): """Compute the server rating from it's state The rating is computed by using load average and the memory used. The returned value is betweed 0 and 100, higher is better """ max_acceptable_load_avg = 8.0 mem = get_memory_usage() load = get_load_average() rating = 100 - int( 50 * ( float(load['fifteen_min_avg']) / max_acceptable_load_avg ) + 50 * ( float(mem['ram_used']) / float(mem['ram_total']) ) ) if rating < 0: rating = 0 return rating def get_sessions (dir): """Get a list of available sessions. Returns a list of sessions gathered from .desktop files """ sessions = [] if os.path.isdir(dir): for f in os.listdir(dir): if f.endswith('.desktop') and os.path.isfile(os.path.join(dir, f)): x={} for line in file(os.path.join(dir, f), 'r').readlines(): if 'Exec=' in line: variable, value = line.split('=') x[variable]=value if 'TryExec' in x: sessions.append(x['TryExec'].rstrip()) elif 'Exec' in x: sessions.append(x['Exec'].rstrip()) return sessions if __name__ == "__main__": # Get the server's default locale # We want it to appear first in the list try: lines = Popen(['locale'], stdout=PIPE).communicate()[0] except OSError: print "ERROR: failed to run locale" sys.exit(0) for line in lines.split(): if line.startswith('LANG='): defaultlocale = line.split('=')[1].strip('"') defaultlocale = defaultlocale.replace('UTF8', 'UTF-8') print "language:" + defaultlocale # Get list of valid locales from locale -a try: lines = Popen(['locale', '-a'], stdout=PIPE).communicate()[0] except OSError: print "ERROR" sys.exit(0) langs = lines.split(None) langs.sort() for lang in langs: lang = lang.rstrip() if lang.endswith('.utf8'): # locale returns .utf8 when we want .UTF-8 lang = lang.replace('.utf8','.UTF-8') else: # if locale did not end with .utf8, do not add to list continue if lang != 'POSIX' and lang != 'C' and lang != defaultlocale: print "language:" + lang try: lines = get_sessions('/usr/share/xsessions/') except OSError: print "ERROR" sys.exit(0) for line in lines: print "session:" + line # Get the rating of this server rate = 0 try: rate = compute_server_rating() except: print "ERROR" sys.exit(0) print "rating:" + str(compute_server_rating())
Now you have to edit "/opt/ltsp/i386/etc/lts.conf" and add this:
MY_SERVERS = "xxxx xxxx xxxx"
Replace xxxx with either the IP or hostname of the servers, list must be space separated. Then, put the following script in /opt/ltsp/i386/usr/lib/ltsp/get_hosts on the server you chose to be the loadbalancing server.
LIST="" # Load query on all servers for i in $MY_SERVERS; do LOAD=`nc $i 9571|grep rating|cut -d: -f2` if test $LOAD; then # add to the list LIST="$LIST$LOAD $i\n" fi done # Now LIST contains the list of servers sorted by load LIST=`echo -e $LIST | sort -nr` # Check if the 1st items have the same load. If so, randomly choose one. OLDIFS=$IFS IFS=" " BESTLIST=( ) I=0 for LINE in $LIST ;do LOAD=`echo $LINE|cut -f 1 -d " "` if [ "$OLDLOAD" -a "$LOAD" != "$OLDLOAD" ] ;then break fi BESTLIST[$I]="$LINE" OLDLOAD=$LOAD I=$((I+1)) done RAND=$(( $RANDOM % $I )) # print the choosen host echo ${BESTLIST[$RAND]} | cut -f 2 -d " " exit 0