One of the great things about any website is when you don’t have to wait around for it to load. When the website is highly optimised with the focus on performance and website loading times, you get loading speeds that are almost instantaneous. But how do you achieve this high?
Caching with PHP OpCache, Memcached and Varnish
One of the fundamental ways to increase the performance of a website is to cache. Caching is a great means of storing intermediate data so that you don’t have to keep requesting data that may not necessarily be changing frequently. Caching can inevitably act as a middle man between your web application and your database server. Reducing, or in some cases, completely removing the need for any database queries.
Introducing Zend OpCache for PHP5.5
If you’re running PHP 5.5 then you’ve got the pre-compiled Zend OpCache at your disposal. For those wondering, what is OpCache?
OpCache is an opcode caching that improves PHP performance by storing precompiled script bytecode in shared memory. This means that any consequent requests for the same PHP script will not need to be parsed and compiled (as is the case normally) whilst instead a cached version of the script is executed.
Enabling OPcache in PHP5.5
Although PHP5.5 comes with OpCache, by default it is disabled. To enable it you need to update your ‘php.ini’ file with the following:
zend_extension=/path/to/php/opcache.so ; For UNIX
zend_extension=C:pathtophp_opcache.dll ; For Windows
As OpCache impacts the Zend engine that powers PHP, we need to register the extension under Zend, hence why we’re adding it to ‘zend_extension’ rather than just ‘extension’.
Releasing OpCache into the wild
If you’ve enabled OpCache, you probably want to know the five functions that are available to you.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/** * @return array * * Returns an array containing all of our configuration details that OpCache is using. * This includes any default .ini settings, version information and any flagged/blacklisted files. */ opcache_get_configuration(); # Example usage echo '<pre>'.print_r(opcache_get_configuration(), true).'</pre>'; /** * @return array * * Returns an array containing a dump of the current status of the cache; the state the cache is * currently in (could be enabled, restarting, disabled, full), memory footprint, script hits and * misses and some other helpful stats. */ opcache_get_status(); # Example usage echo '<pre>'.print_r(opcache_get_status(), true).'</pre>'; /** * @return boolean * * Clears out the entire cache which forces all scripts to be compiled next visit. */ opcache_reset(); /** * @return boolean * * Invalidates only a specific file from the cache. This file, and only this file, will need to be * re-compiled on next visit. */ opcache_invalidate($phpFile, $force = true); /** * @return boolean * * This forces a PHP to be compiled without actually executing the script. This will only create the opcode cache. */ opcache_compile_file($phpFile); |
How can I track OpCache?
If you want a visual dashboard, you’d probably want to head over to OpCacheGUI which does exactly that.
Installing Memcached on CentOS
Memcached is a high-performance, distributed memory object caching server that’s intended on speeding up dynamic web applications by removing the load on a database server.
Installing a Memcached Server
To install memcached, we’re going to need the RHEL repository, simply call the following:
yum install memcached php-pear php-pecl-memcache
Configuring Memcached
If everything goes accordingly, you’ll be able to configure memcached:
vi /etc/sysconfig/memcached
PORT=”11211″
USER=”memcached”
MAXCONN=”1024″
CACHESIZE=”2048″
OPTIONS=
Starting Memcached
Once you’ve configured your installation, you can set memcached to load when your server does and then start the service:
chkconfig –levels 235 memcached on
service memcached start
To get memcached working with PHP, if you’re on Apache you’ll need to restart:
service httpd restart
If you’re on Nginx, you’ll need to restart PHP-fpm
service php-fpm restart
Using Memcached in PHP
Now that you’ve got memcached installed, we’ll use it to cache the responses from our database queries. In the examples below we’ll be working off a PDO database connection – if you need some code on getting a PDO SQL connection setup then visit our tutorial on creating a PHP RSS feed using PDO.
We’re going to create a class that wraps around our database connection:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
class Database extends PDO { /** * This will store our Memcache connection * * @var Memcache */ private $memcache = NULL; /** * Set up our database instance * */ public function __construct() { parent::__construct("Connection;String"); # Create Memcache connection $this->memcache = new Memcache; $this->memcache->connect('localhost', 11211); } public function fetchCache($statement, $params = array(), $cacheKey = '', $cacheTime = 300) { # Do we want to cache? if(!empty($cacheKey)) { $cacheKey = 'query-'.md5(serialize(array($statement->queryString, $params))); } # Try and get from memory $chechCache = $this->memcache->get($cacheKey); # We have some data if(!empty($checkCache)) { return $checkCache; } # Let's query our data $statement->setFetchMode(PDO::FETCH_ASSOC); # Get results $statement->execute($params); # Store response array $response = $statement->fetch(); # Store in cache $this->memcache->set($cacheKey, $response, MEMCACHE_COMPRESSED, $cacheTime); # Return response return $return; } } # Create a database $database = new Database('...'); # Create a statement $statement = $database->prepare("SELECT * FROM users WHERE id = :id"); # The user we want to get, from a cookie, perhaps? $userID = 1; /** * Now cache the data, we send across our original statement * and the parameters we need (if any). * * If the third parameter is empty, it'll automatically hash the query string. * This will cache for 900 seconds. */ $database->fetchCache($statement, array('id' => $userID), 'user-'.$userID, 900); |
Installing Varnish on CentOS
Varnish Cache is an open source web application accelerator that aims to significantly improve performance of web sites. Varnish can be installed as an front end to any server that serves HTTP requests and can be configured to cache the page responses with a specified TTL (which can conveniently be set through PHP).
The great thing about Varnish is that it’s not too tricky to explicitly control what content and pages are cached, and for how long they’ll remain cached. Varnish is robust in the sense that you’re able to put it in front of any server – we’ve tried on Apache and Nginx with a great success on both.
Installing Varnish Web Accelerator
To install Varnish, we’ll need to load the RPM from the Varnish repository. It’s preferred you use the official Varnish repository instead of relying on EPEL as EPEL doesn’t include every official release due to its lack of supporting backwards incompatible updates.
1 2 |
rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch/varnish-release/varnish-release-3.0-1.el6.noarch.rpm yum install varnish |
Starting Varnish
Starting Varnish is as straight forward as getting it installed:
chkconfig –level 345 varnish on
service varnish start
Configuring Varnish
Varnish is a nifty web accelerator so you’ll more than likely want to update the rules it follows (don’t worry, the documentation is pretty sweet!). You’ll need to adjust some of the ports in the configuration file:
vi /etc/sysconfig/varnish
For a great article on the complete options available and different settings with request and response headers, TTL and grace periods, head over to ‘Configuring Varnish for High-Availability with Multiple Web Servers’
What’s the Overall Impression?
Varnish is a fantastic means of caching anything that your web server responds with. Varnish can dramatically reduce the workload your web server actually has to do. Even if you set your pages with a TTL of 5 minutes, the page will only be requested from the underlying web server a maximum of 12 times. If you combine Varnish with Memcached (or Redis) and take advantage of OpCache – you’re on course to achieving dramatically improved page loading times.
Important Points to Consider when Caching
One of the most important factors when you’re caching is that you don’t want to be serving up stale data. You need to make sure that you’re caching is effective so that users aren’t presented with data pulled out from a cache that was set 5 minutes ago.
I’d always advise that you can cache information which you know doesn’t frequently change. For example, if you’re just reading a user from the database then you can be pretty certain that their personal information won’t change dramatically between visits. That is unless they edit their profile in which you can flag the cache as expired (just make sure you remember your keys).
If you’re running a busy site in which you want to cache data that’s frequently changing. You may want to look at the logic behind your data types and how they’re actually cached. You’ll need to find the balance between how frequently you replace or remove a key from your cache and how long to retain data for.
On the other hand, if you’re fairly certain that your information won’t change then you can look at setting your cache times much higher – perhaps even 15 to 30 minutes until the database needs to be re-queried. This could be the case in terms of blog articles or CMS page content.
Leave a Reply