IBM WebSphere SNMP Dynamic Ratio Monitor for BIG-IP with TMSH
Problem this snippet solves:
I have taken Kirk's work and updated it for newer versions of BIG-IP with TMSH. One of the requests I hear often is how to use things like Java Heap Size to make a determination on pool member ratio. As Kirk said in his earlier post: "You may want to dynamically load balance to your servers based on things like CPU and memory utilization, but perhaps the built-in SNMP monitor is not flexible enough for you. This Perl EAV can use as many OIDs as you need and perform mathematical calculations on the results to affect the ratio of the various nodes in the pool. You need to set the load balancing method of the pool to "Ratio". You then need to define this EAV (with the name of the pool as the Argument) and edit the configuration at the top of the script. Finally, apply this monitor (as well as your regular health checking monitor) to the pool."
A separate section in the WebSphere 8 deployment guide links to this code example, and I have specifically written the SNMP and ratio OIDs in this monitor to focus on Java on WebSphere, but feel free to use this for other purposes as well.
Some example configurations (these are just examples and have not been tested and may not be appropriate for your servers):
# Utilization of a 2-CPU machine (Windows-specific?) # (utilization of CPU0, divided by 100 to get value between 0-1, utilization of CPU1, then these two # results are automatically averaged) $oids{'cpu'} = [ '.1.3.6.1.4.1.2021.11.11.0 / 100', '.1.3.6.1.4.1.2021.11.11.1 / 100' ];
# Memory utilization (Linux-specific?) # (RAM used divided by total RAM on the system) $oids{'memory'} = [ '.1.3.6.1.4.1.2021.4.6.0 / .1.3.6.1.4.1.2021.4.5.0' ];
Create a new file containing the code below in /usr/bin/monitors on the LTM filesystem. Permissions on the file must be 700 or better, giving root rwx access to the file. See comments within the code for documentation.
Code :
#!/usr/bin/perl -w use strict; # Version 2.0 udpated for BIG-IP 11.x # This monitor does not actually mark nodes as down -- it simply adjusts # their ratio within the pool based on system utilization. Currently you # can only pass one argument in via the custom monitor declaration -- that # is the name of the pool. If it is passed in it overrides the name of the # pool defined in the configuration section below. # Note that I do not recommend running this monitor more frequently than # once every 30 seconds. # The ratio is calculated as follows: # (N)^(c1((t1 - u1)/t1)) + (N)^(c2((t2 - u2)/t2)) ... # Where: # N = Number of nodes in the pool # c1 = Coefficient for item #1 # t1 = Threshold for item #1 in % # u1 = Utilization for item #1 in % # c2 = Coefficient for item #2 # t2 = Threshold for item #2 in % # u2 = Utilization for item #2 in % # ... ############################################################################# # Configuration Section # This is the pool that this monitor is applied to. You can specify it here # or pass it in as the parameter for the monitor. my $pool = ""; # For version 11.x and above leave this my $partition = "/Common/"; # SNMP Version to use, options are V1, V2c, V3 my $snmp_version = "V3"; # SNMP Community to use if V1 or V2 my $snmp_community = "public"; # SNMP Variables to use if V3 my $snmp_auth_type = "md5"; my $snmp_user = "user"; my $snmp_password = "password"; my $snmp_port = "10162"; # Specify here what items to consider when determining the ratio for the node my @ratio_items = ( 'cpu' ); #my @ratio_items = ( 'cpu', 'memory', 'disk' ); # Specify the Coefficient for each item here my %coefficient = ( 'memory' => 4, 'cpu' => 2, 'disk' => 1, ); # Specify the Threshold for each item here (between 0.00 and 1.00) my %threshold = ( 'memory' => 0.9, 'cpu' => 0.9, 'disk' => 0.9, ); # Define one or more OIDs or calculations for each item to monitor. If # multiple items are listed then the results are averaged. Each item may be # a single OID but may also contain multiple OIDs and/or constants separated # by basic arithmetic operators (Such as +, -, /, and *). OIDs must be numeric # and must begin with a period. # Each item should result in a percentage (between 0.00 and 1.00) my %oids; $oids{'cpu'} = [ '.1.3.6.1.4.1.1977.22.10.13.1.2.1.126.36 / 100' ]; ############################################################################# # Read arguments my $node_ip = $ARGV[0]; $node_ip =~ s/::ffff://; my $port = $ARGV[1]; $pool = $ARGV[2] if defined($ARGV[2]); my $ratio = 1; # Check for and create PID file my $monname = $ENV{MON_TMPL_NAME} || $0; $monname = $0 unless $monname; $monname =~ s/^.*\///; my $pidfile = "/var/run/$monname.$node_ip.pid"; if (-r $pidfile) { open(PIDFILE, $pidfile); my $oldpid =; close PIDFILE; chomp $oldpid; system("kill -9 $oldpid"); } open(PIDFILE, ">$pidfile"); print PIDFILE "$$\n"; close PIDFILE; # Determine number of active pool members my @pool_data = `tmsh show /ltm pool $partition/$pool`; chomp @pool_data; (my $field_name, my $active_members) = split(/:/, $pool_data[10]); print STDERR "Pool $pool has $active_members active members...\n"; my $count = 0; my $total = 0; foreach my $item (@ratio_items) { $count = 0; $total = 0; foreach my $oid (@{$oids{$item}}) { while ($oid =~ /(\.\d+\b[\d.]+)\b/) { # Lookup OID my $lookup = $1; my $snmp_value = ""; if ($snmp_version eq ( "V1" or "V2c")) { $snmp_value = `snmpget -v2c -c $snmp_community $node_ip $lookup`; } else { $snmp_value = `snmpget -v3 -u $snmp_user -a $snmp_auth_type -A $snmp_password $node_ip:$snmp_port $lookup`; } chomp $snmp_value; $snmp_value =~ s/^.* = \w+: //; $oid =~ s/\.\d+\b[\d.]+\b/$snmp_value/; print STDERR "$node_ip($item) OID $lookup = $snmp_value\n"; } my $result = eval $oid; print STDERR "$node_ip($item) evaluated formula: $oid = $result\n"; $count++; $total += $result; } my $result = $total / $count; print STDERR "$node_ip($item) average is $result\n"; print STDERR "active_members: $active_members , coeffcient{item}: $coefficient{$item} , result: $result , threshold: $threshold{$item}\n"; $ratio += $active_members ** ($coefficient{$item} * (($threshold{$item} - $result) / $threshold{$item})); } # Set node's ratio system("tmsh modify /ltm pool $partition/$pool members modify { $node_ip:$port { ratio $ratio}} "); print STDERR "Setting $node_ip:$port in pool $pool to ratio $ratio\n"; # print results unlink $pidfile; print "UP\n";