Forum Discussion
Steffen_Beach_8
Nimbostratus
Feb 15, 2010Polling all current connections from all default pools
So I've been playing around with iControl in preparation of building a custom web interface for my NOC and deployment tool for us engineers. While doing what I would think would be a simple query (snippet below) I've kicked the snot out of my ltm... It times out if I try to collect all data, and there is a nasty spike in CPU. This is on an 8900, which I would think could process this request no problemo.
Here is the summary of objects:
Virtual Servers 166
Pools 246
Nodes 1196
My question is, why does this cause such havoc, and what would be a better approach to getting what I need?
My initial thought to making things more manageable is storing some data (virtual server/pool names) in a DB and performing my own batch calls. More work that I thought would be needed given that the interface accepts (forces) array data types for multi object lookups.
Here is my code snippet:
static void Main(string[] args)
{
Interfaces m_interfaces = new Interfaces();
string ipAddress = "********";
string user = "**********";
string pass = "********";
//Initalize the f5 interface
m_interfaces.initialize(ipAddress, user, pass);
//Check if inialized
if (!m_interfaces.initialized)
Environment.Exit(Environment.ExitCode);
//Get the partition list to drop into PROD
ManagementPartitionAuthZPartition[] partitionList = m_interfaces.ManagementPartition.get_partition_list();
for (int i = 0; i < partitionList.Length; i++)
{
if (partitionList[ i ].partition_name == "PROD")
m_interfaces.ManagementPartition.set_active_partition(partitionList[ i ].partition_name);
}
// TEST DATA
//string[] vsName = new string[1];
//vsName[0] = "vs_products_http";
//string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(vsName);
// END TEST DATA
//Get all virtual servers
string[] localVirtualServers = m_interfaces.LocalLBVirtualServer.get_list();
//Get all the active default pools
string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(localVirtualServers);
//Get the pool stats
LocalLBPoolPoolStatistics poolStats = m_interfaces.LocalLBPool.get_statistics(localDefaultPools);
//Get the pool stat entries
LocalLBPoolPoolStatisticEntry[] poolStatEntries = poolStats.statistics;
//Loop through each pool and print out the server side current connection stats
for (int i = 0; i < poolStatEntries.Length; i++)
{
CommonStatistic[] commonStats = poolStatEntries[ i ].statistics;
for (int x = 0; x < commonStats.Length; x++)
{
if (commonStats[x].type == CommonStatisticType.STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS && poolStatEntries[ i ].pool_name != "")
{
CommonULong64 commonValue = commonStats[x].value;
Console.WriteLine("Pool name: {0} Current connections: {1}", poolStatEntries[ i ].pool_name, commonValue.low.ToString());
}
}
}
}
7 Replies
Sort By
- Steffen_Beach_8
Nimbostratus
BTW -- its timing out here: LocalLBPoolPoolStatistics poolStats = m_interfaces.LocalLBPool.get_statistics(localDefaultPools); - Steffen_Beach_8
Nimbostratus
I figured out a way to get the data by breaking it out into batches, although, it's still gawd awfully slow!!!using System; using System.Collections.Generic; using System.Text; using iControl; namespace iControlInterface { class Program { static void Main(string[] args) { Interfaces m_interfaces = new Interfaces(); string ipAddress = "*******"; string user = "*********"; string pass = "**************"; //Initalize the f5 interface m_interfaces.initialize(ipAddress, user, pass); //Check if inialized if (!m_interfaces.initialized) Environment.Exit(Environment.ExitCode); //Get the partition list to drop into PROD ManagementPartitionAuthZPartition[] partitionList = m_interfaces.ManagementPartition.get_partition_list(); for (int i = 0; i < partitionList.Length; i++) { if (partitionList[ i ].partition_name == "PROD") m_interfaces.ManagementPartition.set_active_partition(partitionList[ i ].partition_name); } // TEST DATA //string[] vsName = new string[1]; //vsName[0] = "vs_products_http"; //string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(vsName); // END TEST DATA //Get all virtual servers string[] localVirtualServers = m_interfaces.LocalLBVirtualServer.get_list(); //PrintInfo(localVirtualServers); //Get all the active default pools string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(localVirtualServers); //PrintInfo(localDefaultPools); //Get the pool stats LocalLBPoolPoolStatistics poolStats = new LocalLBPoolPoolStatistics(); //Get the pool stat entries LocalLBPoolPoolStatisticEntry[] poolStatEntries; List localDefaultPoolsList = new List(localDefaultPools); string[] poolBatch; while(localDefaultPoolsList.Count > 0) { if(localDefaultPoolsList.Count >= 10) { poolBatch = localDefaultPoolsList.GetRange(localDefaultPoolsList.Count - 10, 10).ToArray(); localDefaultPoolsList.RemoveRange(localDefaultPoolsList.Count - 10, 10); poolStats = m_interfaces.LocalLBPool.get_statistics(poolBatch); poolStatEntries = poolStats.statistics; PrintStatistics(poolStatEntries); } else { poolBatch = localDefaultPoolsList.ToArray(); localDefaultPoolsList.Clear(); poolStats = m_interfaces.LocalLBPool.get_statistics(poolBatch); poolStatEntries = poolStats.statistics; PrintStatistics(poolStatEntries); } } } public static void PrintInfo(string[] info) { for (int i = 0; i > info.Length; i++) { Console.WriteLine(info[ i ].ToString()); } } public static void PrintStatistics(LocalLBPoolPoolStatisticEntry[] poolStatEntries) { //Loop through each pool and print out the server side current connection stats for (int i = 0; i < poolStatEntries.Length; i++) { CommonStatistic[] commonStats = poolStatEntries[ i ].statistics; for (int x = 0; x < commonStats.Length; x++) { if (commonStats[x].type == CommonStatisticType.STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS && poolStatEntries[ i ].pool_name != "") { CommonULong64 commonValue = commonStats[x].value; Console.WriteLine("Pool name: {0} Current connections: {1}", poolStatEntries[ i ].pool_name, commonValue.low.ToString()); } } } } } }
- Steffen_Beach_8
Nimbostratus
Okay, now I've really have the problem knocked out. Apparently I was getting back no name pools (I believe for virtul servers with no default pool assigned) and when trying to fetch stats for and empty object the iControl method for get_statistics doesn't play nice. Anyway, I added in a quick method to prune out empty objects from the .get_default_pool_name method, and presto, the stats collection went from just over 3 minutes down to just under 2 seconds! Massive improvement!using System; using System.Collections.Generic; using System.Text; using iControl; using System.Diagnostics; namespace iControlInterface { class Program { static void Main(string[] args) { Interfaces m_interfaces = new Interfaces(); string ipAddress = "*******"; string user = "*******"; string pass = "*******"; //Initalize the f5 interface m_interfaces.initialize(ipAddress, user, pass); //Check if inialized if (!m_interfaces.initialized) Environment.Exit(Environment.ExitCode); //Get the partition list to drop into PROD ManagementPartitionAuthZPartition[] partitionList = m_interfaces.ManagementPartition.get_partition_list(); for (int i = 0; i < partitionList.Length; i++) { if (partitionList[ i ].partition_name == "PROD") m_interfaces.ManagementPartition.set_active_partition(partitionList[ i ].partition_name); } // TEST DATA //string[] vsName = new string[1]; //vsName[0] = "vs_products_http"; //string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(vsName); // END TEST DATA //Get all virtual servers string[] localVirtualServers = m_interfaces.LocalLBVirtualServer.get_list(); //PrintInfo(localVirtualServers); //Get all the active default pools string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(localVirtualServers); //PrintInfo(localDefaultPools); //Get the pool stats LocalLBPoolPoolStatistics poolStats = new LocalLBPoolPoolStatistics(); //Get the pool stat entries LocalLBPoolPoolStatisticEntry[] poolStatEntries; //Load the localDefaultPools into a List object to prune and perform batch get_statistics with List localDefaultPoolsList = RemoveNoNamePools(localDefaultPools); string[] poolBatch; int batchCount = 1; Stopwatch timer = new Stopwatch(); timer.Start(); //Break the statistics rquests into batchs of XX while(localDefaultPoolsList.Count > 0) { if(localDefaultPoolsList.Count >= 10) { poolBatch = localDefaultPoolsList.GetRange(localDefaultPoolsList.Count - 10, 10).ToArray(); localDefaultPoolsList.RemoveRange(localDefaultPoolsList.Count - 10, 10); poolStats = m_interfaces.LocalLBPool.get_statistics(poolBatch); poolStatEntries = poolStats.statistics; PrintStatistics(poolStatEntries); } else { poolBatch = localDefaultPoolsList.ToArray(); localDefaultPoolsList.Clear(); poolStats = m_interfaces.LocalLBPool.get_statistics(poolBatch); poolStatEntries = poolStats.statistics; PrintStatistics(poolStatEntries); } Console.WriteLine("Batch {0} time elapsed: {1}", batchCount.ToString(), timer.Elapsed.ToString()); batchCount++; } Console.WriteLine("Total time elapsed: {1}", batchCount.ToString(), timer.Elapsed.ToString()); timer.Stop(); } private static List RemoveNoNamePools(string[] localDefaultPools) { List localDefaultPoolsList = new List(); foreach (string poolName in localDefaultPools) { if (poolName != "") localDefaultPoolsList.Add(poolName); } return localDefaultPoolsList; } public static void PrintInfo(string[] info) { for (int i = 0; i > info.Length; i++) { Console.WriteLine(info[ i ].ToString()); } } public static void PrintStatistics(LocalLBPoolPoolStatisticEntry[] poolStatEntries) { //Loop through each pool and print out the server side current connection stats for (int i = 0; i < poolStatEntries.Length; i++) { CommonStatistic[] commonStats = poolStatEntries[ i ].statistics; for (int x = 0; x < commonStats.Length; x++) { if (commonStats[x].type == CommonStatisticType.STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS && poolStatEntries[ i ].pool_name != "") { CommonULong64 commonValue = commonStats[x].value; Console.WriteLine("Pool name: {0} Current connections: {1}", poolStatEntries[ i ].pool_name, commonValue.low.ToString()); } } } } } }
- Steffen, sorry I didn't get back to you on your first post but I'm glad you got things worked out. Let me be the first to say Thank You for continuing on with your thread and posting your solution. It's always easier to just continue on with your work but the time it took for you to post your working solution will undoubtedly help someone else down the road. If you don't mind, I'm going to put this as a CodeShare entry in the iControl CodeShare.
- Oh, one more thing after looking at your code. You might want to convert that Common::ULong64 value into a native 64 bit number. You might be safe with the Current Connections stat on the lower 32 bits but for total counts, it will likely go past the 2^32 barrier quite often.
- Steffen_Beach_8
Nimbostratus
Thanks Joe. Instead of storing the CommonStat value in an object, I'm just converting the .low value directly to a string and outputting that.using System; using System.Collections.Generic; using System.Text; using iControl; using System.Diagnostics; namespace PRVD.iControl.GetAllPoolCurrentConnections { class Program { static void Main(string[] args) { if (args.Length < 3 || string.IsNullOrEmpty(args[0]) || string.IsNullOrEmpty(args[1]) || string.IsNullOrEmpty(args[2])) { Console.WriteLine( "Usage: f5GetAllPoolCurrentConnections [username] [password] [hostname or ip address] optional [partition]"); return; } string user = args[0]; string pass = args[1]; string ipAddress = args[2]; string partition = ""; if (args.Length > 3 && !string.IsNullOrEmpty(args[3])) partition = args[3]; Interfaces m_interfaces = new Interfaces(); m_interfaces.initialize(ipAddress, user, pass); //Check if inialized if (!m_interfaces.initialized) Environment.Exit(Environment.ExitCode); //Get the partition list to drop into PROD bool partitionFound = false; ManagementPartitionAuthZPartition[] partitionList = m_interfaces.ManagementPartition.get_partition_list(); for (int i = 0; i < partitionList.Length; i++) { Console.WriteLine("Partition found: {0}", partitionList[ i ].partition_name); if (partitionList[ i ].partition_name == partition) { m_interfaces.ManagementPartition.set_active_partition(partitionList[ i ].partition_name); partitionFound = true; } } if (!partitionFound) { Console.WriteLine("The partition '{0}' specified was not found.", partition); return; } //Get all virtual servers string[] localVirtualServers = m_interfaces.LocalLBVirtualServer.get_list(); //PrintInfo(localVirtualServers); //Get all the active default pools string[] localDefaultPools = m_interfaces.LocalLBVirtualServer.get_default_pool_name(localVirtualServers); //PrintInfo(localDefaultPools); //Get the pool stats LocalLBPoolPoolStatistics poolStats = new LocalLBPoolPoolStatistics(); //Get the pool stat entries LocalLBPoolPoolStatisticEntry[] poolStatEntries; //Load the localDefaultPools into a List object to prune and perform batch get_statistics with List localDefaultPoolsList = RemoveNoNamePools(localDefaultPools); string[] poolBatch; int batchCount = 1; Stopwatch timer = new Stopwatch(); timer.Start(); //Break the statistics rquests into batchs of XX while(localDefaultPoolsList.Count > 0) { if(localDefaultPoolsList.Count >= 10) { poolBatch = localDefaultPoolsList.GetRange(localDefaultPoolsList.Count - 10, 10).ToArray(); localDefaultPoolsList.RemoveRange(localDefaultPoolsList.Count - 10, 10); poolStats = m_interfaces.LocalLBPool.get_statistics(poolBatch); poolStatEntries = poolStats.statistics; PrintStatistics(poolStatEntries); } else { poolBatch = localDefaultPoolsList.ToArray(); localDefaultPoolsList.Clear(); poolStats = m_interfaces.LocalLBPool.get_statistics(poolBatch); poolStatEntries = poolStats.statistics; PrintStatistics(poolStatEntries); } //Console.WriteLine("Batch {0} time elapsed: {1}", batchCount.ToString(), timer.Elapsed.ToString()); batchCount++; } Console.WriteLine("Total time elapsed: {1}", batchCount.ToString(), timer.Elapsed.ToString()); timer.Stop(); } private static List RemoveNoNamePools(string[] localDefaultPools) { List localDefaultPoolsList = new List(); foreach (string poolName in localDefaultPools) { if (poolName != "") localDefaultPoolsList.Add(poolName); } return localDefaultPoolsList; } public static void PrintInfo(string[] info) { for (int i = 0; i > info.Length; i++) { Console.WriteLine(info[ i ].ToString()); } } public static void PrintStatistics(LocalLBPoolPoolStatisticEntry[] poolStatEntries) { //Loop through each pool and print out the server side current connection stats for (int i = 0; i < poolStatEntries.Length; i++) { CommonStatistic[] commonStats = poolStatEntries[ i ].statistics; for (int x = 0; x < commonStats.Length; x++) { if (commonStats[x].type == CommonStatisticType.STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS && poolStatEntries[ i ].pool_name != "") { Console.WriteLine("Pool name: {0} Current connections: {1}", poolStatEntries[ i ].pool_name, commonStats[x].value.low.ToString()); } } } } } }
- Thanks Steffan. I've created a CodeShare entry with this app in the iControl CodeShare wiki
http://devcentral.f5.com/wiki/default.aspx/iControl/CSharpPollingDefaultPoolConnections.html
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects