SharePoint / Guide 8
Performance: warm-up and caching
Warm-up scripts, the object cache, the BLOB cache and the page output cache.
Most SharePoint Server performance complaints come down to four things: cold application pools, publishing features working without their caches, static files read from SQL on every request, and pages rendered again for every user. This guide covers the fixes: warm-up scripts, the object cache, the BLOB cache and the page output cache.
Which cache does what
| Warm-up | Object cache | BLOB cache | Page output cache | |
|---|---|---|---|---|
| Solves | Slow first page after a recycle | Repeated reads of the same list items, navigation and queries | Static files read from SQL | The same page rendered again and again |
| Stores | Nothing; it pre-loads | Objects in the web server's memory | Files on the web server's disk | Rendered HTML in memory |
| Needs publishing features | No | Yes | No (SharePoint Server, not Foundation) | Yes |
| Best for | Every farm | Publishing and portal sites | Portals, sites with images and video | Anonymous and read-mostly publishing sites |
Warm-up: remove the slow first hit
IIS recycles each application pool regularly (by default once a day). The next request after a recycle has to load and compile SharePoint's assemblies and pages, which can take 30 seconds or more. Whoever makes that request, often the first user in the morning, pays for it.
A warm-up script requests the important pages right after the recycle, so users never see a cold server.
- Set a predictable recycle time. In IIS Manager, for each SharePoint application pool, open Recycling and use a specific time outside business hours (for example 2:00 AM) instead of a fixed interval.
- Schedule the warm-up 10 to 15 minutes later with Task Scheduler, on every web server, running as an account with read access to the sites:
powershell
.\Invoke-SPWarmup.ps1 -IncludeSubsites -LogFile D:\Logs\Warmup.csv
Invoke-SPWarmup.ps1 requests the home page of every site collection (and optionally every subsite) plus one application page per web application, and logs the status and time of each request.
- Make each server warm itself. Behind a load balancer, a request for
https://sharepoint.ravindran.inmight go to any server. On each web server, add a hosts file entry pointing the site names at that server's own IP address, so the warm-up hits the local server. Because Windows blocks authenticated requests back to the local machine by default, add the site names to theBackConnectionHostNamesregistry value on that server (this is safer than turning off the loopback check entirely).
Also run the warm-up after patching, after an IIS reset, and after deploying solutions.
Object cache
The object cache keeps frequently read objects (list items used by navigation, content query web part results, cross-list queries) in each web server's memory. It's part of the publishing infrastructure.
Configure the super user and super reader accounts. The object cache reads content as two special accounts so it can cache one copy for all users and then trim it per user. If they aren't set, SharePoint falls back to slower behaviour and logs warnings (event ID 7362) in the Application event log.
- Create two dedicated domain accounts, for example
RAVINDRAN\sp-superuserandRAVINDRAN\sp-superreader. Nobody should sign in with them, and they must not be the application pool or farm account. - Give them Full Control and Full Read user policies on the web application, and store them in the web application's properties.
Set-SPObjectCacheAccounts.ps1does both:
powershell
.\Set-SPObjectCacheAccounts.ps1 -WebApplication https://sharepoint.ravindran.in `
-SuperUser RAVINDRAN\sp-superuser -SuperReader RAVINDRAN\sp-superreader -WhatIf
- Run
iisreseton every web server.
Test straight away. If these accounts are wrong (a typo, or an account that doesn't exist), publishing sites can return "access denied" to everyone. Run the script outside business hours and browse the sites immediately afterwards.
Size it. The default is 100 MB per site collection, set in Site Settings > Site collection object cache. The web application-wide limit is the <ObjectCache maxSize="100" /> element in web.config. Increase it for large portals with heavy navigation or many content query web parts.
BLOB cache
The BLOB cache serves images, style sheets, scripts and video from each web server's disk instead of the SQL content database, and tells browsers to cache them. It has its own guide: see BLOB cache: why and how.
Page output cache
The page output cache stores the fully rendered HTML of publishing pages and serves it to the next user who's allowed to see the same version, skipping page rendering entirely. It helps most on anonymous internet sites and read-mostly intranet portals.
- In the site collection, go to Site Settings > Site collection output cache and turn it on.
- Choose a cache profile. The built-in profiles are: - Public Internet (Purely Anonymous): longest caching, for anonymous sites. - Extranet (Published Site): for authenticated, read-mostly sites. - Intranet (Collaboration Site): shorter caching, varies by user rights. - Disabled.
- Optionally allow page layouts and individual sites to override the profile.
Keep it off for collaboration sites where content changes constantly or pages are personalised per user. The web application-wide defaults are in the <OutputCacheProfiles> element of web.config, including varyByRights="true", which keeps users with different permissions from seeing each other's cached pages. Leave that on.
Other quick wins
- SQL Server: set max degree of parallelism (MAXDOP) to 1 on the SQL instance that hosts SharePoint databases (this is a SharePoint requirement), pre-size databases, and use fixed-size autogrowth rather than percentages.
- Keep content databases a manageable size, as covered in the SharePoint Server tips.
- Distributed Cache: give it enough memory and keep it off busy search servers (see the services guide).
- Find slow pages with the Developer Dashboard, which shows the time spent in each part of a page:
powershell
$svc = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$dds = $svc.DeveloperDashboardSettings
$dds.DisplayLevel = 'On' # set back to 'Off' when finished
$dds.Update()
- Crawl from a dedicated target so search doesn't slow down users (see the search guide).