You are viewing revision #3 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version.
Preface ¶
The Advanced PHP Cache is a PHP extension which primarily serves as an opcode cache for PHP. The basic idea is to save PHP from re-evaluating the PHP code to intermediate bytecode on each request. Installing and enabling APC already yields a significant performance benefit. However, APC is not a black box that will magicaly change all for the better. More over it is important to understand that APC needs memory to operate. Hence, by enabling APC you are trading memory for speed.
In addition to the opcode cache, APC can also serve as a user cache for Yii via [CApcCache]. It should be noted that this will make APC's memory needs less predictable.
Installation ¶
APC is best installed by means of your distribution's packaging system. For RedHat based distros (RHEL, CentOS, Fedora, Mandriva), you'll need to install the php-pecl-apc
package:
~~~
$ sudo yum install php-pecl-apc
~~~
For Debian based distributions, this will be the php-apc
package:
~~~
$ sudo apt-get install php-apc
~~~
If you are running a self-compiled version of PHP, you can install APC via the PEAR/PECL command-line tool:
~~~
$ pecl install APC
~~~
Be advised that this will compile the current version of APC on your system, so you'll need to have the GCC toolchain installed as well as the PHP headers along with the phpize
helper. You will almost certainly need to add APC to your PHP configuration. Otherwise, PHP won't load it. Simply drop a new file called apc.ini
into /usr/local/etc/php.d
(RedHat) or /usr/local/php.d/apache2/conf.d
(Debian) with the following content:
~~~
extension=apc.so
~~~
Preparing Yii ¶
The Yii framework comes with a yiilite.php
which can be used instead of yii.php
. Despite its name, it includes the most used classes. The benefit to APC is that the opcode cache can be quickly filled via one single file instead of digging through several smaller files.
If you wish to use APC as a user cache as well, you'll need to register the CApcCache as cache component in your config. Locate the components
-stanza in your config and add the following lines:
'components'=>array(
'cache'=>array(
'class'=>'CApcCache',
),
...
),
Configuration ¶
Server Filesystem ¶
If you have several Yii-based applications running on one server, you might want to consider dropping one copy of the Yii framework (i.e. the content of the framework
folder in the release tarball) into /usr/local/share/yii
and let the include_path
configuration setting point to that. APC will only have to pick up one copy of Yii then. In the process, you'll also conserve a bit of disk space.
APC Settings ¶
APC can be fine-tuned by a number of settings. Just toss them into your apc.ini
, restart your webserver (or php-fpm process) and see the magic happening. I found the following options to be important for Yii:
apc.enabled
Self explaining. This option enables or disables APC alltogether. Be advised that this is a system-wide setting, soyou cannot selectively switch APC on or off for e.g. certain directories via a.htaccess
or.user.ini
file. You'll want this to be set to on.apc.cache_by_default
Controls the default caching behaviour of APC. This can be used together withapc.filters
for complex cache setups. But in most cases, you'll want this to be 1.apc.mmap_file_mask
Filemask for the shared memory mechanism. The best setting I could find has been /dev/shm/apc.XXXXXXapc.stat
Controls if APC should check for modified files on every request. This setting will bring you the greatest speed benefit. Set it to 0 on production servers but to 1 in development environments (otherwise PHP won't pick up changes you've applied to the code). If you're rolling out a new version of your software, simply restart your webserver or FastCGI process in order to clear the opcode cache.apc.lazy_classes
andapc.lazy_functions
These settings are marked as experimental. However, I've found no regressions after using these. If you're feeling lucky and you're using anonymous functions forevalExpression
, you may want to set these to 1.apc.include_once_override
Setting this to on will speed upinclude*
andrequire*
calls. However, this setting will introduce changes in the behaviour of PHP. Yii is running fine with it but others (such as phpMyAdmin) aren't so happy. So evaluate carefully if this doesn't break other applications on your server. You've been warned!apc.ttl
Controls how long cached opcodes may be cached before being reloaded. Set this to 0 on your productions system so this will never happen. This is most useful together withapc.stat=0
.apc.num_files_hint
This is a hint for APC to reserve sufficient space for the opcode cache. It helps APC during the initial cache build. It isn't terribly important as it's really just a hint. But while you're at it: Set it to roughly the number of your project's PHP files.apc.user_entries_hint
Same asapc.num_files_hint
but for user cache entries, so it is only interesting if you're using APC as a user cache, too. A too high value might result in over-provisioning memory for the cache. This is highly individual, so you'll need to evaluate this yourself.apc.shm_size
The size of the cache. Take note that is the size of the opcode and the user cache. Currently, APC does not allow you to specify seperate memory segments for these. As a general rule: Do not set this lower than 16MB and monitor APC's memory usage closely. If your setting this too low, APC's memory might suffer heavy fragmentation, which will result in a high performance penalty.
Monitoring APC ¶
Some of the aforementioned settings can be very specific to your setup and your application. So you need to take a look at what APC is doing. There are currently two ways of achieving this:
- APC itself comes witha bundled
apc.php
which will tell you a bit about memory consumption, fragmentation and cache content. You'll most likely find it in/usr/local/doc/apc
. Copy it to a location where your webserver can reach it and take appropriate measures to protect it from unauthorized access. - Available as an extension to your very own app comes the apcinfo extension which does roughly the same job as
apc.php
but integrates nicely into your app.
igbinary
A small note: In order to take full advantage of the igbinary serializer for user cache entries,
framework/caching/CCache.php
must be modified:In lines 84 and 120,
unserialize
has to be replaced byigbinary_unserialize
. In line 147,serialize
must be altered toigbinary_serialize
. Otherwise cache entries will still be serialized using PHP's default serializer. Working on a patch.Edit: Said patch will be part of Yii 1.1.11 (cf commit c298fa8)
APC ttl
You recommend setting apc.ttl to 0, but I assume you can only do this as long as your production applications never use the full APC allocated memory? According to the PHP manual, when the ttl is reached, all APC cache is purged. It seems to me it makes sense to set a ttl so stale entries will not use up the cache, or is there a significant performance drawback?
http://www.php.net/manual/en/apc.configuration.php#ini.apc.ttl
RE: APC ttl
Well, the proposed settings here are for production systems. Having said that, the assumption is that the cached codes won't change unless a manual cache purge is performed, so the scenario discussed in the documentation will never occur with
apc.stat=0
andapc.ttl=0
. However, there still might be some problems if user cache entries fill up the cache (btw: For that exact reason it is a bad idea to setapc.user_ttl
to0
as well).All in all, I'll need some time to clean up some portions of this article as I have gained new insights while studying APC's source code. I'm also conducting a few experiments with APC and PHP-FPM's process pools. The results so far are quite interesting ;)
RE: APC ttl
Thanks for your feedback. Interested to see your results. Maybe even some performance comparisons on a real world (instead of hello world) Yii application with and without APC cache, with different options?
Except if you don't allocate enough memory for code caching?
RE[2]: APC ttl
I've got some rather complex applications that I run benchmarks against. They are for very specific purposes so the public will hardly benefit from the raw result numbers. But they are great for experimentation ;)
"Except if you don't allocate enough memory for code caching?"
If you do not allocate enough memory in the first place, you've lost. Simple as that. If there is not enough available memory for the cached bytecodes, the slots will be freed in almost randomly fashion leaving you with a defunct application.
RE[2]: APC ttl
I guess that depends, if you allocate such a small amount that cache invalidates almost instantly, there is no point in using APC. Also, for a single project host it shouldn't be very hard to configure the right amount of memory. But imagine a large host running 50-100 projects, cache might fill up over a period of a few hours. You could prevent that by using small enough ttl's, or accept periodical full cache purging. Or is there something else going wrong when the allocated memory runs out?
RE[2]: APC ttl
I think it's time for some anecdotal evidence: I'm the care taker of an old legacy application that does mostly number-crunching in realtime. There is little sense in using caches here so the app doesn't use it safe for some http-level caching. Said app is sitting on a single-purpose box with nginx+php-fpm+MariaDB. Since the app's memory requirements even in APC has been a near constant, I set APC's available memory that low including a safety margin of 1MB. I recently upgraded the box from PHP 5.3 to 5.4 which resulted in increased memory needs. Unfortunately I left the APC settings as they were, still believing they were fine. The application though basicaly fell apart: A random potpourri of 500s, undefined classes, partial and blank pages.
That is what happens if you set the cache too small to contain the PHP opcodes. If it's sufficient for the opcodes but too small for the user cache, the situation is a bit different: You'll see a lot of user cache purges, effectively negating the benefits of caching.
Useful
thanks Da:Sourcerer.
Very useful article.
No Significant result after APC Implementation | Please Guide
Before APC Implementation
_bash-4.1$ ab -n 100 http://localhost/mywebsite.com/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: Apache/2.2.15
Server Hostname: localhost
Server Port: 80
Document Path: /mywebsite.com/
Document Length: 51841 bytes
Concurrency Level: 1
Time taken for tests: 111.972 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Non-2xx responses: 100
Total transferred: 5222800 bytes
HTML transferred: 5184100 bytes
Requests per second: 0.89 [#/sec] (mean)
Time per request: 1119.724 [ms] (mean)
Time per request: 1119.724 [ms] (mean, across all concurrent requests)
Transfer rate: 45.55 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 910 1120 350.3 1049 4279
Waiting: 905 1114 350.3 1044 4274
Total: 910 1120 350.3 1049 4279
Percentage of the requests served within a certain time (ms)
50% 1049
66% 1068
75% 1088
80% 1136
90% 1268
95% 1517
98% 1860
99% 4279
100% 4279 (longest request)_
After APC Implementation
bash-4.1$ ab -n 100 http://localhost/mywebsite.com/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: Apache/2.2.15
Server Hostname: localhost
Server Port: 80
Document Path: /mywebsite.com/
Document Length: 51841 bytes
Concurrency Level: 1
Time taken for tests: 112.384 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Non-2xx responses: 100
Total transferred: 5222800 bytes
HTML transferred: 5184100 bytes
Requests per second: 0.89 [#/sec] (mean)
Time per request: 1123.844 [ms] (mean)
Time per request: 1123.844 [ms] (mean, across all concurrent requests)
Transfer rate: 45.38 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 594 1124 316.5 1027 3447
Waiting: 593 1123 316.5 1026 3446
Total: 594 1124 316.5 1027 3447
Percentage of the requests served within a certain time (ms)
50% 1027
66% 1089
75% 1192
80% 1233
90% 1342
95% 1527
98% 2237
99% 3447
100% 3447 (longest request)
nice article! thanks!!
nice article! thanks!!
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.