Saturday, May 2, 2015

SharePoint 2013: Application pools recycle when memory limits are exceeded

Problem

After deploying a new SharePoint 2013 farm having three tiers (data, app, web), you stop the SharePoint Foundation Web Application service on the application server(s), since the content web applications are no longer needed on these machines.  A day or so later, you see the following in your farm's Problems and Solutions report:

TitleApplication pools recycle when memory limits are exceeded.
Severity0 - Rule Execution Failure
CategoryPerformance
ExplanationThe system cannot find the path specified.
RemedyIn the Internet Information Services Manager, uncheck any memory-based maximums set for the application pools named above. For more information about this rule, see [URL]
Failing Servers[Application Server]
Failing ServicesSPWebService (WSS_Administration)
Rule SettingsView

and

TitleApplication pools recycle when memory limits are exceeded.
Severity2 - Warning
CategoryPerformance
ExplanationThe application pools named  are configured to recycle when memory limits are exceeded.  Recycling based on memory limits is not usually necessary in a 64-bit environment and should be disabled.  Unnecessary recycling can result in dropped requests from the recycled worker process and slow performance for end users making requests to the new worker process.  If the working set of your worker process grows without bound, analyze the set of applications and components that run in the process to determine whether one of them is leaking memory..
RemedyIn the Internet Information Services Manager, uncheck any memory-based maximums set for the application pools named above. For more information about this rule, see [URL].
Failing Servers[Application Server]
Failing ServicesSPWebService
Rule SettingsView

The solution to this problem is simple, but does involve some tedious administrative steps. Basically, you need to change the web application's application pool to something different, and then remove the original application pool.

Solution
  1. Create new application pool and assign to web application
    1. Draft a name for the new application pool and determine the service account you want to run it on.  This service account should be the same one being used for the existing application pool (eg, spApp).
    2. Log into a SharePoint 2013 server using the SharePoint Setup User Administrator account (eg, spAdmin). This is the same account that you (should have) used to perform the initial farm installation and configuration.
      This is important in that the changes you will be making will be to the farm configuration database; and, by default, only this account has the privileges necessary to make such changes.
    3. Launch an elevated SharePoint Management shell.
    4. Execute the following commands, making appropriate revisions:
      $WebAppURL = "[Your site URL]" $NewAppPoolName = "[Name Of New App Pool]" $NewAppPoolIdentity = "[Identity Of New App Pool]" $Password = Read-Host -Prompt "Enter the service account password: " -AsSecureString $Service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService $NewAppPool = New-Object Microsoft.SharePoint.Administration.SPApplicationPool($NewAppPoolName,$Service) $NewAppPool.CurrentIdentityType = "SpecificUser" $NewAppPool.Username = $NewAppPoolUserName $NewAppPool.SetPassword($Password) $NewAppPool.Provision() $NewAppPool.Update($true) $NewAppPool.Deploy()
      The new application pool will be set immediately.
  2. Identify the application pool to remove
    1. Using the same shell used previously, execute the following command:
      ([Microsoft.SharePoint.Administration.SPWebService]::ContentService).ApplicationPools | Sort-Object Name | Select-Object Name, ID, UserName, Status, parent | Format-Table -Auto
  3. Remove old application pool
    1. Execute the following commands, making appropriate revisions:
    2. Now, using the same management shell, execute the following command to remove the web application pool.
      $apppool = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.ApplicationPools | where {$_.Name -eq "[Name of old web application pool]"} $apppool.UnProvisionGlobally()
References
  • When I originally began building the farm, the first server I built was an application server, and on this server I also deployed the primary content web application, which runs on the SharePoint Foundation Web Application service.  Once the application server was fully built out and configured, I then deployed two web front end servers.  As a part of standing up the web front end servers, the content web applications were automatically instantiated and deployed to them: I did not have to do this intentionally.  I then configured the two WFEs in a network load balanced configuration using Windows 2012 NLB.  At the end of the day, the content web applications were instantiated and running on three servers: the application server and the two WFEs.  Thus, at that time, if you looked into IIS on each of these servers, you would see the content web applications and their associated application pools running on each server.  But because the web application's domain name was associated only with the NLB IP address, when users connected to the web application, they would only connect to the web application running on one of the two WFEs and never to the instance also running on the application server, even though it too was up and running and available.

    So long as this happy state of affairs was unchanged, the rule would: 1) execute against each server, 2) find that each web application pool was associated with a running instance of a web application, and then 3) successfully complete without issue.  However, when I finally got around to stopping the SharePoint Foundation Web Application service on the application server since it was no longer serving any useful purpose, this state of affairs changed, and the rule failed when it ran against the application server.

    The rule makes no distinction as to which server the rule failed on.  You can see this when you view the rule properties: the Scope can be set to All Servers or Any Server, but not to an individual server.  The rule, if it fails, does not identify which server or servers it failed on; only that a failure in fact occurred.

  • The application pool object method UnprovisionGlobally removes all instances of the application pool from all IIS instances on the farm.  On the other hand, when you add an application pool, per the steps above, you only add the application pool to those IIS instances running the content web application.
Extras
  • Command to view all IIS application pools:
    [void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration") (New-Object Microsoft.Web.Administration.ServerManager).applicationpools | sort-object name | ft name
  • Command to remove an IIS application pool: Remove-WebAppPool.

No comments: