Nov 06

How to: Improve the performance / speed of WordPress sites running in IIS

How to: Improve the performance / speed of WordPress running in IIS

To be entirely honest I am still struggling with this topic. However I have identified a few points that should help improve the performance / speed of a WordPress site running in IIS. Now, if a distinction should be made it would be this: You can generally offer your end users a site that appears on screen within milliseconds… but you’ll be serving static content. As an admin having WordPress respond instantly seems basically impossible specially using a Windows Host. So this guide will mostly help you get your site’s visitor a speedier feel of your site and improve your Google PageSpeed but that’s about it.

I. Try to avoid network lag

So I had this great idea of a wold where you have front end and back end services, in different subnets, with a load balanced web server farm running off a shared networking location… well…. it slows down your WordPress installation considerably. Here is what I have learned:

  • Having servers on different subnets means there is added lag courtesy of your gateway. So during non peak times it is pretty much nothing and during busy network times it could add a few milliseconds. Multiply that by a bunch of database queries over a short period of time and it could add up.
  • Every time you access a page it needs to read off your network the php files to compile (yes, every single web request). I know we all have state of the art servers and yes I can “brag” I can sustain 300mbps speeds with no problem between my servers but that has nothing to do. Each network request needs to be authenticated, transmitted, loaded into memory, etc… so you can imagine how this adds another lag to your web server.

So the message is simple: avoid as much as possible using network resources and try to have as much as possible locally. In the case of the site’s files I took the approach of DFS replication so that all my files are shared across my Web Servers. Obviously there could be sync issues vs the one point shared location so it all depends on your use. If you have a bunch of WP users doing file changes it could turn ugly but if there is only 1 admin doing it I see little risk. Also, DFS at full speed replication 24×7 will replicate file changes or uploads within seconds. If you have crazy needs then there are crazy solutions offered out there but for normal people with only 1 web server… host your files locally in a fast drive. In the case of the database… well having it locally would be nice but if it is remote there are apps offering db caching but we’ll talk about that later on.

II. Use Server side caching and URL Compression

IIS has some wonderful caching technology you can rely upon. So really what you need to understand is how to leverage server side caching. The problem with apps nowadays is that all the content is generated dynamically. What this means is that in order to cache a page you need either static content (static HTML pages vs dynamic php) or technology that caches this content (WP plugins) and serves it. My recommendation here is that you use IIS caching mechanism for all your static content and if you are running WordPress you use a plugin like W3 Total Cache which can cache a wide variety of parts of your website like pages, objects, db queries and set the cache properties for web browsers to cache your content as well.

Now, a word of caution: There are so many settings and fine tuning you have to perform that you better invest some time getting familiar with the concepts and testing the results. For example, W3 Total Cache has a feature called Minify. The idea is simple but the implementation can get complex. If you don´t configure the settings correctly you might break your javascript or CSS in your site. Even worse, I had everything set up correctly but apparently there is some bug that the minified files don´t get generated on the disk and therefore there is no styling happening on the site. So you might need to tweak settings and even turn off features. Keep in mind this may interact negatively with other plugins and that other Minify plugins might not be compatible with features like Multisite.

III. Identify Javascript, CSS & External resources slowing down your page

Use a tool such as http://www.webpagetest.org/ to see the external resources and scripts that might be slowing down your page. Leverage existing resources like Google’s PageSpeed to get suggestions on what to improve. Some aspects might be easy to fix while others and entire pain in the neck but it’s worth it.

IV. Move to a better host

Believe it or not, it matters. I was hosting with this random provider I found through a Microsoft promotion many years back and thought to myself: “Hey, Godaddy is awesome let´s switch”. I was having an average response of 800 ms and after the switch it went up to about 4 – 8 seconds. Clearly hosting WP on a Windows box is not the greatest idea but still for response times to go x10 is way too much. Be sure to consider this as part of the problem might be the server that is hosting your site.

V. Tune PHP for IIS

