Scalability Best Practices for SharePoint 2013’s Architecture

Posted by Errin O'Connor on May, 10, 2015 10:05

It is important to implement a highly available as well as scalable SharePoint 2013 platform and avoid some of the known pitfalls that degrade its performance, such as the following:

  • Having all SharePoint services in the “default” service group
  • Having JavaScript that has not been optimized or deployed in a best practices manner
  • Procuring or having inadequate hardware
  • Not paying enough time and attention to SQL Server’s configuration and its optimization
  • Not providing the proper tools to allow for monitoring and reviewing the underlying server logs

If you are experiencing performance issues, it is key to first attempt to perform exercises such as load testing in a similar or replicated environment, as well as reviewing the IIS logs, the server’s performance, and latency for web, service, and SQL servers. There are some obvious metrics that are sometimes overlooked, such as memory, RPS, and the CPU’s statistics.

There are some major updates or architectural considerations in relation to SharePoint 2013, such as discouraging dedicated service farms that end up increasing server count as well as overall maintenance requirements.

It is also important to use as few application pools as possible in SharePoint 2013 because each application pool takes up memory and resources, and it is better to share these resources to avoid some of the caching errors that have come up in many enterprise wide farms.

There is also a recommendation for one web application as well as one corresponding zone as well as using host-named site collections that allow for reduced resource consumption and much better scalability. You are always able to have multiple host names in regard to secure site access (SSA).

SharePoint 2013’s Search and Scalability Recommendations

SharePoint 2013’s search, which now includes fast search, has very different metrics involved in the scalability of search. For example, for every 10 million items, there is a scaling recommendation to add an index partition.

With 20 million items, the scaling recommendation is to add a new crawl database, and with 30 million items, it is recommended to go with a dedicated search farm. I have also seen some great results when providing a dedicated host for crawling on the crawling target server.

Your search will always function at a higher level when it is originally architected with best practices in mind with defined targets and proper logical and physical architecture.

SharePoint 2013’s SQL Server 2012 Scalability Recommendations

There are a lot of similarities in recommendations from past versions of SharePoint. It is key to ensure that you always use SQL aliases whenever possible because this makes later migrations or database moves much easier and can save 100 or more hours of rework if those changes are ever needed.

There are several candidates for aliases, and if you begin with one SQL Server instance and three aliases, you will have the option to scale and later move any highly used databases into a dedicated SQL node.

SQL Server 2012 R2 comes with new AlwaysOn for redundancy capabilities, which is native in SQL Server 2014. This does require Windows Server Failover Clustering (WSFC).

[gravityforms id=41 title=”true” description=”false”]
<div class='gf_browser_unknown gform_wrapper exit_intent_popup_wrapper' id='gform_wrapper_41' ><form method='post' enctype='multipart/form-data' id='gform_41' class='exit_intent_popup' action='/scalability-best-practices-sharepoint-2013/'> <div class='gform_heading'> <h3 class='gform_title'>Exit Intent</h3> <span class='gform_description'></span> </div> <div class='gform_body'><ul id='gform_fields_41' class='gform_fields top_label form_sublabel_below description_below'><li id='field_41_1' class='gfield gform_hidden field_sublabel_below field_description_below gfield_visibility_visible' ><input name='input_1' id='input_41_1' type='hidden' class='gform_hidden' aria-invalid="false" value='' /></li><li id='field_41_9' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_9' >Full Name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_9' id='input_41_9' type='text' value='' class='medium' placeholder='Full Name' aria-required="true" aria-invalid="false" /></div></li><li id='field_41_6' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_6' >Email<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_email'> <input name='input_6' id='input_41_6' type='text' value='' class='medium' placeholder='Email Address' aria-required="true" aria-invalid="false" /> </div></li><li id='field_41_7' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_7' >Phone<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_phone'><input name='input_7' id='input_41_7' type='text' value='' class='medium' placeholder='Phone Number' aria-required="true" aria-invalid="false" /></div></li><li id='field_41_10' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_10' >Company Name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_10' id='input_41_10' type='text' value='' class='medium' placeholder='Company Name' aria-required="true" aria-invalid="false" /></div></li><li id='field_41_8' class='gfield field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_8' >Message</label><div class='ginput_container ginput_container_textarea'><textarea name='input_8' id='input_41_8' class='textarea medium' placeholder='Type your message here...' aria-invalid="false" rows='10' cols='50'></textarea></div></li> </ul></div> <div class='gform_footer top_label'> <input type='submit' id='gform_submit_button_41' class='gform_button button' value='Submit' onclick='if(window["gf_submitting_41"]){return false;} window["gf_submitting_41"]=true; ' onkeypress='if( event.keyCode == 13 ){ if(window["gf_submitting_41"]){return false;} window["gf_submitting_41"]=true; jQuery("#gform_41").trigger("submit",[true]); }' /> <input type='hidden' class='gform_hidden' name='is_submit_41' value='1' /> <input type='hidden' class='gform_hidden' name='gform_submit' value='41' /> <input type='hidden' class='gform_hidden' name='gform_unique_id' value='' /> <input type='hidden' class='gform_hidden' name='state_41' value='WyJbXSIsIjEwNTJhNGVmMWMyNzI3YTJmMjdiZTA1NjU4ZDMzYzY3Il0=' /> <input type='hidden' class='gform_hidden' name='gform_target_page_number_41' id='gform_target_page_number_41' value='0' /> <input type='hidden' class='gform_hidden' name='gform_source_page_number_41' id='gform_source_page_number_41' value='1' /> <input type='hidden' name='gform_field_values' value='' /> </div> </form> </div><script type='text/javascript'> jQuery(document).bind('gform_post_render', function(event, formId, currentPage){if(formId == 41) {if(typeof Placeholders != 'undefined'){ Placeholders.enable(); }jQuery('#input_41_7').mask('(999) 999-9999').bind('keypress', function(e){if(e.which == 13){jQuery(this).blur();} } );} } );jQuery(document).bind('gform_post_conditional_logic', function(event, formId, fields, isInit){} );</script><script type='text/javascript'> jQuery(document).ready(function(){jQuery(document).trigger('gform_post_render', [41, 1]) } ); </script>