SharePoint 2013: Network Latency Test script

If you are familiar with the various planning documents on TechNet, then you know that there are some very specific intra-farm network latency requirements outlined at https://technet.microsoft.com/en-us/library/cc262485.aspx.  

The requirement of interest for the blog post is:

  • There is a highly consistent intra-farm latency of <1ms one way, 99.9% of the time over a period of ten minutes. (Intra-farm latency is commonly defined as the latency between the front-end web servers and the database servers.)

In order to ensure proper functioning of the SharePoint farm this requirement must be met.  However, how do you know if the requirement is met if you can’t test it?  Well, Alex Strachan, a clever colleague that works in MCS, wrote a PowerShell script that does exactly that.  I have made some modifications to the script to better suit my preferences but the credit for this idea all goes to Alex.  Thanks Alex for sharing.  If you’d like to see his evolving version of the script please see his blog at https://blogs.technet.com/b/alexst/.

I recommend that this script be run during validation of new deployments as well as on a regular frequency post-deployment to test and verify that there are not any network latencies that have crept into the environment that could be hindering SharePoint operations.

The script performs the following steps:

  1. Ping each of the server in the “server list” to make servers are reachable.
  2. Connect to the SQL server to verify DB connectivity.
  3. Run a 10 minute ping test against each to ensure that the environment meets the <1 ms latency requirement
  4. Generates output to show the percentage of pings that complete in 5 ms, 4 ms, 3 ms, 2 ms and 1 ms respectively

Here is sample output from the script:

 Test Connectivity:
Testing Ping
  Pinging SP2013DC
  Pinging SP2013SPS
  Pinging SP2013SQL
 - Succeeded 
Testing SQL Connection
 - Succeeded 
Starting network consistency tests @ 11/11/2013 14:00:28
Id              Name            State      HasMoreData     Location             Command                  
--              ----            -----      -----------     --------             -------                  
1               SP2013DC.lat... Running    True            localhost            ...                      
3               SP2013SPS.la... Running    True            localhost            ...                      
5               SP2013SQL.la... Running    True            localhost            ...                      
Gathering statistics for 10 minutes... 
Processing Data... 
SP2013DC meets the latency requirements with 0.01% of pings >1ms
SP2013SPS DOES NOT meet the latency requirements with 25.55% of pings >1ms
  (1.68% > 5ms, 3.16% > 4ms, 5.98% > 3ms, 11.86% > 2ms, 25.55% > 1ms)
SP2013SQL DOES NOT meet the latency requirements with 28.36% of pings >1ms
  (1.76% > 5ms, 3.18% > 4ms, 5.96% > 3ms, 12.47% > 2ms, 28.36% > 1ms)

To run the script, you need to edit the following variable(s) as appropriate for your environment

$hostname – a list of SharePoint server names and/or IP addresses

$SQLName – the name of the SQL server that contains the farm config DB

 <#
//*********************************************************

// THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF

// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY

// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR

// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.

// ©2013 Microsoft Corporation. All rights reserved.

//*********************************************************
#>
# Edit these variables to match your environment

$SPServerNames = "SP2013DC", "SP2013SPS", "SP2013SQL"

$SQLServername = "SP2013SQL"
#Edit this if you want to change the durations of the ping test (in minutes)

$RunTime = 10
### test connectivity ###

Write-Host "Test Connectivity:"
Write-Host "Testing Ping"

$ping = New-Object System.Net.NetworkInformation.ping
for($i=0; $i -le $SPServernames[$i].Length-1; $i++){
    Write-Host "  Pinging $($SPServerNames[$i])"
    $status = $ping.send($SPServernames[$i]).Status
        
    if($status -ne "Success"){
        throw "Ping Failed to $($SPSServernames[$i])"
        }
    }
    
Write-Host " - Succeeded `n"
### test SQL connectivity ###

Write-Host "Testing SQL Connection"

#Connect to SQL using SQlCLient the same way that SharePoint Does

$SQLConnection = New-Object System.Data.SQLClient.SQLConnection("Data Source=$SQLServername;Integrated Security=True")

$SQLConnection.Open()

if($SQLConnection.state -ne "Open"){
    throw "SQL Connection Failed"
    }
Write-Host " - Succeeded `n"
### Intra-server latency consistency test ###

Write-Host "Starting network consistency tests @ $([DateTime]::Now)"
$ScriptBlock = {
    # accept the loop variable across the job-context barrier
    param($InHost, $RunTime) 
    $start = [DateTime]::Now
    $ping = New-Object System.Net.NetworkInformation.ping
    
    $PingResults = @()
    while([datetime]::now -le $start.AddMinutes($RunTime)){ 
        $outping = $ping.send($InHost)
        if($outping.Status -ne "Success"){
            $PingResults = $PingResults + 100
            } else{
            $PingResults = $PingResults + $outping.RoundtripTime
            }
        Start-Sleep .1
        } 
    return $PingResults
    }
#run ping jobs in parallel

foreach($i in $SPServernames){
    Start-Job $ScriptBlock -ArgumentList $i, $RunTime -Name "$i.latency_test"
}
Write-Host "`nGathering statistics for $($RunTime) minutes... `n"
#wait and clean up

While (Get-Job -State "Running") { Start-Sleep $($runTime/2) }
$output = @{}

foreach($i in $SPServernames){
    $output[$i] = Receive-Job -Name "$i.latency_test"
}
Remove-Job *
#test results

Write-Host "Processing Data... `n"
$BadPings = @{}

$PercentBadPings = @{}
foreach($i in $SPServernames){
    $BadPings[$i] = $output[$i] | ?{$_ -ge 1}
    $TotalPings = $output[$i].Length
    $PercentBadPingsOver5Ms =  ($BadPings[$i] | ?{$_ -ge 5}).length/$TotalPings * 100
    $PercentBadPingsOver4Ms =  ($BadPings[$i] | ?{$_ -ge 4}).length/$TotalPings * 100
    $PercentBadPingsOver3Ms =  ($BadPings[$i] | ?{$_ -ge 3}).length/$TotalPings * 100
    $PercentBadPingsOver2Ms =  ($BadPings[$i] | ?{$_ -ge 2}).length/$TotalPings * 100
    $PercentBadPingsOver1Ms =  ($BadPings[$i] | ?{$_ -ge 1}).length/$TotalPings * 100
      
    if($PercentBadPingsOver1Ms -ge .1)
    {
        "{0} DOES NOT meet the latency requirements with {1:N2}% of pings >1ms" -f $i, $PercentBadPingsOver1Ms  
        "  ({0:N2}% > 5ms, {1:N2}% > 4ms, {2:N2}% > 3ms, {3:N2}% > 2ms, {4:N2}% > 1ms)`n" -f $PercentBadPingsOver5Ms,$PercentBadPingsOver4Ms,$PercentBadPingsOver3Ms,$PercentBadPingsOver2Ms,$PercentBadPingsOver1Ms
    } 
        else
        {
        "{0} meets the latency requirements with {1:N2}% of pings >1ms`n" -f $i, $PercentBadPingsOver1Ms
        }
    $LatencyTestFailed = 1
    }
    
#if($LatencyTestFailed -eq 1){

#    throw "Farm Latency Test Failed"

#    } 

Powershell Source: CheckNetworkLatency.ps1

I hope you find this post useful and I look forward to reading your comments.

# # # # #