As you probably know PHP is originally developed to be executed on Unix systems (Linux, etc) and WordPress was originally developed for the LAMP infrasctructure: Linux, Apache, MySQL, PHP (in this case). So it comes at no surprise that PHP on IIS is not really comparable in features/performance. This is particularly true back in 2006 when you start seeing the first PHP installations on Windows IIS. Over time you start seeing new improvements that really make a difference. Take for example Fast CGI released in 2007, then PHP 5.3 developed with Windows in mind during 2008, in 2009 WinCache is realeased. In PHP 5.5 there is a Zep OpCache which replaces some functionality of WinCache for OpCode. So as you can appreciate over the years PHP is becoming more and more Windows friendly but you need to make use of these features. If you are not using Fast CGI, WinCache, and the latest versions of PHP there is a lot of performance improvements you are missing out on.

  • 1. PHP Performance on Windows Mark Brown, Ruslan Yakushev Microsoft
  • 2. A Little History 2006 • PHP on Win/IIS = Big Joke 2007 • IIS FastCGI 2008 • windows.php.net • PHP 5.3 2009 • PHP 5.3 Release • WinCache 1.0 2010 • FastCGI 1.5 • WinCache 1.1
  • 3. PHP Community and Microsoft • “PHP on Windows” project involves: – PHP core developers – PHP installer developers – PHP documentation team – PHP community and influentials – PHP applications communities (WordPress, Joomla, Drupal, others) – Many others…
  • 4. CGI  FASTCGI
  • 5. CGI vs FastCGI • (CGI on Windows) == SLOW !!! – New PHP process per request • FastCGI == (CGI on steroids) – Re-use PHP processes in a process pool – Single-threaded execution environment – Use Non-Thread Safe PHP with IIS FastCGI • PHP ISAPI? – Stay away!!! Use FastCGI instead – No ISAPI support in 5.3 anyway
  • 6. CGI vs. FastCGI
  • 7. CGI vs. FastCGI CGI Processes FastCGI processes
  • 8. FastCGI 1.5 • New features: – Auto-tuning of maxIntances for optimal performance – Automatic recycling of PHP processes with config change MonitorChangesTo setting – No more restarts with changes to php.ini • Consistent set of features across all IIS versions: – For IIS 7.5 in WS08 R2 – new features are included – For IIS 7.0 in WS08 – install the FastCGI update (http://www.iis.net/expand/FastCGI) – For IIS 5.1 & 6.0 – install FastCGI 1.5 extension
  • 9. IIS FastCGI and PHP Setup – automated • Use the easiest option – Web Platform Installer!  Get Web Platform Installer from http://www.microsoft.com/web/php/
  • 10. Add PHP installer option
  • 11. IIS FastCGI & PHP Setup – manual • Follow the instructions on php.net: • IIS 5.1 and IIS 6.0: – php.net/manual/en/install.windows.iis6.php • IIS 7 and later: – php.net/manual/en/install.windows.iis7.php • PHP configuration – php.net/manual/en/install.windows.manual.php
  • 12. PHP 5.2  PHP 5.3
  • 13. PHP 5.3 improvements • PHP 5.3 improvements: – Using VC9 compiler (PHP 5.2 used VC6) – Optimized API calls (using Win32 instead of POSIX) – All PHP libraries built from the source code – Compatibility fixes • Windows builds are available at: – http://windows.php.net/ From: http://ilia.ws/files/Confoo2010_PHP53.pdf “Substantial performance improvements on Windows (40% +)”
  • 14. WINCACHE
  • 15. WinCache 1.0 • PHP Accelerator optimized for Windows – Opcode cache – File cache – Resolve path cache • Download from: – http://www.iis.net/expand/WinCacheForPhp • Contributed by MS to PECL: – Source code on http://pecl.php.net/wincache/ – Documentation on http://www.php.net/wincache/ – BSD license Contributions are welcome!
  • 16. Why use opcode cache? To serve an index.php in WordPress, PHP has to read, parse, compile and execute more than 100 PHP files!
  • 17. WinCache in action Just add extension=php_wincache.dll in php.ini. No app code changes necessary!
  • 18. WinCache and CPU usage • WinCache significantly reduces CPU load • Use FastCGI maxInstances setting to load CPU more • Set maxInstances to 0 to enable auto tuning
  • 19. WinCache and CPU usage Increased FastCGI maxInstances from 4 (default) to 10
  • 20. WinCache 1.1 User Cache API: • Stores app data in shared memory • Function by function compatible with APC
  • 21. WinCache 1.1 – Session Handler • Stores PHP session data in shared memory • Enabled in php.ini : session.save_handler = wincache • Session storage is not persistent in beta, but will be in RC: – Use the code snapshot to try it out.
  • 22. WinCache 1.1 user cache in action Instructions on how to configure WordPress to use WinCache user cache: http://ruslany.net/2010/03/make-wordpress-faster-on-iis-with-wincache-1-1/
  • 23. WinCache statistics script Always restrict access to wincache.php by using built-in authentication or web server authentication!
  • 24. What’s next? • Popular PHP applications to adopt WinCache: – Joomla 1.6 – Drupal cacherouter module – Sugar CRM • WinCache improvements: – File change notifications support – Function hooks
  • 25. Summary • In 3 years Windows/IIS has become a great option for hosting PHP applications • In 2 years the PHP performance on Windows has improved considerably.
  • 26. PHP on Windows – Contacts • Pierre Joye • Venkat Raman Don • (PHP Core Developer) – [email protected] • (IIS and WinCache Tester) – [email protected] – http://twitter.com/PierreJoye – http://blogs.iis.net/donraman • Mark Brown • Kanwaljeet Singla • (Web Platform) • (IIS and WinCache – twitter.com/markjbrown Developer) – blogs.msdn.com/markbrown/ – [email protected] – http://twitter.com/kjsingla • Ruslan Yakushev – http://blogs.iis.net/ksingla/ • (IIS Program Manager) – [email protected] – http://twitter.com/ruslany – http://ruslany.net/
  • 27. PHP on Windows – resources • http://windows.php.net/ • http://php.iis.net/ • php.windows mailing list • http://forums.iis.net/

And here are a few improvements I suggest (plugins, etc):

I. Install WP Super Cache plugin

I think this is the way to go vs WP Total Cache as it generates HTML pages instead of PHP pages and your IIS site can leverage caching and delivery of static content much better

II. Install WP Better Minify plugin

Again, WP Total Cache has minification powers but then again… it doesn’t. At least on my different IIS sites the minified .jss and .css were never created in the file directory so I gave up and tried this plugin which is working great. I do believe however that it needs some fine tunning:

  • Go to: /site/wwwroot/wp-content/plugins/bwp-minify/min/ and open the Config.php file. There you should fine tune it to your needs. In my particular case here are the noteworthy settings I modified:
    • $min_serveOptions[‘maxAge’] = 7200; try setting it to at least a week per Google’s recommendation. So that would be $min_serveOptions[‘maxAge’] = 604800;
    • To use Google’s Closure Compiler API to minify Javascript (falling back to JSMin on failure), uncomment the following line:
      $min_serveOptions[‘minifiers’][‘application/x-javascript’] = array(‘Minify_JS_ClosureCompiler’, ‘minify’);
  • Go to: /site/wwwroot/wp-content/plugins/bwp-minify/includes/ and open the class-bwp-minify.php to modify the js to be asynchronous so Google would like it better. Keep in mind doing so might break some thing but worth a try.
    •    case ‘script’:
      $return  = “<script type=’text/javascript’ src='” . $this->get_minify_src($string) . “‘ async></script>n”;

As I continue to discover other important factors that impact a site’s responsiveness/speed/performance I will continue to update this post. However, as an extreme of the kind of benefits you might receive with the above mentioned “improvements” you could see an 8 second response go down to less than 400 ms. Definetively something worth taking a look, just keep in mind this improvement is for your general reader, logged in users / admins that depend on the dynamic content being generated will find indirect improvement from general user’s decreased server use mainly.

Update 1 (September 2014):

I also recommend looking to available/allocated memory to your php process: How to: Increase the memory being allocated to PHP

Leave a Reply

%d bloggers like this: