Scaling SharePoint 2016 On-Premise for Office 365 like performance

I’d like to preface this post with that fact that I will not be focusing on high-availability, disaster recovery, Site Collection and Database allocation, disk subsystems, physical verses virtual server environments, bandwidth, and backups.

Perhaps it is a combination of Microsoft’s release cycle and the changing of the seasons but lately I have been seeing an influx of SharePoint 2016 On-Premise deployments.  Most of these SharePoint 2016 On-Premise deployments are upgrades to SharePoint 2010 and SharePoint 2013 On-Premise environments for customers whose organization is not Cloud ready yet for one reason or another. This recent end of the year demand has led me to come up with a way of comparing Office 365 SharePoint and SharePoint 2016 performance and readiness experience.

The Client’s whose deployments I would like to ‘blog’ about are ranging from 150-500 users with approximately 2 terabytes of SharePoint content.

If we follow Microsoft’s performance scaling for my SharePoint 2016 environment, Microsoft would recommend the following approximate configuration.

Server Specifications – Sample 1

Server Item Quantity
SharePoint 2016 Application / Web Front End CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 300GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SQL Server CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 2000GB
    E Drive: 2000GB
    L Drive: 2000GB
    T Drive: 500GB
  Operating System Windows Server 2016
  Application SQL Server Standard 2016

While the above configuration will run SharePoint 2016 the first performance concern we will notice will be related to Search Indexing.

When we attempt to index and crawl content in the above configuration, the page serving performance of our SharePoint environment will be dramatically degraded.  To solve that challenge we need to add at least one dedicated Indexing / Crawling Server.

Server Specifications – Sample 2

Server Item Quantity
SharePoint 2016 Application / Web Front End CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 300GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Index CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 400GB
    D Drive: 500GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SQL Server CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 2000GB
    E Drive: 2000GB
    L Drive: 2000GB
    T Drive: 500GB
  Operating System Windows Server 2016
  Application SQL Server Standard 2016

Of course, now we will have adequate page loading times without performance being degraded by Search Indexing, however our Search Query performance may slow.  To address this performance degradation, we will need to add a dedicated Search Query server.

Server Specifications – Sample 3

Server Item Quantity
SharePoint 2016 Application / Web Front End CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 300GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Index CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 400GB
    D Drive: 500GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Query CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 100GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SQL Server CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 2000GB
    E Drive: 2000GB
    L Drive: 2000GB
    T Drive: 500GB
  Operating System Windows Server 2016

Now we will have adequate Search and page loading performance, but what if we start to utilize a lot of background services and workflows, our page load times will decrease as our Application server is also our Web Front End, so again, we must increase our server footprint.

Server Specifications – Sample 4

Server Item Quantity
SharePoint 2016 Application CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 300GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Web Front End CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 100GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Index CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 400GB
    D Drive: 500GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Query CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 100GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SQL Server CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 2000GB
    E Drive: 2000GB
    L Drive: 2000GB
    T Drive: 500GB
  Operating System Windows Server 2016
  Application SQL Server Standard 2016

And last but not least, our user base really would like the features of Office Online Server with the ability to Co-Author and work on Microsoft Office documents within the web browser, so once again, we must expand our configuration to the following.

Server Specifications – Sample 5

Server Item Quantity
SharePoint 2016 Application CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 300GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Web Front End CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 100GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
Office Online Server CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 100GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Index CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 400GB
    D Drive: 500GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SharePoint 2016 Search Query CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 100GB
  Operating System Windows Server 2016
  Application SharePoint Server 2016
     
SQL Server CPU 4 Cores – 64bit
  RAM 24GB
  Approximate Hard Drive Configuration C Drive: 100GB
    D Drive: 2000GB
    E Drive: 2000GB
    L Drive: 2000GB
    T Drive: 500GB
  Operating System Windows Server 2016
  Application SQL Server Standard 2016

As you can see, without mentioning backups, high-availability, and disaster recovery; the footprint for a SharePoint 2016 On-Premise environment with comparable performance to SharePoint within Office 365 will be rather large and costly.

Advertisements

Converting Content Types, Records Center, and PowerShell

I recently started a project with a customer who wanted to implement a SharePoint Records Center and complex Record Retention Policies based around the age of documents, metadata, and Content Types. There was one major problem, the Client was currently using the out of the box “Document” Content Type across all sites and Site Collections and was using library specific Metadata.

My solution was to create Content Types whose Site Column Metadata matched that of the Metadata in specific libraries (using Managed Metadata was not practical for this Client) we then had to programmatically update the Content Types in every library before implement the Records Center, Content Organizer, and Retention Policies.

To do this, I wanted to be able to iterate through a Document Library, all of its Folders, and based conditionally around an existing Content Type, convert to another Content Type  while preserving Metadata including ‘Modified’ and ‘Modified By’ fields….Behold PowerShell to the rescue. 

I will openly admit, this script is not all entirely my original ideas, I leverage a few concepts from other individuals online and combined them together.

Feel free to use this script and modified it as needed.

 

#loading SharePoint Powershell Snapin
Add-PSSnapin Microsoft.SharePoint.PowerShell
write-host “setting web variable”
#The URL of the SharePoint site and subsite that contains the library
$web = Get-SPWeb “https://MySharePointSite/Subsite”
write-host “after setting web variable”
write-host “before setting list variable”
#below is where we define the Library name
#use the library name and not the library URL string.  Spaces are acceptable
$list = $web.Lists[“Documents”]
write-host “after etting list variable”
#Get Item by ContentType
write-host “before foreach item loop”
foreach ($item in $list.Items) {
    write-host “inside foreach item loop”
            
    #Inside the ‘if statement’ below, enter the name of your original content type
    #I left this as “Document”  
   
    #here is where we set the original content type name
    if($item.ContentType.Name -eq “Document”) {
        write-host “inside conditional ContentType logic”
                                        
        write-host “before modifying content type”
        # disable event firing / stop changing modified date
        $myAssembly = [Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint”);
        $type = $myAssembly.GetType(“Microsoft.SharePoint.SPEventManager”);
        $prop = $type.GetProperty([string]”EventFiringDisabled”,[System.Reflection.BindingFlags] ([System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static));
        $prop.SetValue($null, $true, $null);
        write-host “setting new content type”
        #here is where we enter the new content type name
        $item[“ContentType”] = “New ContentTypeName”
        write-host “saving changes to content type without modifing the Modified or Modified By Fields”
        # saving content type changes
        $item.SystemUpdate($false)
        # enable event firing
        $prop.SetValue($null, $false, $null);
    }
                                        
}