Last Tuesday, Zend Optimizer+ was released as open source software and I couldn't resist taking it for a spin. This piece of software is a serious candidate to be integrated in the PHP core and is an alternative to APC, another opcode cache solution. Which makes it very interesting for all PHP developers. Let's see what Zend Optimizer+ actually is and how it can be installed.
PHP is an interpreted language. This means that every time a web page is requested, the server has to compile all the PHP files needed to generate it from source to a binary format that the machine understands. Needless to say, this is slow. There are many PHP accelerators on the market that are basically extensions, designed to improve the performance of software applications.
Most of them solve the compilation problem by caching the binary format (also known as bytecodes or opcodes) of the PHP scripts in a shared memory location, from where it can be executed directly. This substantially increases the speed of PHP applications. If your code does not yet use an opcode cache, it is advised to start using one right now.
At the time of this writing, one of the most widely used opcode caches for PHP is the Alternative PHP Cache (APC). This cache does not limit itself to opcode caching, but it also provides a user cache. This user cache is basically a key-value store that uses a configurable amount of memory. APC also has a nice GUI that looks something like this:
Some time ago, APC was even so popular that all the major PHP developers decided to officially endorse APC and had it scheduled for inclusion in the PHP core no later than PHP 6. A lot has happened since, PHP 6 did not happen yet and APC is still not in core.
Another PHP accelerator is Zend Optimizer+. It also improves PHP performance by storing precompiled script bytecode in the shared memory. This eliminates the stages of reading code from the disk and compiling it on future access. In addition, it applies a few bytecode optimization patterns that make code execution faster.
Last month, PHP developer and co-founder of Zend Technologies Zeev Suraski announced that Zend was looking into open-sourcing Zend Optimizer+ and including it into PHP 5.5. Yesterday, Optimizer+ was effectively released as open source software at https://github.com/zend-dev/ZendOptimizerPlus/.
Zeev also opened a PHP request for comments (RFC) at https://wiki.php.net/rfc/optimizerplus to integrate Optimizer+ into the PHP distribution. This means that the next version of PHP may have Optimizer+ built-in as an opcode cache, which suddenly makes it a very interesting piece of software for all PHP developers.
I immediately booted one of my Debian development boxes with a recent PHP 5.4 to take it for a spin. The first thing you will need to do is remove APC, if you have it installed, because it will interfere with Optimizer+:
apt-get remove php5-apc
Or just disable the module like this:
Then, clone the Git repository from GitHub:
git clone git://github.com/zend-dev/ZendOptimizerPlus.git
This downloads the extension source code on your machine. In order to compile it, you need to have the PHP module development package installed:
apt-get install php5-dev
Change directory into ZendOptimizerPlus, phpize, run the configure script and then compile the extension:
The extension will be compiled into the .libs folder. Copy it into your PHP extension library:
cp .libs/ZendOptimizerPlus.so /usr/lib/php5/20100525/
Now you can configure PHP to load the extension. If you would like to tune the extension to match your exact needs, consult the README where all parameters are well documented. You can already configure the extension to use sane defaults, like described in the README on GitHub:
cat << EOF > /etc/php5/mods-available/ZendOptimizerPlus.ini
When you restart your Apache2 server and take a look at phpinfo() output, you will now have the following section:
Optimizer+ does not come with a nice PHP statistics page like APC but you can use the "accelerator_get_status()" function to print memory usage, cache statistics and the list of cached PHP scripts. The function returns an array containing the following elements:
accelerator_enabled - boolean; TRUE if code acceleration is enabled, FALSE otherwise
cache_full - boolean; TRUE if the Optimizer+ cache is full
memory_usage - array; contains information about Optimizer+ memory usage, with the following keys:
used_memory - integer; bytes of memory used
free_memory - integer; bytes of memory available for cache
wasted_memory - integer; bytes of memory used by invalid or outdated code
Wasted memory is reclaimed when the accelerator is reset, or when the percentage of wasted memory reaches the value of the max_wasted_percentage directive
current_wasted_percentage - float; The percentage of wasted opcode cache memory out of total memory available
accelerator_statistics - array; contains current opcode cache usage statistics, with the following keys:
num_cached_scripts - integer; number of cached scripts
max_cached_scripts - integer; maximum number of cached scripts
hits - integer; number of cache "hits" - that are requests for files that had valid cache entries
last_restart_time - integer; timestamp of the last restart time
misses - integer; number of cache "misses" - that are requests for files which were not cached
blacklist_misses - integer; number of requests to blacklisted files
blacklist_miss_ratio - float; ratio between hits and requests to blacklisted files
accelerator_hit_rate - float; ratio between opcode cache hits and misses
scripts - array; Each key in the array is the name of an accelerated script. Values are an array with information about the script, with the following keys:
full_path - string; the full path to the script
hits - integer; number of cache hits for this script
memory_consumption - integer; bytes of memory used to cache this script
last_used - string; string representation of the last time this script was fetched from cache. For example "Thu Jan 31 13:37:40 2008"
last_used_timestamp - integer; UNIX timestamp of the last time this script was fetched from cache
timestamp - integer; UNIX timestamp of when the script was cached
Edit: 27/feb/2012: Some frameworks / CMSes were benchmarked by Zeev, you can find the results linked in the RFC. Symfony2 was missing from this list, so I did a benchmark myself with Symfony2.1.8 on Nginx / PHP FPM 5.4.8. Optimizer+ is version 7.0.0-dev, APC is 3.1.13. The Y axis contains the number of requests per second.
The RFC is still under discussion but Zend Optimizer+ is a good candidate to make it into the PHP core.
One of the downsides of Optimizer+ is that it does not have a user cache API like APC. Another important point is that APC uses a memory manager and can reclaim memory associated with a script that is no longer in use. Optimizer+ just marks such memory as dirty, but never actually reclaims it. Optimizer+ restarts itself once the dirty percentage climbs above a configurable threshold.
On the upside, Optimizer+ promotes itself to have a consistent performance edge over APC. Also, it advertises to be fully compatible with PHP releases even before they come out. Lastly, Optimizer+ has optional corruption detection capabilities that can prevent a server-wide crash in case of data corruption.
We'll see how it goes from here. There is still some work to be done and it is unsure if Optimizer+ will even make it into PHP 5.5. Also this is not a one man decision, all the PHP developers will soon vote on the RFC in order for it to be accepted.
Edit 29/mar/2013: In the meanwhile, Zend Optimizer+ was renamed to opcache and did make it into PHP 5.5.